diff --git a/include/rtos/context.h b/include/rtos/context.h new file mode 100644 index 0000000..82d0520 --- /dev/null +++ b/include/rtos/context.h @@ -0,0 +1,27 @@ +#ifndef _CONTEXT_H_ +#define _CONTEXT_H_ + +#include +#include "rtos/spinlock.h" + +enum state_t { + CONTEXT_NULL = 0x00, + CONTEXT_RUNNING, + CONTEXT_READY, + CONTEXT_INTERRUPTED, + CONTEXT_SLEEP, + CONTEXT_SLEEP_QUEUE, +}; + +struct context { + state_t state; + uint8_t priority; + uint32_t spinlock_held; + uint32_t dummy; +}; + +uint32_t context_wait_priority_queue(struct spinlock *lock, struct context **queue); +uint32_t context_signal_queue(struct context **queue); +uint32_t context_interrupt_queue(struct context *c, struct context **queue); + +#endif /* _CONTEXT_H_ */ diff --git a/include/rtos/critical.h b/include/rtos/critical.h new file mode 100644 index 0000000..a5e62fb --- /dev/null +++ b/include/rtos/critical.h @@ -0,0 +1,10 @@ +#ifndef _CRITICAL_H_ +#define _CRITICAL_H_ + +/* disable Interrupts */ +void enter_critical_section(void); + +/* enable Interrupts */ +void exit_critical_section(void); + +#endif /* _CRITICAL_H_ */ diff --git a/include/rtos/semaphore.h b/include/rtos/semaphore.h new file mode 100644 index 0000000..6bdf7f1 --- /dev/null +++ b/include/rtos/semaphore.h @@ -0,0 +1,22 @@ +#ifndef _SEMSPHORE_H_ +#define _SEMSPHORE_H_ + +#include + +#include "rtos/context.h" +#include "rtos/spinlock.h" + +struct semaphore { + struct context *sleep_queue; + struct spinlock lock; + uint32_t count; +}; + +state_t sem_wait(struct semaphore *sem); +void sem_post(struct semaphore *sem); + +void sem_interrupt(struct semaphore *sem, struct context *c); +int32_t sem_get_count(struct semaphore *sem); +void sem_init(struct semaphore *sem, uint8_t priority, int32_t count); + +#endif /* _SEMSPHORE_H_ */ diff --git a/include/rtos/spinlock.h b/include/rtos/spinlock.h new file mode 100644 index 0000000..18da564 --- /dev/null +++ b/include/rtos/spinlock.h @@ -0,0 +1,16 @@ +#ifndef _SPINLOCK_H_ +#define _SPINLOCK_H_ + +#include + +struct spinlock { + uint8_t locked; + uint8_t priority_locked; + uint8_t priority_unlocked; +}; + +void spinlock_lock(struct spinlock *lock); +void spinlock_unlock(struct spinlock *lock); +void spinlock_init(struct spinlock *lock, uint8_t priority); + +#endif /* _SPINLOCK_H_ */ diff --git a/main.c b/main.c index 477de44..582660e 100644 --- a/main.c +++ b/main.c @@ -16,46 +16,76 @@ * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +#include +#include + #include "AT91SAM7S256.h" +#include "board.h" #include "at91_sysc.h" #include "at91_dbgu.h" -#include "at91_pitc.h" -#include "at91_tests.h" -#include "at91_udp.h" -#include "at91_pio.h" -#include "at91_twi.h" - -#include "at91_tc1.h" #include "memalloc.h" -#include "board.h" -#include -#include - -static uint32_t pitc_test(struct pitc_timer *timer) +uint32_t * init_ctx(uint32_t *stack, void *code, void *arg) { - static uint32_t i; - *AT91C_PIOA_SODR = i; - i = i ^ LED_GREEN; - *AT91C_PIOA_CODR = i; -/* - struct rc_values rc; - uint32_t count = rcontrol_getvalues(&rc); + uint32_t org_stack = (uint32_t)stack; - printf("%ld channels: ", count); - uint32_t j; - for (j = 0; j < count; j++) - printf("%+5d ", rc.chan[j]); + *stack-- = (uint32_t) code; // r15 (pc) + *stack-- = 0x14141414; // r14 (lr) + *stack-- = org_stack -4; // r13 (sp) + *stack-- = 0x12121212; // r12 + *stack-- = 0x11111111; // r11 + *stack-- = 0x10101010; // r10 + *stack-- = 0x09090909; // r9 + *stack-- = 0x08080808; // r8 + *stack-- = 0x07070707; // r7 + *stack-- = 0x06060606; // r6 + *stack-- = 0x05050505; // r5 + *stack-- = 0x04040404; // r4 + *stack-- = 0x03030303; // r3 + *stack-- = 0x02020202; // r2 + *stack-- = 0x01010101; // r1 + *stack-- = (uint32_t) arg; // r0 (function parameter) + *stack = 0xF0000013; // SPSR (SVC, ARM, IRQ & FIQ enabled) - printf("\r"); -*/ - return PITC_RESTART_TIMER; + return stack; } -static struct pitc_timer pitc_test_timer = { - .interval = 10, - .func = &pitc_test, -}; +/* we're in the scheduler, SVC mode */ +void restore_ctx(uint32_t *stack) +{ + asm volatile ( + /* restore spsr */ + "mov lr, r0 \n\t" + "ldmia lr!, {r0} \n\t" + "msr spsr, r0 \n\t" + + /* restore all registers */ + "ldmia lr, {r0-r13} \n\t" + "nop \n\t" + "ldmia sp!, {r14-r15}^ \n\t" + "nop \n\t" + ); +} + + +void store_ctx(void) +{ + asm volatile ( + /* push r0 on (task)stack */ + "stmdb sp!, {r0} \n\r" + + // TODO: fill r0 with address TCB + + /* return address */ + "stmdb r0!, {lr} \n\r" + ); +} + +void testfunc(void *p) +{ + printf("bla: %p\n\r", p); + while(1); +} int main(void) { @@ -63,33 +93,13 @@ int main(void) *AT91C_PIOA_PER = LED_GREEN | LED_ORANGE; *AT91C_PIOA_OER = LED_GREEN | LED_ORANGE; - /* needed for dbgu */ at91_sysc_init(); - at91_dbgu_init(); at91_dbgu_puts("==========================================================\n\rGood morning Dave\n\r"); - /* triggers pinchange-isrs */ - at91_pio_init(); + uint32_t *blub = static_alloc(1024); + printf("blub: %p\n\r", blub); - /* timer */ - at91_pitc_init(); - at91_rttc_test_init(); - at91_tc1_init(); - - /* adc, need timer */ - at91_adc_test_init(); - - /* twi */ - at91_twi_init(); - at91_twi_test(); - - /* usb */ - at91_udp_init(); - - printf("static alloc: %5ld bytes\n\r", static_alloc_used()); - - pitc_schedule_timer(&pitc_test_timer); - - while (1); + uint32_t *tmp = init_ctx(blub + (1024/4), testfunc, 0); + restore_ctx(tmp); } diff --git a/src/at91_adc.c b/src/at91_adc.c deleted file mode 100644 index 84b558c..0000000 --- a/src/at91_adc.c +++ /dev/null @@ -1,92 +0,0 @@ -/*************************************************************************** - * Copyright (C) 01/2008 by Olaf Rempel * - * razzor@kopf-tisch.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; version 2 of the License * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#include -#include - -#include "AT91SAM7S256.h" -#include "board.h" -#include "at91_pitc.h" - -static uint16_t adc_result[4]; - -static void at91_adc_isr(void) -{ - AT91S_PDC *pdc = AT91C_BASE_PDC_ADC; - pdc->PDC_RPR = (uint32_t) &adc_result; - pdc->PDC_RCR = ARRAY_SIZE(adc_result); - pdc->PDC_PTCR = AT91C_PDC_RXTEN; - - /* clear interrupts */ - AT91S_ADC *adc = AT91C_BASE_ADC; - uint32_t status = adc->ADC_SR; - status = status; -} - -static uint32_t adc_trigger(struct pitc_timer *timer) -{ - *AT91C_ADC_CR = AT91C_ADC_START; - return PITC_RESTART_TIMER; -} - -static struct pitc_timer adc_timer = { - .interval = 100, - .func = &adc_trigger, -}; - -void at91_adc_test_init(void) -{ - /* enable ADC clock */ - *AT91C_PMC_PCER = (1 << AT91C_ID_ADC); - - /* ADC Software reset */ - AT91S_ADC *adc = AT91C_BASE_ADC; - adc->ADC_CR = AT91C_ADC_SWRST; - - /* - * ADC config: 10bit, no sleep - * 4.8MHz (48MHz / ((4 +1) * 2) = 4.8MHz) - * 96 cycles Startup ((11 +1) * 8 / 4.8MHz = 20us) - * 3 cycles SH ((2 +1) / 4.8MHz = 625ns) - * Conversion time per channel @5MHz ~2us - */ - adc->ADC_MR = AT91C_ADC_TRGEN_DIS | - AT91C_ADC_LOWRES_10_BIT | - AT91C_ADC_SLEEP_NORMAL_MODE | - (AT91C_ADC_PRESCAL & (4 << 8)) | - (AT91C_ADC_STARTUP & (11 << 16)) | - (AT91C_ADC_SHTIM & (2 << 24)); - - /* setup PDC */ - AT91S_PDC *pdc = AT91C_BASE_PDC_ADC; - pdc->PDC_RPR = (uint32_t) &adc_result; - pdc->PDC_RCR = ARRAY_SIZE(adc_result); - pdc->PDC_PTCR = AT91C_PDC_RXTEN; - - /* enable 4 channels, PDC Interrupt */ - adc->ADC_CHER = 0xF0; - adc->ADC_IER = AT91C_ADC_ENDRX; - - /* low priority, level triggered, own vector */ - AT91S_AIC *aic = AT91C_BASE_AIC; - aic->AIC_SMR[AT91C_ID_ADC] = IRQPRIO_ADC | AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL; - aic->AIC_SVR[AT91C_ID_ADC] = (uint32_t)at91_adc_isr; - aic->AIC_IECR = (1< 1; i--) { buf[i] = (var & 0x0F); buf[i] += (buf[i] < 0xa) ? '0' : ('a' - 0x0a); - var >>= 4; + var >>= 4; } buf[10] = '\0'; dbgu_puts(buf); @@ -59,8 +59,8 @@ ARM7TDMI 32bit Undefined Address Instruction Fetch Abort --- Registerdump (cpsr:0xa0000013 - SVC): r0:0x00000002 r1:0x0000000c r2:0x00200038 r3:0x80000000 r4:0x0020fffc r5:0x00101788 r6:0x00000180 r7:0x41000000 - r8:0x00008400 r9:0x00100004 r10:0x03000294 fp:0x0020fe84 -r12:0x0020fe10 sp:0x0020fe70 lr:0x00102174 pc:0x80000004 + r8:0x00008400 r9:0x00100004 sl:0x03000294 fp:0x0020fe84 + ip:0x0020fe10 sp:0x0020fe70 lr:0x00102174 pc:0x80000004 --- Stackdump: 0x0020fe70: 0x0020fe7c 0x00101648 0x001015a8 0x0020feaf 0x0020fe80: 0x0020fec0 0x0020fe90 0x00101780 0x00101620 @@ -96,17 +96,17 @@ void at91_abt_handler(uint32_t cpsr, uint32_t *registers) dbgu_puts("32bit "); break; } - + if (asr & AT91C_MC_UNDADD) dbgu_puts("Undefined Address "); else if (asr & AT91C_MC_MISADD) dbgu_puts("Misaliged Address "); - + switch (asr & AT91C_MC_ABTTYP) { case AT91C_MC_ABTTYP_DATAR: dbgu_puts("Data Read "); break; - + case AT91C_MC_ABTTYP_DATAW: dbgu_puts("Data Write "); break; @@ -115,7 +115,7 @@ void at91_abt_handler(uint32_t cpsr, uint32_t *registers) dbgu_puts("Prefetch "); break; } - + dbgu_hexvar("Abort\n(ASR:", asr); dbgu_hexvar(" AASR:", *AT91C_MC_AASR); dbgu_puts(")\n"); @@ -142,9 +142,9 @@ void at91_abt_handler(uint32_t cpsr, uint32_t *registers) dbgu_hexvar(" r7:", registers[10]); dbgu_hexvar("\n r8:", registers[11]); dbgu_hexvar(" r9:", registers[12]); - dbgu_hexvar(" r10:", registers[13]); + dbgu_hexvar(" sl:", registers[13]); dbgu_hexvar(" fp:", registers[14]); - dbgu_hexvar("\nr12:", registers[15]); + dbgu_hexvar("\n ip:", registers[15]); dbgu_hexvar(" sp:", registers[0]); dbgu_hexvar(" lr:", registers[1]); dbgu_hexvar(" pc:", registers[2]); diff --git a/src/at91_pio.c b/src/at91_pio.c deleted file mode 100644 index 6a990d4..0000000 --- a/src/at91_pio.c +++ /dev/null @@ -1,69 +0,0 @@ -/*************************************************************************** - * Copyright (C) 01/2008 by Olaf Rempel * - * razzor@kopf-tisch.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; version 2 of the License * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#include -#include -#include "AT91SAM7S256.h" -#include "board.h" -#include "at91_pio.h" - -/* extern symbols, defined in ldscript */ -extern struct pio_pinchange_isr _pio_isr_table; -extern struct pio_pinchange_isr _pio_isr_table_end; - -static void pio_isr(void) -{ - uint32_t status = *AT91C_PIOA_ISR; - uint32_t input = *AT91C_PIOA_PDSR; - - struct pio_pinchange_isr *isr; - for (isr = &_pio_isr_table; isr < &_pio_isr_table_end; isr++) - if (isr->mask & status) - isr->func(status, input); -} - -void pio_trigger_isr(uint32_t mask) -{ - uint32_t input = *AT91C_PIOA_PDSR; - - struct pio_pinchange_isr *isr; - for (isr = &_pio_isr_table; isr < &_pio_isr_table_end; isr++) - if (isr->mask & mask) - isr->func(mask, input); -} - -void at91_pio_init(void) -{ - /* enable PIO clock */ - *AT91C_PMC_PCER = (1 << AT91C_ID_PIOA); - - /* enable pinchange interrupts */ - struct pio_pinchange_isr *isr; - for (isr = &_pio_isr_table; isr < &_pio_isr_table_end; isr++) - *AT91C_PIOA_IER = isr->mask; - - /* dummy read to clear interrupts */ - uint32_t dummy = *AT91C_PIOA_ISR; - dummy = dummy; - - /* low priority, level triggered, own vector */ - AT91S_AIC *aic = AT91C_BASE_AIC; - aic->AIC_SMR[AT91C_ID_PIOA] = IRQPRIO_PIOA | AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL; - aic->AIC_SVR[AT91C_ID_PIOA] = (uint32_t)pio_isr; - aic->AIC_IECR = (1 << AT91C_ID_PIOA); -} diff --git a/src/at91_pitc.c b/src/at91_pitc.c deleted file mode 100644 index 95faddf..0000000 --- a/src/at91_pitc.c +++ /dev/null @@ -1,79 +0,0 @@ -/*************************************************************************** - * Copyright (C) 01/2008 by Olaf Rempel * - * razzor@kopf-tisch.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; version 2 of the License * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#include "AT91SAM7S256.h" -#include "at91_pitc.h" -#include "at91_sysc.h" -#include "board.h" - -/* PIV is 20bit -> min. 3Hz @48MHz MCK */ -#define HZ_TO_PIV(HZ) (MCK / (16 * HZ)) - -static LIST_HEAD(timer_list); -volatile static uint32_t pitc_ticks; - -void pitc_schedule_timer(struct pitc_timer *timer) -{ - timer->nextrun = timer->interval + pitc_ticks; - - struct pitc_timer *search; - list_for_each_entry(search, &timer_list, list) - if (search->nextrun > timer->nextrun) - break; - - list_add_tail(&timer->list, &search->list); -} - -static void pitc_isr(uint32_t status) -{ - /* get Ticks and clear interrupt */ - pitc_ticks += (*AT91C_PITC_PIVR & AT91C_PITC_PICNT) >> 20; - - struct pitc_timer *search, *tmp; - list_for_each_entry_safe(search, tmp, &timer_list, list) { - /* if this entry not scheduled yet, abort search */ - if (pitc_ticks < search->nextrun) - break; - - /* remove from list */ - list_del(&search->list); - - /* exec handler */ - if (search->func(search) == PITC_REMOVE_TIMER) { - /* one-shot timer, mark as completed */ - search->nextrun = 0x00; - continue; - } - /* interval timer, reschedule it */ - pitc_schedule_timer(search); - } -} - -uint32_t pitc_get_ticks(void) -{ - return pitc_ticks; -} - -void at91_pitc_init(void) -{ - sysc_register_isr(AT91_SYSIRQ_PIT, &pitc_isr); - - *AT91C_PITC_PIMR = (AT91C_PITC_PIV & HZ_TO_PIV(100)) | - AT91C_PITC_PITEN | - AT91C_PITC_PITIEN; -} diff --git a/src/at91_rttc_test.c b/src/at91_rttc_test.c deleted file mode 100644 index ce6d9c2..0000000 --- a/src/at91_rttc_test.c +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include "AT91SAM7S256.h" -#include "at91_sysc.h" -#include "board.h" - -static void rtt_isr(uint32_t status) -{ - *AT91C_RTTC_RTAR = *AT91C_RTTC_RTVR +1; -/* - static uint32_t i; - *AT91C_PIOA_SODR = i; - i = i ^ LED_ORANGE; - *AT91C_PIOA_CODR = i; -*/ -} - -void at91_rttc_test_init(void) -{ - /* calculate SLOWCK from MAINCK and measured MAINF */ - uint32_t prescaler = MAINCK * 16 / (*AT91C_CKGR_MCFR & AT91C_CKGR_MAINF); - - sysc_register_isr(AT91_SYSIRQ_RTT, &rtt_isr); - - /* - * AT91C_RTTC_RTTINCIEN doesn't work - * use AT91C_RTTC_ALMIEN and increment RTAR in isr - */ - *AT91C_RTTC_RTAR = *AT91C_RTTC_RTVR +1; - *AT91C_RTTC_RTMR = (AT91C_RTTC_RTPRES & prescaler) | - AT91C_RTTC_ALMIEN | - AT91C_RTTC_RTTRST; - - printf("rttc running at %ld Hz\n\r", prescaler); -} diff --git a/src/at91_tc1.c b/src/at91_tc1.c deleted file mode 100644 index 99a2870..0000000 --- a/src/at91_tc1.c +++ /dev/null @@ -1,227 +0,0 @@ -/*************************************************************************** - * Copyright (C) 01/2008 by Olaf Rempel * - * razzor@kopf-tisch.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; version 2 of the License * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#include -#include -#include /* abs() */ -#include "AT91SAM7S256.h" -#include "board.h" -#include "at91_tc1.h" -#include "at91_pio.h" - -/* Hard limits for ISR */ -#define PULSE_MIN 0x0500 -#define PULSE_MAX 0x0D00 -#define PULSE_TIMEOUT 0x0F00 -#define PULSE_CENTER 0x08C0 - -/* moving average filters */ -#define PULSE_FILTER_FAST (1<<2) -#define PULSE_FILTER_SLOW (1<<4) -#define PULSE_FILTER_DIFF 16 /* point to switch filters */ -#define PULSE_MID_DIFF 50 /* minimum diff to center */ - -#define VALUE_RANGE 256 - -#define ROUND_DIV256(x) ((x >> 8) + ((x & 0x80) ? 1 : 0)) - -struct channel_data { - uint16_t width; - uint16_t width_slow; - uint16_t filter; /* 0 - fast filter, 1 - slow filter */ - uint16_t min; /* minimum value during calibration */ - uint16_t mid; /* center value */ - uint16_t max; /* maximum value */ -}; - -static struct channel_data ch_data[MAX_CHANNELS]; -static uint32_t count, valid, cal_in_progress; - -static void ppm_isr(void) -{ - static uint32_t i; - - /* RC Compare -> no TIOA1 edge for 2.5ms */ - uint32_t status = *AT91C_TC1_SR; - - if (status & AT91C_TC_CPCS) { - /* average channel count */ - count = ((count * 7) + (i << 8)) / 8; - - /* at least 4 channels and a stable channel count */ - if ((ROUND_DIV256(count) == i) && (i >= 4)) { - if (valid < 10) - valid++; - - } else if (valid > 0) { - valid--; - } - - /* reset index */ - i = 0; - } - - /* edge on TIOA1 */ - if (status & AT91C_TC_LDRAS) { - /* get impulse width */ - uint16_t width = *AT91C_TC1_RA; - - /* valid range: 1 - 2ms */ - if (width > PULSE_MIN && width < PULSE_MAX) { - if (i < ARRAY_SIZE(ch_data)) { - /* calc both filters */ - ch_data[i].width = ((ch_data[i].width * (PULSE_FILTER_FAST -1)) + width) / PULSE_FILTER_FAST; - ch_data[i].width_slow = ((ch_data[i].width_slow * (PULSE_FILTER_SLOW -1)) + width) / PULSE_FILTER_SLOW; - - if (cal_in_progress) { - /* use slow filter values, calc center */ - ch_data[i].min = MIN(ch_data[i].width_slow, ch_data[i].min); - ch_data[i].max = MAX(ch_data[i].width_slow, ch_data[i].max); - ch_data[i].mid = (ch_data[i].min + ch_data[i].max) / 2; - } - } - i++; - } - } -} - -uint32_t rcontrol_getvalues(struct rc_values *rc) -{ - if (valid < 5) - return 0; - - uint32_t i; - uint32_t cnt = MIN(ROUND_DIV256(count), ARRAY_SIZE(ch_data)); - for (i = 0; i < cnt; i++) { - /* switch between fast and slow filter */ - uint16_t filter = (abs(ch_data[i].width - ch_data[i].width_slow) < PULSE_FILTER_DIFF); - - /* - * transition fast -> slow filter - * slow filter is lagging behind, so give it a boost - */ - if (filter && !ch_data[i].filter && !cal_in_progress) - ch_data[i].width_slow = ch_data[i].width; - - ch_data[i].filter = filter; - - uint16_t width = (filter) ? ch_data[i].width_slow : ch_data[i].width; - - /* expand the value to +/- VALUE_RANGE */ - int32_t tmp = (width - ch_data[i].mid) * VALUE_RANGE; - tmp = tmp / ((tmp > 0) ? (ch_data[i].max - ch_data[i].mid) : (ch_data[i].mid - ch_data[i].min)); - - /* keep result in range */ - if (tmp > VALUE_RANGE) - tmp = VALUE_RANGE; - - if (tmp < -VALUE_RANGE) - tmp = -VALUE_RANGE; - - rc->chan[i] = tmp; - } - return cnt; -} - -void rcontrol_calibrate(uint32_t mode) -{ - uint32_t i; - - switch (mode) { - case RC_CAL_START: - cal_in_progress = 1; - for (i = 0; i < ARRAY_SIZE(ch_data); i++) { - /* use hard limits as hint */ - ch_data[i].max = PULSE_MIN; - ch_data[i].mid = (PULSE_MIN + PULSE_MAX) / 2; - ch_data[i].min = PULSE_MAX; - } - break; - - case RC_CAL_END: - cal_in_progress = 0; - for (i = 0; i < ARRAY_SIZE(ch_data); i++) { - /* treat current position as center */ - ch_data[i].mid = ch_data[i].width_slow; - - /* if center is near minimum, clamp output to 0..+1024 */ - if (ch_data[i].mid - ch_data[i].min < PULSE_MID_DIFF) - ch_data[i].mid = ch_data[i].min; - - /* if center is near maximum, clamp output to -1024..0 */ - if (ch_data[i].max - ch_data[i].mid < PULSE_MID_DIFF) - ch_data[i].mid = ch_data[i].max; - } - break; - } -} - -void rcontrol_print_cal(void) -{ - uint32_t i; - for (i = 0; i < ARRAY_SIZE(ch_data); i++) { - printf("%ld: %d(%+d) - %d(0) - %d(%+d)\n\r", i, - ch_data[i].min, ch_data[i].min - ch_data[i].mid, - ch_data[i].mid, - ch_data[i].max, ch_data[i].max - ch_data[i].mid - ); - } -} - -void at91_tc1_init(void) -{ - /* enable TC1 clock */ - *AT91C_PMC_PCER = (1 << AT91C_ID_TC1); - - /* MCK /32, trigger & capture on falling TIOA1 edge */ - *AT91C_TC1_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | AT91C_TC_LDRA_FALLING | - AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG; - - /* enable RA load and RC compare interrupt */ - *AT91C_TC1_IER = AT91C_TC_LDRAS | AT91C_TC_CPCS; - - /* RC Compare Interrupt if no rising Edge on TIOA1 for 2.56ms */ - *AT91C_TC1_RC = PULSE_TIMEOUT; - - /* enable & trigger the clock */ - *AT91C_TC1_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - /* level triggered, own vector */ - AT91S_AIC *aic = AT91C_BASE_AIC; - aic->AIC_SMR[AT91C_ID_TC1] = IRQPRIO_TC1 | AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL; - aic->AIC_SVR[AT91C_ID_TC1] = (uint32_t)ppm_isr; - aic->AIC_IECR = (1 << AT91C_ID_TC1); -} - -static void tast_monitor(uint32_t status, uint32_t input) -{ - if (!(input & TAST1) && (cal_in_progress == 0)) { - printf("start calibration\n\r"); - - rcontrol_calibrate(RC_CAL_START); - - - } else if (!(input & TAST2) && (cal_in_progress == 1)) { - printf("end calibration\n\r"); - - rcontrol_calibrate(RC_CAL_END); - rcontrol_print_cal(); - } -} - -PIO_PINCHANGE_ISR(TAST1 | TAST2, tast_monitor); diff --git a/src/at91_twi.c b/src/at91_twi.c deleted file mode 100644 index aa053be..0000000 --- a/src/at91_twi.c +++ /dev/null @@ -1,261 +0,0 @@ -/*************************************************************************** - * Copyright (C) 02/2008 by Olaf Rempel * - * razzor@kopf-tisch.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; version 2 of the License * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#include -#include - -#include "AT91SAM7S256.h" -#include "board.h" -#include "at91_twi.h" -#include "at91_pio.h" - -/* - * undocumented TWI_SR flags, at least OVRE seems to be present on a sam7s256 - * taken from linux-2.6.24/include/asm-arm/arch-at91/at91_twi.h - */ -#define AT91_TWI_OVRE (1<<6) /* Overrun */ -#define AT91_TWI_UNRE (1<<7) /* Underrun */ - -/* - * while ((cldiv = ((MCK / (2 * TWI)) -3) / (1 << ckdiv)) > 255) - * ckdiv++ ; - * - * works for TWI >= 100kHz - */ -#define TWI_CLK(x) (((MCK / (2 * (x))) -3)<<8 | ((MCK / (2 * (x))) -3)) - -enum twi_states { - TWI_IDLE = 0x00, - TWI_ERROR, - TWI_GENERIC_CMD = 0x10, - TWI_BLMC_UPDATE = 0x20, -}; - -static volatile uint32_t twi_state = TWI_IDLE; -static uint8_t *twi_data; -static uint32_t twi_size; -static uint32_t twi_count; - -static void twi_isr(void) -{ - /* get status */ - uint32_t status = *AT91C_TWI_SR; - status &= *AT91C_TWI_IMR; - - /* NACK - disable all interrupts and go to state TWI_ERROR */ - if (status & AT91C_TWI_NACK) { - *AT91C_TWI_IDR = AT91C_TWI_TXCOMP | AT91C_TWI_RXRDY | AT91C_TWI_TXRDY | AT91C_TWI_NACK; - twi_state = TWI_ERROR; - - // TODO: TWI_BLMC_UPDATE? - return; - } - - /* tx register ready for new data */ - if (status & AT91C_TWI_TXRDY) { - if (twi_count != twi_size) { - /* feed next byte */ - *AT91C_TWI_THR = twi_data[twi_count++]; - - } else { - /* wait for TXCOMP */ - *AT91C_TWI_IDR = AT91C_TWI_RXRDY | AT91C_TWI_TXRDY; - *AT91C_TWI_IER = AT91C_TWI_TXCOMP | AT91C_TWI_NACK; - } - } - - /* rx register has data */ - if (status & AT91C_TWI_RXRDY) { - /* get data */ - twi_data[twi_count++] = *AT91C_TWI_RHR; - - /* transfer complete? */ - if (twi_count == twi_size) { - /* send STOP and wait for TXCOMP */ - *AT91C_TWI_CR = AT91C_TWI_STOP; - *AT91C_TWI_IDR = AT91C_TWI_TXRDY; - *AT91C_TWI_IER = AT91C_TWI_TXCOMP | AT91C_TWI_NACK; - } - } - - /* transfer really complete? */ - if (status & AT91C_TWI_TXCOMP) { - - /* are we doing a blmc update? */ - if (twi_state == TWI_BLMC_UPDATE) { - uint32_t addr = (*AT91C_TWI_MMR >> 16) & 0x7F; - if (addr != TWI_ADDR_BL4) { - /* increase address */ - *AT91C_TWI_MMR += (1<<16); - - /* send next value to next blmc */ - *AT91C_TWI_THR = *twi_data++; - } else { - // TODO: - } - - } else { - *AT91C_TWI_IDR = AT91C_TWI_TXCOMP | AT91C_TWI_RXRDY | AT91C_TWI_TXRDY | AT91C_TWI_NACK; - twi_state = TWI_IDLE; - } - } -} - -uint32_t twi_setpwm(uint8_t *values) -{ - if (twi_state != TWI_IDLE) - return 1; - - twi_state = TWI_BLMC_UPDATE; - twi_data = values; /* data is not copied! */ - twi_size = 0; - twi_count = 0; - - *AT91C_TWI_MMR = (TWI_ADDR_BL1 << 16) | AT91C_TWI_IADRSZ_1_BYTE; - *AT91C_TWI_IADR = CMD_SET_PWM; - - *AT91C_TWI_THR = *twi_data++; - *AT91C_TWI_IER = AT91C_TWI_TXRDY | AT91C_TWI_NACK; - - return 0; -} - -uint32_t twi_cmd(uint8_t addr, struct blmc_cmd *cmd) -{ - if (twi_state != TWI_IDLE) - return 1; - - /* TODO: locking needed? */ - twi_state = TWI_GENERIC_CMD; - - /* read transfer, or write transfer with payload */ - if (cmd->mode & BLMC_CMD_READ || cmd->size != 0) { - /* set address, direction, argument count and command bytes */ - *AT91C_TWI_MMR = (addr << 16) | (cmd->mode & 0xFF) << 8; - *AT91C_TWI_IADR = cmd->cmd; - - /* write transfer without payload */ - } else { - /* use one cmd byte as payload (needed to start transfer) */ - cmd->mode--; - *AT91C_TWI_MMR = (addr << 16) | (cmd->mode & 0xFF) << 8; - *AT91C_TWI_IADR = (cmd->cmd) >> 8; - } - - /* isr needs data & size parameters */ - twi_data = cmd->data; - twi_size = cmd->size; - twi_count = 0; - - if (cmd->mode & BLMC_CMD_READ) { - *AT91C_TWI_CR = AT91C_TWI_START; - *AT91C_TWI_IER = AT91C_TWI_RXRDY | AT91C_TWI_NACK; - - } else { - *AT91C_TWI_THR = (twi_size != 0) ? cmd->data[twi_count++] : (cmd->cmd & 0xFF); - *AT91C_TWI_IER = AT91C_TWI_TXRDY | AT91C_TWI_NACK; - } - - /* - * wait for end - * TODO: locking needed? - * TODO: timeout? - */ - while (twi_state != TWI_IDLE && twi_state != TWI_ERROR); - if (twi_state != TWI_IDLE) { - twi_state = TWI_IDLE; - return 1; - } - - return 0; -} - -void at91_twi_test(void) -{ - uint32_t i; - for (i = TWI_ADDR_BL1; i <= TWI_ADDR_BL4; i++) { - struct blmc_cmd cmd = { - .cmd = CMD_BOOT_LOADER, - .mode = BLMC_CMD_WRITE | BLMC_CMD_0_ARG, - }; - uint32_t ret = twi_cmd(i, &cmd); - printf("twi[0x%02lx](%ld) ", i, ret); - - volatile uint32_t x; - for (x = 0; x < 200000; x++); - - uint8_t buf[16]; - cmd.cmd = CMD_GET_INFO, - cmd.mode = BLMC_CMD_READ | BLMC_CMD_0_ARG, - cmd.size = sizeof(buf), - cmd.data = buf, - ret = twi_cmd(i, &cmd); - printf("boot(%ld):'%s' ", ret, buf); - - cmd.cmd = CMD_GET_SIGNATURE; - cmd.size = 4; - ret = twi_cmd(i, &cmd); - printf("sig(%ld):0x%02x%02x%02x ", ret, buf[0], buf[1], buf[2]); - - cmd.cmd = CMD_BOOT_APPLICATION; - cmd.mode = BLMC_CMD_WRITE | BLMC_CMD_0_ARG; - cmd.size = 0; - ret = twi_cmd(i, &cmd); - - for (x = 0; x < 200000; x++); - - cmd.cmd = CMD_GET_INFO, - cmd.mode = BLMC_CMD_READ | BLMC_CMD_0_ARG, - cmd.size = sizeof(buf), - cmd.data = buf, - ret = twi_cmd(i, &cmd); - printf("app(%ld):'%s'\n\r", ret, buf); - } -} - -void at91_twi_init(void) -{ - /* enable Clock */ - *AT91C_PMC_PCER = (1 << AT91C_ID_TWI); - - /* SDA & SCL from Peripheral A, Open Drain, no Pullup */ - AT91S_PIO *pio = AT91C_BASE_PIOA; - - /* do a software reset (bus not connected) */ - *AT91C_TWI_CR = AT91C_TWI_SWRST; - - pio->PIO_MDER = AT91C_PA3_TWD | AT91C_PA4_TWCK; - pio->PIO_PPUDR = AT91C_PA3_TWD | AT91C_PA4_TWCK; - pio->PIO_ASR = AT91C_PA3_TWD | AT91C_PA4_TWCK; - pio->PIO_PDR = AT91C_PA3_TWD | AT91C_PA4_TWCK; - - /* set TWI Clock */ - *AT91C_TWI_CWGR = TWI_CLK(400000); //| (5<<16); - - /* disable all (known) interrupts */ - *AT91C_TWI_IDR = AT91C_TWI_TXCOMP | AT91C_TWI_RXRDY | AT91C_TWI_TXRDY | AT91C_TWI_NACK; - - /* level triggered, own vector */ - AT91S_AIC *aic = AT91C_BASE_AIC; - aic->AIC_SMR[AT91C_ID_TWI] = IRQPRIO_TWI | AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL; - aic->AIC_SVR[AT91C_ID_TWI] = (uint32_t)twi_isr; - aic->AIC_IECR = (1 << AT91C_ID_TWI); - - /* enable teh monster */ - *AT91C_TWI_CR = AT91C_TWI_MSEN; -} diff --git a/src/at91_udp.c b/src/at91_udp.c deleted file mode 100644 index ec2554a..0000000 --- a/src/at91_udp.c +++ /dev/null @@ -1,552 +0,0 @@ -/*************************************************************************** - * Copyright (C) 01/2008 by Olaf Rempel * - * razzor@kopf-tisch.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; version 2 of the License * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#include -#include "AT91SAM7S256.h" -#include "at91_pio.h" -#include "board.h" -#include "fifo.h" - -#include "usb_ch9.h" -#include "usb_cdc.h" - -#define csr_clear_flags(csr, flags) \ - while ((csr) & (flags)) \ - (csr) &= ~(flags); - -#define csr_set_flags(csr, flags) \ - while (((csr) & (flags)) != (flags)) \ - (csr) |= (flags); - -struct ep_transfer { - uint16_t length; - uint16_t curpos; - - char *data; - void (*complete_cb)(void); -}; - -struct ep_ctx { - uint16_t maxpktsize; - uint16_t flags; - - union { - struct ep_transfer *transfer; - struct fifo *fifo; - }; -}; - -#define CTX_TRANSFER 0x01 /* ctx use ep_transfer struct */ -#define CTX_FIFO 0x02 /* ctx use fifo */ -#define CTX_IN 0x04 /* write to the host */ -#define CTX_OUT 0x08 /* read from the host */ -#define CTX_RXBANK0 0x10 -#define CTX_RXBANK1 0x20 - -static struct ep_transfer ep0_transfer; -static struct ep_ctx ep_ctx[4]; - -static uint16_t current_address; -static uint16_t current_config; -static uint16_t current_interface; - -static const struct usb_device_descriptor dev_descriptor = { - .bLength = sizeof(struct usb_device_descriptor), - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0110, - .bMaxPacketSize0 = 8, - .idVendor = USB_VENDOR_ID, - .idProduct = USB_PRODUCT_ID +1, - .bcdDevice = 0x0001, - .bNumConfigurations = 1, -}; - -struct my_config { - struct usb_config_descriptor cfg; - struct usb_interface_descriptor ctrl_iface; - struct usb_cdc_header_desc cdc_header; - struct usb_cdc_call_mgmt_descriptor cdc_call_mgmt; - struct usb_cdc_acm_descriptor cdc_acm; - struct usb_cdc_union_desc cdc_union; - struct usb_endpoint_descriptor notify_ep; - struct usb_interface_descriptor data_iface; - struct usb_endpoint_descriptor dataout_ep; - struct usb_endpoint_descriptor datain_ep; -} __attribute__ ((packed)); - -static const struct my_config cfg_descriptor = { -.cfg = { - .bLength = sizeof(struct usb_config_descriptor), - .bDescriptorType = USB_DT_CONFIG, - .wTotalLength = sizeof(struct my_config), - .bNumInterfaces = 2, - .bConfigurationValue = 1, - .bmAttributes = USB_CONFIG_ATT_SELFPOWER | USB_CONFIG_ATT_WAKEUP, - .bMaxPower = 50, -}, -.ctrl_iface = { - .bLength = sizeof(struct usb_interface_descriptor), - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, - .bInterfaceProtocol = 1, -}, -.cdc_header = { - .bLength = sizeof(struct usb_cdc_header_desc), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_HEADER_TYPE, - .bcdCDC = 0x0110, -}, -.cdc_call_mgmt = { - .bLength = sizeof(struct usb_cdc_call_mgmt_descriptor), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, - .bmCapabilities = USB_CDC_CALL_MGMT_CAP_CALL_MGMT, - .bDataInterface = 1, -}, -.cdc_acm = { - .bLength = sizeof(struct usb_cdc_acm_descriptor), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_ACM_TYPE, - .bmCapabilities = (USB_CDC_CAP_BRK | USB_CDC_CAP_LINE | USB_CDC_COMM_FEATURE), -}, -.cdc_union = { - .bLength = sizeof(struct usb_cdc_union_desc), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_UNION_TYPE, - .bMasterInterface0 = 0, - .bSlaveInterface0 = 1, -}, -.notify_ep = { - .bLength = sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN | 0x03, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = 64, - .bInterval = 10, -}, -.data_iface = { - .bLength = sizeof(struct usb_interface_descriptor), - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 1, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_CDC_DATA, -}, -.dataout_ep = { - .bLength = sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT | 0x01, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 64, -}, -.datain_ep = { - .bLength = sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN | 0x02, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 64, -}, -}; - -static void ep_transfer_send(uint32_t ep, char *data, uint32_t length, - void (*complete_cb)(void)) -{ - struct ep_ctx *ctx = &ep_ctx[ep]; -// printf("ep_transfer_send(%ld) size=%ld flags=0x%x\n\r", ep, length, ctx->flags); - if (!(ctx->flags & CTX_TRANSFER) || (ctx->flags & (CTX_IN | CTX_OUT))) - return; - - /* from buffer to usb */ - ctx->flags |= CTX_IN; - - struct ep_transfer *transfer = ctx->transfer; - transfer->length = length; - transfer->curpos = 0; - transfer->data = data; - transfer->complete_cb = complete_cb; - - uint32_t maxsize = ctx->maxpktsize; - - /* get data from transfer */ - while (transfer->curpos < transfer->length && maxsize--) - AT91C_UDP_FDR[ep] = transfer->data[transfer->curpos++]; - - /* trigger tx */ - AT91C_UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY; -} - -static void ep_transfer_receive(uint32_t ep, char *data, uint32_t length, - void (*complete_cb)(void)) -{ - struct ep_ctx *ctx = &ep_ctx[ep]; -// printf("ep_transfer_receive(%ld) size=%ld flags=0x%x\n\r", ep, length, ctx->flags); - if (!(ctx->flags & CTX_TRANSFER) || (ctx->flags & (CTX_IN | CTX_OUT))) - return; - - /* from usb to buffer */ - ctx->flags |= CTX_OUT; - - struct ep_transfer *transfer = ctx->transfer; - transfer->length = length; - transfer->curpos = 0; - transfer->data = data; - transfer->complete_cb = complete_cb; -} - -/* stalls the endpoint */ -static void ep_send_stall(uint32_t ep) -{ - printf("stall\n\r"); - AT91C_UDP_CSR[ep] |= AT91C_UDP_FORCESTALL; -} - -static void udp_configure_ep(const struct usb_endpoint_descriptor *desc) -{ - /* get endpoint address, set Max Packet Size */ - uint32_t ep = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - ep_ctx[ep].maxpktsize = desc->wMaxPacketSize; - - /* get endpoint type (ctrl, iso, bulb, int) */ - uint32_t eptype = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; - if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) { - eptype |= 0x04; - } else { - ep_ctx[ep].flags |= CTX_RXBANK0; - } - - /* configure UDP endpoint and enable interrupt */ - AT91C_UDP_CSR[ep] = AT91C_UDP_EPEDS | (eptype << 8); - *AT91C_UDP_IER = (1 << ep); -} - -/* - * set local address - * (USB_REQ_SET_ADDRESS callback) - */ -static void udp_txcb_setaddress(void) -{ - *AT91C_UDP_FADDR = (AT91C_UDP_FEN | current_address); - *AT91C_UDP_GLBSTATE = AT91C_UDP_FADDEN; -} - -/* - * configure endpoints - * (USB_REQ_SET_CONFIGURATION callback) - */ -static void udp_txcb_setconfig(void) -{ - udp_configure_ep(&cfg_descriptor.notify_ep); - udp_configure_ep(&cfg_descriptor.datain_ep); - udp_configure_ep(&cfg_descriptor.dataout_ep); - - /* set UDP to "configured" */ - *AT91C_UDP_GLBSTATE = AT91C_UDP_CONFG; -} - -static void udp_txcb_setinterface(void) -{ - printf("claim interface %d\n\r", current_interface); -} - -static void ep_handle_ctrlrequest(struct usb_ctrlrequest *req) -{ - printf("typ:0x%02x req:0x%02x val:0x%04x idx:0x%04x len:0x%04x\n\r", - req->bRequestType, req->bRequest, req->wValue, req->wIndex, req->wLength); - - switch (req->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK)) { - case (USB_TYPE_STANDARD | USB_RECIP_DEVICE): /* 0x00/0x80 */ - switch (req->bRequest) { - case USB_REQ_SET_ADDRESS: /* 0x05 */ - current_address = req->wValue; - ep_transfer_send(0, NULL, 0, udp_txcb_setaddress); - break; - - case USB_REQ_GET_DESCRIPTOR: /* 0x06 */ - switch (req->wValue >> 8) { - case USB_DT_DEVICE: /* 0x01 */ - ep_transfer_send(0, (char *)&dev_descriptor, - MIN(sizeof(dev_descriptor), req->wLength), - NULL); - break; - - case USB_DT_CONFIG: /* 0x02 */ - ep_transfer_send(0, (char *)&cfg_descriptor, - MIN(sizeof(cfg_descriptor), req->wLength), - NULL); - break; - - default: - ep_send_stall(0); - break; - } - break; - - case USB_REQ_SET_CONFIGURATION: /* 0x09 */ - current_config = req->wValue; - ep_transfer_send(0, NULL, 0, udp_txcb_setconfig); - break; - - default: - ep_send_stall(0); - break; - } - break; - - case (USB_TYPE_STANDARD | USB_RECIP_INTERFACE): /* 0x01/0x81 */ - // TODO: follow current_interface - switch (req->bRequest) { - case USB_REQ_SET_INTERFACE: /* 0x0b */ - current_interface = req->wValue; - ep_transfer_send(0, NULL, 0, udp_txcb_setinterface); - break; - - default: - ep_send_stall(0); - break; - } - break; - - case (USB_TYPE_CLASS | USB_RECIP_INTERFACE): /* 0x21/0xA1 */ - // TODO: follow current_interface - switch (req->bRequest) { - case USB_CDC_REQ_SET_LINE_CODING: /* 0x20 */ - /* read 7 bytes */ - break; - - case USB_CDC_REQ_SET_CONTROL_LINE_STATE: /* 0x22 */ - ep_transfer_send(0, NULL, 0, NULL); - break; - - default: - ep_send_stall(0); - break; - } - break; - - default: - ep_send_stall(0); - break; - } -} - -static void udp_handle_ep(uint32_t ep) -{ - /* endpoint enabled? */ - AT91_REG *csr = &AT91C_UDP_CSR[ep]; - if (!(*csr & AT91C_UDP_EPEDS)) - return; - - /* ctrl request packet? */ - if (*csr & AT91C_UDP_RXSETUP) { - struct usb_ctrlrequest req; - uint8_t *p; - for (p = (uint8_t *)&req; p < (uint8_t *)(&req +1); p++) - *p = AT91C_UDP_FDR[ep]; - - /* set data phase transfer direction */ - if (req.bRequestType & USB_DIR_IN) - *csr |= AT91C_UDP_DIR; - - /* clear interrupt - *MUST* use csr_clear_flags() here */ - csr_clear_flags(*csr, AT91C_UDP_RXSETUP); - - ep_handle_ctrlrequest(&req); - } - - /* transmit complete? */ - if (*csr & AT91C_UDP_TXCOMP) { - struct ep_ctx *ctx = &ep_ctx[ep]; - - if (ctx->flags & CTX_FIFO) { - /* get data from fifo */ - if (fifo_txudp(ctx->fifo, ep, ctx->maxpktsize)) - AT91C_UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY; - - } else if ((ctx->flags & (CTX_TRANSFER | CTX_IN)) == (CTX_TRANSFER | CTX_IN)) { - /* transfer not complete */ - struct ep_transfer *transfer = ctx->transfer; - if (transfer->length != transfer->curpos) { - uint32_t maxsize = ctx->maxpktsize; - - /* get data from transfer */ - while (transfer->curpos < transfer->length && maxsize--) - AT91C_UDP_FDR[ep] = transfer->data[transfer->curpos++]; - - /* trigger tx */ - AT91C_UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY; - - /* transfer complete, execute callback */ - } else { - ctx->flags &= ~CTX_IN; - - if (transfer->complete_cb) - transfer->complete_cb(); - } - } - - /* clear interrupt */ - *csr &= ~(AT91C_UDP_TXCOMP); - } - - /* clear STALLSENT interrupt */ - if (*csr & AT91C_UDP_STALLSENT) - csr_clear_flags(*csr, (AT91C_UDP_STALLSENT | AT91C_UDP_FORCESTALL)); - - /* data ready to read? */ - if (*csr & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1)) { - struct ep_ctx *ctx = &ep_ctx[ep]; - - uint16_t len = (*csr & AT91C_UDP_RXBYTECNT) >> 16; - - // TODO: only ep0 status OUT? - if (!len && (ctx->flags & CTX_TRANSFER)) { - ctx->flags &= ~(CTX_OUT | CTX_IN); - ctx->transfer->length = 0; - ctx->transfer->curpos = 0; - } - - if (ctx->flags & CTX_FIFO) { - fifo_rxudp(ctx->fifo, ep, len); - - } else if ((ctx->flags & (CTX_TRANSFER | CTX_OUT)) == (CTX_TRANSFER | CTX_OUT)) { - - /* transfer not complete */ - struct ep_transfer *transfer = ctx->transfer; - if (transfer->length != transfer->curpos) { - /* get data from transfer */ - while (transfer->curpos < transfer->length && len--) - transfer->data[transfer->curpos++] = AT91C_UDP_FDR[ep]; - } - - /* test again */ - if (transfer->length == transfer->curpos) { - ctx->flags &= ~CTX_OUT; - - if (transfer->complete_cb) - transfer->complete_cb(); - } - } - - if (ctx->flags & CTX_RXBANK0) { - if (*csr & AT91C_UDP_RX_DATA_BK0) - csr_clear_flags(*csr, AT91C_UDP_RX_DATA_BK0); - - /* all but ep0 have ping pong buffers */ - if (ep > 0) - ctx->flags = (ctx->flags & ~CTX_RXBANK0) | CTX_RXBANK1; - - } else if (ctx->flags & CTX_RXBANK1) { - if (*csr & AT91C_UDP_RX_DATA_BK1) - csr_clear_flags(*csr, AT91C_UDP_RX_DATA_BK1); - - ctx->flags = (ctx->flags & ~CTX_RXBANK1) | CTX_RXBANK0; - } - } -} - -static void udp_isr(void) -{ - uint32_t isr = *AT91C_UDP_ISR; - if (isr & AT91C_UDP_ENDBUSRES) { - AT91S_UDP *udp = AT91C_BASE_UDP; - - /* reset all endpoints */ - udp->UDP_RSTEP = (AT91C_UDP_EP0 | AT91C_UDP_EP1 | - AT91C_UDP_EP2 | AT91C_UDP_EP3) ; - udp->UDP_RSTEP = 0; - - /* init ep0 */ - struct ep_ctx *ctx = &ep_ctx[0]; - ctx->maxpktsize = 8; - ctx->flags = CTX_TRANSFER | CTX_RXBANK0; - ctx->transfer = &ep0_transfer; - ctx->transfer->length = 0; - ctx->transfer->curpos = 0; - - /* Configure endpoint0 as Control EP */ - udp->UDP_CSR[0] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL); - - /* enable ep0 Interrupt, disable all others */ - udp->UDP_IER = AT91C_UDP_EPINT0; - udp->UDP_IDR = AT91C_UDP_EPINT1 | AT91C_UDP_EPINT2 | AT91C_UDP_EPINT3 | - AT91C_UDP_RXSUSP | AT91C_UDP_RXRSM | AT91C_UDP_SOFINT | - AT91C_UDP_WAKEUP; - } - - /* Handle Endpoint Interrupts */ - uint32_t i; - for (i = 0; i < 4; i++) { - if (isr & *AT91C_UDP_IMR & (1<PIO_CODR = UDP_PULLUP; - pio->PIO_PER = UDP_PULLUP; - pio->PIO_OER = UDP_PULLUP; - // TODO: needed? - pio->PIO_PPUDR = UDP_VBUS_MON; - - /* UDPCK (48MHz) = PLLCK / 2 */ - *AT91C_CKGR_PLLR |= AT91C_CKGR_USBDIV_1; - - /* enable UDP clocks */ - *AT91C_PMC_SCER = AT91C_PMC_UDP; - *AT91C_PMC_PCER = (1 << AT91C_ID_UDP); - - /* enable transmitter */ - *AT91C_UDP_TXVC &= ~AT91C_UDP_TXVDIS; - - /* clear & disable all UDP interrupts */ - *AT91C_UDP_IDR = AT91C_UDP_EPINT0 | AT91C_UDP_EPINT1 | AT91C_UDP_EPINT2 | - AT91C_UDP_EPINT3 | AT91C_UDP_RXSUSP | AT91C_UDP_RXRSM | - AT91C_UDP_SOFINT | AT91C_UDP_WAKEUP; - - *AT91C_UDP_ICR = AT91C_UDP_RXSUSP | AT91C_UDP_RXRSM | AT91C_UDP_SOFINT | - AT91C_UDP_ENDBUSRES | AT91C_UDP_WAKEUP ; - - /* level triggered, own vector */ - AT91S_AIC *aic = AT91C_BASE_AIC; - aic->AIC_SMR[AT91C_ID_UDP] = IRQPRIO_UDP | AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL; - aic->AIC_SVR[AT91C_ID_UDP] = (uint32_t)udp_isr; - aic->AIC_IECR = (1 << AT91C_ID_UDP); - - pio_trigger_isr(UDP_VBUS_MON); -} - -static void udp_vbus_monitor(uint32_t status, uint32_t input) -{ - if (input & UDP_VBUS_MON) - /* usb connected -> enable pullup */ - *AT91C_PIOA_SODR = UDP_PULLUP; - else - /* usb got diconnected -> disable pullup */ - *AT91C_PIOA_CODR = UDP_PULLUP; -} - -PIO_PINCHANGE_ISR(UDP_VBUS_MON, udp_vbus_monitor); diff --git a/src/rtos/context.c b/src/rtos/context.c new file mode 100644 index 0000000..9a6118b --- /dev/null +++ b/src/rtos/context.c @@ -0,0 +1 @@ +#include diff --git a/src/telemetrie.c b/src/telemetrie.c deleted file mode 100644 index 4df776c..0000000 --- a/src/telemetrie.c +++ /dev/null @@ -1,255 +0,0 @@ -/*************************************************************************** - * Copyright (C) 02/2008 by Olaf Rempel * - * razzor@kopf-tisch.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; version 2 of the License * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#include -#include -#include -#include "board.h" // ARRAY_SIZE() -#include "at91_pitc.h" -#include "telemetrie.h" -#include "memalloc.h" -#include "fifo.h" - -/* extern symbols, defined in ldscript */ -extern struct tdc_value _tdc_value_table; -extern struct tdc_value _tdc_value_table_end; - -/* max. 8x 32 = 256 variables */ -static uint32_t tdc_varmap[8]; - -/* array of devices, that are used to reach address X */ -static struct comm_device *routing_table[8]; - -/* - * returns: - * -1: on routing error - * 0: no space left in txfifo (caller should retry) - * >0: success - */ -int32_t tdc_transmit(uint32_t addr, struct tdc_pkt_header *head) -{ - if (addr >= ARRAY_SIZE(routing_table) || !routing_table[addr]) - return -1; - - return fifo_put(routing_table[addr]->txfifo, (char *)head, head->size); -} - -static int32_t tdc_get_vars(void) -{ - /* restart point */ - static uint32_t id; - - struct tdc_value *value = &_tdc_value_table + id; - - while (value < &_tdc_value_table_end) { - uint32_t datalen = strlen(value->name); - - struct tdc_getvars_reply *reply = alloc(sizeof(struct tdc_getvars_reply) + datalen); - reply->cmd = TDC_REPLY | TDC_ADDR1 | TDC_GETVARS; - reply->size = sizeof(struct tdc_getvars_reply) + datalen; - reply->id = id; - reply->flags = value->flags; - memcpy(reply->name, value->name, datalen); - - uint32_t ret = tdc_transmit(TDC_ADDR0, ((struct tdc_pkt_header *)reply)); - free(reply); - - /* push routing error(-1) and retry(0) */ - if (ret <= 0) - return ret; - - id++; - value++; - } - - /* dump complete, reset restart point */ - id = 0; - return 1; -} - -static int32_t tdc_get_value(uint32_t id) -{ - struct tdc_value *value = &_tdc_value_table + id; - if (value >= &_tdc_value_table_end) - return -1; - - uint32_t datalen = value->flags & TDC_SIZEMASK; - - struct tdc_getvalue_reply *reply = alloc(sizeof(struct tdc_getvalue_reply) + datalen); - reply->cmd = TDC_REPLY | TDC_ADDR1 | TDC_GETVALUE; - reply->size = sizeof(struct tdc_getvars_reply) + datalen; - reply->id = id; - memcpy(reply->data, value->data, datalen); - - int32_t ret = tdc_transmit(TDC_ADDR0, ((struct tdc_pkt_header *)reply)); - free(reply); - - return ret; -} - -static int32_t tdc_set_value(uint32_t id, uint8_t *data) -{ - struct tdc_value *value = &_tdc_value_table + id; - if (value >= &_tdc_value_table_end) - return -1; - - uint32_t datalen = value->flags & TDC_SIZEMASK; - - // TODO: atomic? - memcpy(value->data, data, datalen); - - return 1; -} - -static uint32_t tdc_timer_cb(struct pitc_timer *timer) -{ - uint32_t i, j; - for (i = 0; i < ARRAY_SIZE(tdc_varmap); i++) { - uint32_t tmp = tdc_varmap[i]; - - for (j = 0; j < 32; j++) { - if (!tmp) - break; - - if (tmp & 0x01) { - if (tdc_get_value(i * 32 + j) <= 0) - return PITC_REMOVE_TIMER; - } - - tmp >>= 1; - } - } - return PITC_RESTART_TIMER; -} - -static struct pitc_timer tdc_timer = { - .func = tdc_timer_cb, -}; - -static int32_t tdc_setup_timer(uint32_t interval, uint32_t *varmap) -{ - memcpy(tdc_varmap, varmap, sizeof(tdc_varmap)); - - if (interval > 0) { - tdc_timer.interval = interval; - // TODO: timer already running - pitc_schedule_timer(&tdc_timer); - - } else { - // TODO: timer stop - } - return 1; -} - -static const struct tdc_hello_reply hello_reply = { - .cmd = TDC_REPLY | TDC_ADDR1 | TDC_HELLO, - .size = sizeof(struct tdc_hello_reply), - .name = "sam7fc-v0.01", -}; - -/* - * returns: - * -1: on routing error - * 0: no space left in txfifo (caller should retry) - * >0: success - */ -static int32_t tdc_parse_packet(struct tdc_pkt_header *head) -{ - /* all replys go to the HOST */ - if (head->cmd & TDC_REPLY) - return tdc_transmit(TDC_ADDR0, head); - - /* forward this packet? */ - if ((head->cmd & TDC_ADDRMASK) != TDC_ADDR1) { - uint32_t addr = (head->cmd & TDC_ADDRMASK) >> 4; - return tdc_transmit(addr, head); - } - - int32_t ret = -1; - - /* parse the packet */ - switch (head->cmd & TDC_OPCODEMASK) { - case TDC_HELLO: - /* answer the hello */ - ret = tdc_transmit(TDC_ADDR0, (struct tdc_pkt_header *)&hello_reply); - break; - - case TDC_GETVARS: - ret = tdc_get_vars(); - break; - - case TDC_GETVALUE: { - struct tdc_getvalue_request *pkt = (struct tdc_getvalue_request *)head; - ret = tdc_get_value(pkt->id); - } break; - - case TDC_SETVALUE: { - struct tdc_setvalue_request *pkt = (struct tdc_setvalue_request *)head; - ret = tdc_set_value(pkt->id, pkt->data); - } break; - - case TDC_REQVALUES: { - struct tdc_reqvalues_request *pkt = (struct tdc_reqvalues_request *)head; - ret = tdc_setup_timer(pkt->interval, pkt->varmap); - } break; - }; - - /* - * on succes(>0) return size of request, - * and push retry(0) and routing error(-1) up - */ - return (ret > 0) ? head->size : ret; -} - -void tdc_register_device(uint32_t addr, struct comm_device *device) -{ - if (addr < ARRAY_SIZE(routing_table)) - routing_table[addr] = device; -} - -void tdc_receive(struct comm_device *device) -{ - while (1) { - /* peek the header */ - struct tdc_pkt_header tmp_head; - uint32_t len = fifo_peek(device->rxfifo, (char *)&tmp_head, sizeof(tmp_head)); - if (len != sizeof(tmp_head)) - return; - - /* peek the whole packet */ - struct tdc_pkt_header *head = alloc(tmp_head.size); - len = fifo_peek(device->rxfifo, (char *)head, tmp_head.size); - if (len != tmp_head.size) - return; - - /* if it's a hello-request, remember the device as path to the host */ - if ((head->cmd & (TDC_OPCODEMASK & TDC_DIR)) == TDC_HELLO) - tdc_register_device(TDC_ADDR0, device); - - /* parse packet, remove data if no restart is needed */ - int32_t ret = tdc_parse_packet(head); - free(head); - - /* some tx-fifo was full(0), return to caller and let it retry */ - if (!ret) - return; - - /* success(>0) or routing error(-1) -> remove the packet */ - fifo_remove(device->rxfifo, tmp_head.size); - } -}