aboutsummaryrefslogtreecommitdiff
path: root/center_fw/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'center_fw/src/main.c')
-rw-r--r--center_fw/src/main.c337
1 files changed, 233 insertions, 104 deletions
diff --git a/center_fw/src/main.c b/center_fw/src/main.c
index 274abad..59bd7a1 100644
--- a/center_fw/src/main.c
+++ b/center_fw/src/main.c
@@ -17,11 +17,54 @@
#include "global.h"
#include "8b10b.h"
+#include "crc32.h"
+#include "protocol.h"
+#include "xorshift.h"
-static uint16_t adc_data[64*2];
static volatile struct state_8b10b_dec st_8b10b_dec;
-static void quicksort(uint16_t *head, uint16_t *tail);
+/* Modulation constants */
+#define THRESHOLD_ADC_COUNTS 28500 /* ADC counts */
+#define MIN_RECTIFIER_MARGIN 5000 /* ADC counts */
+#define SAMPLES_PER_BAUD 16
+#define OVERSAMPLING_RATIO 16
+#define SAMPLING_PHASE (SAMPLES_PER_BAUD / 2)
+#define LED_DEAD_TIME 4 /* in ADC samples */
+#ifndef CONFIG_MODULE_ADDRESS
+#warn "CONFIG_MODULE_ADDRESS is not defined, defaulting to 0."
+#define CONFIG_MODULE_ADDRESS 0
+#endif /* CONFIG_MODULE_ADDRESS */
+
+#define DEBUG_DISABLE_DRIVERS 1
+
+
+volatile union {
+ struct data_packet packet;
+ uint8_t bytes[sizeof(struct data_packet)];
+} rx_buf;
+
+volatile ssize_t rx_pos;
+volatile bool packet_received;
+volatile bool rng_reset;
+uint32_t packet_rng_state = 0;
+
+struct data_packet foobar;
+int global_brightness;
+int channel_mask;
+
+struct error_counters {
+ int crc_errors;
+ int receive_overflows;
+ int processing_overflows;
+ int decoding_errors;
+} errors;
+
+/* generated by ./gamma.py */
+uint16_t brightness_lut[16] = {
+ 54, 247, 604, 1137, 1857, 2774, 3894, 5223,
+ 6768, 8534, 10525, 12745, 15199, 17891, 20823, 24000
+};
+
int main(void) {
/* Configure clocks for 64 MHz system clock.
@@ -49,40 +92,35 @@ int main(void) {
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
RCC->APBENR1 |= RCC_APBENR1_TIM3EN | RCC_APBENR1_DBGEN;
- RCC->APBENR2 |= RCC_APBENR2_TIM1EN | RCC_APBENR2_ADCEN;
+ RCC->APBENR2 |= RCC_APBENR2_TIM1EN | RCC_APBENR2_ADCEN | RCC_APBENR2_TIM14EN;
RCC->IOPENR |= RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN | RCC_IOPENR_GPIOCEN;
- /*
- TIM1->PSC = 0;
- TIM1->ARR = nominal_period;
- TIM1->DIER = TIM_DIER_UIE | TIM_DIER_CC1IE;
- TIM1->CR1 = TIM_CR1_ARPE | TIM_CR1_CEN;
- TIM1->CCR1 = 3000;
- NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
- NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 0);
- NVIC_EnableIRQ(TIM1_CC_IRQn);
- NVIC_SetPriority(TIM1_CC_IRQn, 0);
- */
+ TIM14->CR1 = TIM_CR1_ARPE | TIM_CR1_OPM;
+ /* External clock mode, with TIM 3 as source */
+ TIM14->PSC = 0;
+ static_assert(125 * (SAMPLES_PER_BAUD - LED_DEAD_TIME) * OVERSAMPLING_RATIO <= 0xffff);
+ TIM14->ARR = 125 * (SAMPLES_PER_BAUD - LED_DEAD_TIME) * OVERSAMPLING_RATIO;
+ TIM14->CCER = TIM_CCER_CC1E;
+ TIM14->DIER = TIM_DIER_CC1IE;
+ NVIC_EnableIRQ(TIM14_IRQn);
+ NVIC_SetPriority(TIM14_IRQn, 1<<6);
+
+ for (int i=0; i<COUNT_OF(brightness_lut); i++) {
+ }
xfr_8b10b_reset((struct state_8b10b_dec *)&st_8b10b_dec);
+ rx_pos = -1;
+ packet_received = false;
+ rng_reset = false;
+ memset(&errors, 0, sizeof(errors));
TIM3->CR1 = TIM_CR1_ARPE;
TIM3->CR2 = (2<<TIM_CR2_MMS_Pos); /* Update event on TRGO */
TIM3->PSC = 0;
/* We sample 32 times per 1 kHz AC cycle, and use 32 times oversampling. */
- TIM3->ARR = 125*16; /* Output 64 MHz / 125 = 512 kHz signal */
+ TIM3->ARR = 125; /* Output 64 MHz / 125 = 512.0 kHz signal */
TIM3->CR1 |= TIM_CR1_CEN;
- DMAMUX1[0].CCR = 5; /* ADC */
- DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;
- DMA1_Channel1->CMAR = (uint32_t)(void *)adc_data;
- DMA1_Channel1->CNDTR = COUNT_OF(adc_data);
- DMA1_Channel1->CCR = (1<<DMA_CCR_MSIZE_Pos) | (1<<DMA_CCR_PSIZE_Pos) | DMA_CCR_MINC | DMA_CCR_CIRC | DMA_CCR_HTIE | DMA_CCR_TCIE;
- DMA1_Channel1->CCR |= DMA_CCR_EN;
-
- NVIC_EnableIRQ(DMA1_Channel1_IRQn);
- NVIC_SetPriority(DMA1_Channel1_IRQn, 64);
-
ADC1->ISR = ADC_ISR_CCRDY | ADC_ISR_ADRDY; /* Clear CCRDY */
ADC1->CR = ADC_CR_ADVREGEN;
delay_us(20);
@@ -90,8 +128,8 @@ int main(void) {
while (ADC1->CR & ADC_CR_ADCAL) {
/* wait. */
}
- ADC1->CFGR1 = (1<<ADC_CFGR1_EXTEN_Pos) | (3<<ADC_CFGR1_EXTSEL_Pos) | ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG; /* TIM3 TRGO */
- ADC1->CFGR2 = (1<<ADC_CFGR2_CKMODE_Pos) | (4<<ADC_CFGR2_OVSR_Pos) | (1<<ADC_CFGR2_OVSS_Pos) | ADC_CFGR2_OVSE;
+ ADC1->CFGR1 = (1<<ADC_CFGR1_EXTEN_Pos) | (3<<ADC_CFGR1_EXTSEL_Pos); /* TIM3 TRGO */
+ ADC1->CFGR2 = (1<<ADC_CFGR2_CKMODE_Pos) | (3<<ADC_CFGR2_OVSR_Pos) | (0<<ADC_CFGR2_OVSS_Pos) | ADC_CFGR2_TOVS | ADC_CFGR2_OVSE;
ADC1->CHSELR = (1<<4); /* Enable input 4 -> PA4 (Vdiff)*/
while (!(ADC1->ISR & ADC_ISR_CCRDY)) {
/* wait. */
@@ -102,6 +140,9 @@ int main(void) {
while (!(ADC1->ISR & ADC_ISR_ADRDY)) {
/* wait. */
}
+ ADC1->IER = ADC_IER_EOCIE;
+ NVIC_EnableIRQ(ADC1_IRQn);
+ NVIC_SetPriority(ADC1_IRQn, 0);
ADC1->CR |= ADC_CR_ADSTART;
GPIOA->MODER = OUT(0) | IN(1) | OUT(2) | OUT(3) | ANALOG(4) | OUT(5) | OUT(6) | IN(7) | ANALOG(9) | ANALOG(10) | OUT(11) | ANALOG(12)| AF(13) | AF(14);
@@ -111,73 +152,187 @@ int main(void) {
DBG->APBFZ1 |= DBG_APB_FZ1_DBG_TIM3_STOP;
DBG->APBFZ2 |= DBG_APB_FZ2_DBG_TIM1_STOP;
while (42) {
+ if (packet_received) {
+ if (rng_reset) {
+ packet_rng_state = xorshift32(1);
+ }
+
+ for(size_t i=0; i<sizeof(rx_buf.packet); i++) {
+ packet_rng_state = xorshift32(packet_rng_state);
+ // rx_buf.bytes[i] ^= packet_rng_state; FIXME DEBUG
+ }
+
+ uint32_t crc_state = crc32_reset();
+ for(size_t i=0; i<offsetof(struct data_packet, crc); i++) {
+ crc_state = crc32_update(crc_state, rx_buf.bytes[i]);
+ }
+ crc_state = crc32_finalize(crc_state);
+
+ if (crc_state == rx_buf.packet.crc) {
+ /* good packet received */
+ int val = rx_buf.packet.brightness[CONFIG_MODULE_ADDRESS/2];
+ if (CONFIG_MODULE_ADDRESS & 1) {
+ val >>= 4;
+ }
+ global_brightness = val;
+ channel_mask = rx_buf.packet.channels[CONFIG_MODULE_ADDRESS];
+
+ } else {
+ errors.crc_errors++;
+ }
+
+ packet_received = false;
+ }
}
}
-/*
-void TIM1_BRK_UP_TRG_COM_IRQHandler(void) {
- TIM1->SR &= ~TIM_SR_UIF;
-}
+int16_t sym_dump[512];
+size_t sym_dump_pos = 0;
+
+uint8_t adc_dump[32];
+size_t adc_dump_pos = 0;
+
+uint8_t bit_dump[4096];
+size_t bit_dump_pos = 0;
-void TIM1_CC_IRQHandler(void) {
- TIM1->SR &= ~TIM_SR_CC1IF;
+void gdb_dump(void) {
}
-*/
-static size_t received_symbols = 0;
-static int symbol_buf[64];
-static size_t received_bits = 0;
-static int16_t bit_buf[256];
-size_t adc_reduced_pos = 0;
-static uint8_t adc_reduced[4096];
-
-void DMA1_Channel1_IRQHandler(void) {
- static int sampling_phase = 0;
- static int last_sample = 0;
-
- uint16_t *buf = (DMA1->ISR & DMA_ISR_HTIF1) ? &adc_data[0] : &adc_data[COUNT_OF(adc_data)/2];
- DMA1->IFCR = DMA_IFCR_CGIF1;
+
+void ADC1_IRQHandler(void) {
+ static int phase = 0;
+ static int last_bit = 0;
GPIOB->BSRR = (1<<7);
- const int threshold_adc_counts = 28500;
- const int sample_per_baud = 16;
+ /* Read sample and apply threshold */
+ int sample = ADC1->DR; /* resets the EOC interrupt flag */
+ int bit = sample > THRESHOLD_ADC_COUNTS;
+ int bit_margin = ((int)sample) - THRESHOLD_ADC_COUNTS;
+ if (bit_margin < 0) {
+ bit_margin = -bit_margin;
+ }
+
+ adc_dump[adc_dump_pos] = (sample>>10) & 0x3f;
- for (size_t i=0; i<COUNT_OF(adc_data)/2; i++) {
- int sample = buf[i];
+ /* Find edges and compute current phase */
+ if (bit && !last_bit) { /* rising edge */
+ phase = 0;
+ adc_dump[adc_dump_pos] |= 0x40;
- adc_reduced[adc_reduced_pos] = (sample & 0xffff)>>9;
+ } else if (last_bit && !bit) { /* falling edge */
+ phase = 0;
+ adc_dump[adc_dump_pos] |= 0x40;
- if ((last_sample <= threshold_adc_counts && sample >= threshold_adc_counts) ||
- (last_sample >= threshold_adc_counts && sample <= threshold_adc_counts)){
- sampling_phase = sample_per_baud / 4; /* /2 for half baud sampling point, /2 for sinusoidal edge shape */
+ } else {
+ phase ++;
+ if (phase == SAMPLES_PER_BAUD) {
+ phase = 0;
+ }
+ }
- } else if (sampling_phase == 0) {
- int bit = sample > threshold_adc_counts;
- adc_reduced[adc_reduced_pos] |= 0x80;
+ /* Trigger 8b10b sample */
+ if (phase == SAMPLING_PHASE) {
+ adc_dump[adc_dump_pos] |= 0x80;
- bit_buf[received_bits] = bit;
- received_bits = (received_bits+1) % COUNT_OF(bit_buf);
+ bit_dump[bit_dump_pos] = bit;
+ bit_dump_pos++;
+ if (bit_dump_pos == COUNT_OF(bit_dump)) {
+ bit_dump_pos = 0;
+ gdb_dump();
+ }
- int rc = xfr_8b10b_feed_bit((struct state_8b10b_dec *)&st_8b10b_dec, bit);
- if (rc > -K_CODES_LAST) {
- symbol_buf[received_symbols] = rc;
- received_symbols = (received_symbols+1) % COUNT_OF(symbol_buf);
+ int rc = xfr_8b10b_feed_bit((struct state_8b10b_dec *)&st_8b10b_dec, bit);
+ if (rc > -K_CODES_LAST) {
+ sym_dump[sym_dump_pos++] = rc;
+ if (sym_dump_pos == COUNT_OF(sym_dump)) {
+ sym_dump_pos = 0;
}
- sampling_phase = sample_per_baud;
+ if (rc < 0) {
+ if (rc == -K28_1) {
+ rng_reset = true;
+ rx_pos = 0;
+
+ } else if (rc == -K27_7) {
+ if (rx_pos >= 0) {
+ rx_pos = 0;
+ }
+ } else {
+ rx_pos = -1;
+ }
+ } else {
+ if (packet_received) {
+ /* receive buffer overflow */
+ rx_pos = -1;
+ errors.processing_overflows++;
+
+ } else {
+ if (rx_pos == sizeof(rx_buf.packet)) {
+ /* receive buffer overflow */
+ rx_pos = -1;
+ errors.receive_overflows++;
+ }
+
+ rx_buf.bytes[rx_pos] = rc;
+ rx_pos++;
+ if (rx_pos == sizeof(rx_buf.packet)) {
+ packet_received = true;
+ }
+ }
+ }
} else {
- sampling_phase--;
+ errors.decoding_errors++;
}
+ }
+
+ adc_dump_pos++;
+ if (adc_dump_pos == COUNT_OF(adc_dump)) {
+ adc_dump_pos = 0;
+ }
- adc_reduced_pos++;
- if (adc_reduced_pos == COUNT_OF(adc_reduced)) {
- adc_reduced_pos =0;
+ /* Trigger synchronous rectifier */
+ if (phase == SAMPLES_PER_BAUD - LED_DEAD_TIME || bit != last_bit || bit_margin < MIN_RECTIFIER_MARGIN) { /* reset */
+ GPIOA->BRR = (1<<11); /* RECT1 */
+ GPIOC->BRR = (1<<15); /* RECT2 */
+ GPIOA->BRR = (1<<6);
+
+ } else if (phase == LED_DEAD_TIME) { /* set */
+ if (bit) {
+ GPIOA->BSRR = (1<<6);
+#ifndef DEBUG_DISABLE_DRIVERS
+ GPIOC->BSRR = (1<<15); /* RECT2 */
+#endif
+ } else {
+#ifndef DEBUG_DISABLE_DRIVERS
+ GPIOA->BSRR = (1<<11); /* RECT1 */
+#endif
}
- last_sample = sample;
+
+ int nibble = (bit ? (channel_mask >> 4) : channel_mask) & 0x0f;
+ int b0 = (nibble>>0) & 1;
+ int b1 = (nibble>>1) & 1;
+ int b2 = (nibble>>2) & 1;
+ int b3 = (nibble>>3) & 1;
+
+#ifndef DEBUG_DISABLE_DRIVERS
+ GPIOA->BSRR = (b0<<2) | (b3<<3) | (b2<<5);
+ GPIOB->BSRR = (b1<<3);
+#endif
+ TIM14->CCR1 = brightness_lut[global_brightness];
+ TIM14->CR1 |= TIM_CR1_CEN;
}
+ last_bit = bit;
GPIOB->BRR = (1<<7);
}
+void TIM14_IRQHandler(void) {
+ TIM14->SR = 0;
+
+ /* Reset all LED outputs */
+ GPIOA->BRR = (1<<2) | (1<<3) | (1<<5);
+ GPIOB->BRR = (1<<3);
+}
+
void delay_us(int duration_us) {
while (duration_us--) {
for (int i=0; i<32; i++) {
@@ -186,6 +341,14 @@ void delay_us(int duration_us) {
}
}
+void *memset(void *s, int c, size_t n) {
+ uint8_t *b = (uint8_t *)s;
+ while (n--) {
+ *b++ = c;
+ }
+ return s;
+}
+
void NMI_Handler(void) {
asm volatile ("bkpt");
}
@@ -208,37 +371,3 @@ void __libc_init_array (void) __attribute__((weak));
void __libc_init_array () {
}
-/* https://github.com/openmv/openmv/blob/2e8d5d505dbe695b8009d832e5ef7691009148e1/src/omv/common/array.c#L117 */
-static void quicksort(uint16_t *head, uint16_t *tail) {
- while (head < tail) {
- uint16_t *h = head - 1;
- uint16_t *t = tail;
- uint16_t v = tail[0];
- for (;;) {
- do {
- ++h;
- } while (h < t && h[0] < v);
- do {
- --t;
- } while (h < t && v < t[0]);
- if (h >= t) {
- break;
- }
- uint16_t x = h[0];
- h[0] = t[0];
- t[0] = x;
- }
- uint16_t x = h[0];
- h[0] = tail[0];
- tail[0] = x;
- // do the smaller recursive call first, to keep stack within O(log(N))
- if (t - head < tail - h - 1) {
- quicksort(head, t);
- head = h + 1;
- } else {
- quicksort(h + 1, tail);
- tail = t;
- }
- }
-}
-