From 0c5b35fa3eecbe8c0035fdc5ca608a5c510df165 Mon Sep 17 00:00:00 2001 From: jaseg Date: Sat, 21 Apr 2018 16:21:48 +0200 Subject: Fix new packet-based comms protocol --- firmware/Makefile | 7 +-- firmware/global.h | 22 ++++++++++ firmware/mac.c | 3 -- firmware/mac.h | 22 ---------- firmware/main.c | 124 +++++++++++++++++++++++++++--------------------------- firmware/serial.c | 34 +++++++-------- firmware/serial.h | 11 ++++- 7 files changed, 113 insertions(+), 110 deletions(-) delete mode 100644 firmware/mac.c delete mode 100644 firmware/mac.h diff --git a/firmware/Makefile b/firmware/Makefile index 1e668e1..be1709b 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -10,9 +10,10 @@ OBJCOPY := arm-none-eabi-objcopy OBJDUMP := arm-none-eabi-objdump SIZE := arm-none-eabi-size -CFLAGS = -Wall -Wpedantic -Wstrict-aliasing -g -std=gnu11 -Os +#CFLAGS = -Wall -Wpedantic -Wstrict-aliasing -g -std=gnu11 -Os +CFLAGS = -Wall -Wpedantic -Wstrict-aliasing -g -std=gnu11 -O1 CFLAGS += -mlittle-endian -mcpu=cortex-m0 -march=armv6-m -mthumb -#CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections +CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections CFLAGS += -Wl,-Map=main.map # Technically we're using an STM32F030F4, but apart from the TSSOP20 package that one is largely identical to the @@ -43,7 +44,7 @@ sources.tar.xz.zip: sources.tar.xz sources.c: sources.tar.xz.zip xxd -i $< | head -n -1 | sed 's/=/__attribute__((section(".source_tarball"))) =/' > $@ -main.elf: main.c mac.c adc.c serial.c startup_stm32f030x6.s system_stm32f0xx.c $(HAL_PATH)/Src/stm32f0xx_ll_utils.c cmsis_exports.c +main.elf: main.c adc.c serial.c startup_stm32f030x6.s system_stm32f0xx.c $(HAL_PATH)/Src/stm32f0xx_ll_utils.c cmsis_exports.c sources.c $(CC) $(CFLAGS) -o $@ $^ $(OBJCOPY) -O ihex $@ $(@:.elf=.hex) $(OBJCOPY) -O binary $@ $(@:.elf=.bin) diff --git a/firmware/global.h b/firmware/global.h index 6116adc..3e585f6 100644 --- a/firmware/global.h +++ b/firmware/global.h @@ -1,9 +1,31 @@ #ifndef __GLOBAL_H__ #define __GLOBAL_H__ +#define COLOR_SPEC_WHITE 0x00 +#define COLOR_SPEC_SINGLE_COLOR 0x01 +#define COLOR_SPEC_RGB 0x02 +#define COLOR_SPEC_RGBW 0x03 +#define COLOR_SPEC_COLD_WARM_WHITE 0x04 +#define COLOR_SPEC_WWA 0x05 /* cold white/warm white/amber */ + +#define OLSNDOT_V1 0x01 + #define FIRMWARE_VERSION 2 #define HARDWARE_VERSION 2 +/* Maximum bit count supported by serial command protocol. The brightness data is assumed to be of this bit width, but + * only the uppermost NBITS bits are used. */ +#define MAX_BITS 16 + +/* Bit count of this device. Note that to change this you will also have to adapt the per-bit timer period lookup table + * in main.c. */ +#define NBITS 14 + +#define NCHANNELS 32 +#define CHANNEL_SPEC 'H' +#define COLOR_SPEC COLOR_SPEC_RGBW +#define DEVICE_TYPE OLSNDOT_V1 + #define TS_CAL1 (*(uint16_t *)0x1FFFF7B8) #define VREFINT_CAL (*(uint16_t *)0x1FFFF7BA) diff --git a/firmware/mac.c b/firmware/mac.c deleted file mode 100644 index b2fb48a..0000000 --- a/firmware/mac.c +++ /dev/null @@ -1,3 +0,0 @@ -#include "mac.h" - -uint32_t device_mac = MAC_ADDR; diff --git a/firmware/mac.h b/firmware/mac.h deleted file mode 100644 index 26aaff6..0000000 --- a/firmware/mac.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __MAC_H__ -#define __MAC_H__ - -#include - -/* Device MAC address. - * - * 32 bits might seem a little short for a device MAC, but at 20 bus nodes the probablility of a collision is about 1 in - * 10 million. Check for yourself using the python code below. - * - * #!/usr/bin/env python3 - * from operator import mul - * from functools import reduce - * m = 32 - * n = 20 - * print(reduce(mul, [2**m-i for i in range(n)]) / ((2**m)**n)) - * # -> 0.9999999557621786 - */ - -extern uint32_t device_mac; - -#endif /* __MAC_H__ */ diff --git a/firmware/main.c b/firmware/main.c index 7fc78c3..ec1e576 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -38,15 +38,6 @@ #include "serial.h" #include "adc.h" -/* Bit count of this device. Note that to change this you will also have to adapt the per-bit timer period lookup table - * below. - */ -#define NBITS 14 - -/* Maximum bit count supported by serial command protocol. The brightness data is assumed to be of this bit width, but - * only the uppermost NBITS bits are used. */ -#define MAX_BITS 16 - void do_transpose(void); /* Bit-golfed modulation data generated from the above values by the main loop, ready to be sent out to the shift @@ -58,6 +49,56 @@ volatile uint32_t brightness_by_bit[NBITS] = { 0 }; uint32_t sys_time = 0; uint32_t sys_time_seconds = 0; +/* This value sets how long a batch of ADC conversions used for temperature measurement is started before the end of the + * longest cycle. Here too the above caveats apply. + * + * This value is in TIM1/TIM3 timer counts. */ +#define ADC_PRETRIGGER 150 /* trigger with about 12us margin to TIM1 CC IRQ */ + +/* Bit timing base value. This is the lowes bit interval used */ +#define PERIOD_BASE 4 + +/* This value is a constant offset added to every bit period to allow for the timer IRQ handler to execute. This is set + * empirically using a debugger and a logic analyzer. */ +#define TIMER_CYCLES_FOR_SPI_TRANSMISSIONS 120 + +/* This is the same as above, but for the reset cycle of the bit period. */ +#define RESET_PERIOD_LENGTH 40 + +/* Defines for brevity */ +#define A TIMER_CYCLES_FOR_SPI_TRANSMISSIONS +#define B PERIOD_BASE + +/* This is a constant offset containing some empirically determined correction values */ +#define C (1 /* reset pulse comp */ - 3 /* analog snafu comp */) + +/* This lookup table maps bit positions to timer period values. This is a lookup table to allow for the compensation for + * non-linear effects of ringing at lower bit durations. + */ +static uint16_t timer_period_lookup[NBITS] = { + /* LSB here */ + A - C + (B<< 0), + A - C + (B<< 1), + A - C + (B<< 2), + A - C + (B<< 3), + A - C + (B<< 4), + A - C + (B<< 5), + A - C + (B<< 6), + A - C + (B<< 7), + A - C + (B<< 8), + A - C + (B<< 9), + A - C + (B<<10), + A - C + (B<<11), + A - C + (B<<12), + A - C + (B<<13), + /* MSB here */ +}; + +/* Don't pollute the global namespace */ +#undef A +#undef B +#undef C + int main(void) { /* Get all the good clocks and PLLs on this thing up and running. We're running from an external 25MHz crystal, * which we're first dividing down by 5 to get 5 MHz, then PLL'ing up by 6 to get 30 MHz as our main system clock. @@ -90,14 +131,14 @@ int main(void) { /* Enable all the periphery we need */ - RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; + RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_DMAEN; RCC->APB2ENR |= RCC_APB2ENR_SPI1EN | RCC_APB2ENR_TIM1EN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_ADCEN; RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; /* Configure all the GPIOs */ GPIOA->MODER |= (3<AFR[0] |= - (1<PSC = 1; /* Prescale by 2, resulting in a 16MHz timer frequency and 62.5ns timer step size. */ /* CH2 - clear/!MR, CH3 - strobe/STCP */ - TIM1->CCMR2 = (6<CCER |= TIM_CCER_CC3E | TIM_CCER_CC3NE | TIM_CCER_CC3P | TIM_CCER_CC3NP; + TIM1->CCMR2 = (6<CCER |= TIM_CCER_CC3E | TIM_CCER_CC3NE | TIM_CCER_CC3P | TIM_CCER_CC3NP | TIM_CCER_CC4E; TIM1->BDTR = TIM_BDTR_MOE | (1<DIER = TIM_DIER_UIE; /* Enable update (overrun) interrupt */ TIM1->ARR = 1; TIM1->CR1 |= TIM_CR1_CEN; + /* Trigger at the end of the longest bit cycle. This means this does not trigger in shorter bit cycles. */ + TIM1->CCR4 = timer_period_lookup[NBITS-1] - ADC_PRETRIGGER; /* Configure Timer 1 update (overrun) interrupt on NVIC. Used only for update (overrun) for strobe timing. */ NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn); @@ -184,7 +228,8 @@ int main(void) { | USART_CR1_RE; USART1->CR3 = USART_CR3_DEM; /* RS485 DE enable (output on RTS) */ // USART1->BRR = 30; - USART1->BRR = 40; // 750000 + //USART1->BRR = 40; // 750000 + USART1->BRR = 60; // 500000 USART1->CR1 |= USART_CR1_UE; /* Configure USART1 interrupt on NVIC. Used only for RX. */ @@ -214,58 +259,13 @@ void do_transpose(void) { for (uint32_t i=0; iRDR; /* This automatically acknowledges the IRQ */ if (data == 0x00) { /* End-of-packet */ - /* Process higher protocol layers on this packet. */ - writep = packet_received(rxpos); + if (cobs_state != COBS_WAIT_SYNC) /* Has a packet been received? */ + /* Process higher protocol layers on this packet. */ + packet_received(rxpos); /* Reset for next packet. */ cobs_state = COBS_WAIT_START; @@ -206,7 +204,7 @@ void USART1_IRQHandler(void) { } /* Write processed payload byte to current receive buffer */ - writep[rxpos++] = data; + rx_buf.byte_data[rxpos++] = data; } } } diff --git a/firmware/serial.h b/firmware/serial.h index 5066c43..94cfd57 100644 --- a/firmware/serial.h +++ b/firmware/serial.h @@ -27,7 +27,6 @@ void send_status_reply(void); /* Internal low-level stuff */ void tx_char(uint8_t c); void send_frame_formatted(uint8_t *buf, int len); -volatile uint8_t *packet_received(int len); /* Error counters for debugging */ extern unsigned int uart_overruns; @@ -38,6 +37,10 @@ union tx_buf_union { struct __attribute__((packed)) { uint8_t firmware_version, hardware_version; + uint8_t nbits; + uint8_t channel_spec; + uint8_t color_spec; + uint16_t nchannels; uint32_t uptime_s, uart_overruns, frame_overruns, @@ -45,6 +48,10 @@ union tx_buf_union { int16_t vcc_mv, temp_celsius; } desc_reply; + struct __attribute__((packed)) { + uint32_t mac; + uint16_t device_type; + } device_type_reply; uint8_t byte_data[0]; }; @@ -57,7 +64,7 @@ union rx_buf_union { * |<----------------NBITS---------------->| |<>|--ignored * | (MSB) brightness data (LSB) | |<>|--ignored */ - struct __attribute__((packed)) { uint32_t framebuf[32]; uint8_t end[0]; } set_fb_rq; + struct __attribute__((packed)) { uint16_t framebuf[32]; uint8_t end[0]; } set_fb_rq; uint8_t byte_data[0]; uint32_t mac_data; }; -- cgit