DMA channel assignments redone, basic protocol stuff working

This commit is contained in:
jaseg 2017-09-01 15:44:39 +02:00
parent a832816d61
commit 6b40626a1b
3 changed files with 121 additions and 34 deletions

134
fw/main.c
View file

@ -43,15 +43,48 @@ void strobe_leds(void) {
GPIOA->BSRR = GPIO_BSRR_BR_9;
}
static volatile unsigned int sys_time = 0;
volatile unsigned int sys_time = 0;
volatile struct framebuf fb[2] = {0};
volatile struct framebuf *read_fb=fb+0, *write_fb=fb+1;
volatile int led_state = 0;
volatile enum { FB_WRITE, FB_FORMAT, FB_UPDATE } fb_op;
volatile uint8_t rx_buf[sizeof(struct framebuf) + 4 /* crc */];
volatile union {
struct {
uint32_t millifps;
} fps_reply;
} tx_buf;
volatile uint8_t this_addr = 0x05; /* FIXME */
union {
struct {
uint8_t device_id __attribute__((aligned(2)));
};
uint16_t flash_data[0];
} flash_data __attribute__((section ("configflash")));
void write_config(void *target, uint16_t value) {
FLASH->KEYR = 0x45670123;
FLASH->KEYR = 0xCDEF89AB;
FLASH->CR = FLASH_CR_PG;
*(uint16_t *)target = value;
while (FLASH->SR & FLASH_SR_BSY)
;
FLASH->CR = FLASH_CR_LOCK;
}
void erase_config() {
FLASH->KEYR = 0x45670123;
FLASH->KEYR = 0xCDEF89AB;
FLASH->CR = FLASH_CR_PER;
FLASH->AR = (uint32_t)&flash_data;
FLASH->CR = FLASH_CR_STRT;
while (FLASH->SR & FLASH_SR_BSY)
;
FLASH->CR = FLASH_CR_LOCK;
}
#define LED_COMM 0x0001
#define LED_ERROR 0x0002
#define LED_ID 0x0004
@ -66,6 +99,10 @@ inline unsigned int stk_end(unsigned int start) {
return (start - SysTick->VAL) & 0xffffff;
}
inline unsigned int stk_microseconds() {
return sys_time*1000 + (1000 - (SysTick->VAL / (SystemCoreClock/1000000)));
}
enum {
SPI_AUX,
SPI_WORD0,
@ -117,15 +154,16 @@ void SPI1_IRQHandler() {
spi_state ++;
}
static volatile int frame_duration;
uint8_t segment_map[8] = {5, 7, 6, 4, 1, 3, 0, 2};
static volatile int frame_duration_us;
/* returns new bit time in cycles */
int shift_data() {
static int active_segment = 0;
static unsigned int active_bit = 0;
static int last_frame_sys_time;
static unsigned int last_frame_time;
/* Note: On boot, multiplexing will start with bit 1 due to the next few lines. This is perfectly ok. */
int rv = 1<<active_bit;
active_bit++;
if (active_bit == nbits) {
active_bit = 0;
@ -134,9 +172,9 @@ int shift_data() {
if (active_segment == nsegments) {
active_segment = 0;
int time = sys_time;
frame_duration = time - last_frame_sys_time;
last_frame_sys_time = sys_time;
int time = stk_microseconds();
frame_duration_us = time - last_frame_time;
last_frame_time = time;
if (fb_op == FB_UPDATE) {
volatile struct framebuf *tmp = read_fb;
read_fb = write_fb;
@ -149,7 +187,7 @@ int shift_data() {
spi_state = SPI_AUX;
SPI1->DR = (read_fb->brightness ? SR_ILED_HIGH : SR_ILED_LOW)
| (led_state<<1)
| (0xff00 ^ (0x100<<active_segment));
| (0xff00 ^ (0x100<<segment_map[active_segment]));
} else {
spi_word = read_fb->data[active_bit*frame_size_words + active_segment];
spi_state = SPI_WORD0;
@ -157,7 +195,7 @@ int shift_data() {
}
SPI1->CR2 |= SPI_CR2_TXEIE;
return rv;
return 1<<active_bit;
}
void cfg_timer3() {
@ -198,8 +236,16 @@ enum Command {
CMD_SET_ADDR,
CMD_SET_FB,
CMD_GET_DESC,
CMD_GET_FRAMERATE,
CMD_ERASE_CONFIG,
};
enum {
PROT_ADDR,
PROT_CMD,
PROT_
} protocol_state = PROT_ADDR;
int gaddr;
void USART1_IRQHandler() {
gaddr = USART1->RDR;
@ -214,11 +260,16 @@ void USART1_IRQHandler() {
}
/* Are we addressed? */
if (addr != this_addr) {
asm("bkpt");
/* We are not. Mute USART until next idle condition */
USART1->RQR |= USART_RQR_MMRQ;
} else {
/* We are. Switch by command. */
switch (cmd) {
case CMD_PING:
USART1->TDR = 42;
USART1->RQR |= USART_RQR_MMRQ;
break;
case CMD_SET_FB:
/* Are we ready to process new frame data? */
if (fb_op != FB_WRITE) {
@ -232,6 +283,13 @@ void USART1_IRQHandler() {
DMA1_Channel3->CCR |= DMA_CCR_EN;
USART1->CR3 |= USART_CR3_DMAR;
break;
case CMD_GET_FRAMERATE:
tx_buf.fps_reply.millifps = frame_duration_us > 0 ? 1000000000 / frame_duration_us : 0;
DMA1_Channel4->CNDTR = sizeof(tx_buf.fps_reply);
USART1->ICR |= USART_ICR_TCCF; /* FIXME: (1) is this necessary? (2) where should this be done? */
DMA1_Channel4->CCR |= DMA_CCR_EN;
USART1->RQR |= USART_RQR_MMRQ;
break;
}
}
errout:
@ -252,6 +310,11 @@ void DMA1_Channel2_3_IRQHandler() {
USART1->CR1 |= USART_CR1_RXNEIE;
}
void DMA1_Channel4_5_IRQHandler() {
DMA1->IFCR |= DMA_IFCR_CGIF4;
DMA1_Channel4->CCR &= ~DMA_CCR_EN_Msk;
}
void uart_config(void) {
USART1->CR1 = /* 8-bit -> M1, M0 clear */
/* RTOIE clear */
@ -267,16 +330,17 @@ void uart_config(void) {
| USART_CR1_TE
| USART_CR1_RE;
//USART1->CR2 = USART_CR2_RTOEN; /* Timeout enable */
USART1->CR3 = USART_CR3_DEM; /* RS485 DE enable (output on RTS) */
USART1->CR3 = USART_CR3_DEM /* RS485 DE enable (output on RTS) */
| USART_CR3_DMAT;
int usartdiv = 25;
USART1->BRR = usartdiv;
USART1->CR1 |= USART_CR1_UE;
/* Configure DMA for USART frame data reception */
/* Configure DMA 1 / Channel 3 for USART frame data reception: USART1->RDR -> rx_buf */
DMA1_Channel3->CPAR = (unsigned int)&USART1->RDR;
DMA1_Channel3->CMAR = (unsigned int)rx_buf;
DMA1_Channel3->CNDTR = sizeof(rx_buf);
DMA1_Channel3->CCR = (0<<DMA_CCR_PL_Pos);
DMA1_Channel3->CCR = (1<<DMA_CCR_PL_Pos);
DMA1_Channel3->CCR |=
(0<<DMA_CCR_MSIZE_Pos) /* 8 bit */
| (0<<DMA_CCR_PSIZE_Pos) /* 8 bit */
@ -284,20 +348,36 @@ void uart_config(void) {
| DMA_CCR_TCIE
| DMA_CCR_CIRC;
DMA1_Channel4->CPAR = (unsigned int)&CRC->DR;
DMA1_Channel4->CMAR = (unsigned int)rx_buf;
DMA1_Channel4->CCR = (0<<DMA_CCR_PL_Pos);
DMA1_Channel4->CCR |=
/* Configure DMA 1 / Channel 5 for USART frame data CRC check: rx_buf -> CRC->DR */
DMA1_Channel5->CPAR = (unsigned int)&CRC->DR;
DMA1_Channel5->CMAR = (unsigned int)rx_buf;
DMA1_Channel5->CCR = (0<<DMA_CCR_PL_Pos);
DMA1_Channel5->CCR |=
DMA_CCR_MEM2MEM /* Software trigger (precludes CIRC) */
| DMA_CCR_DIR /* Read from memory */
| (0<<DMA_CCR_MSIZE_Pos) /* 8 bit */
| (0<<DMA_CCR_PSIZE_Pos) /* 8 bit */
| DMA_CCR_MINC;
/* Configure DMA 1 / Channel 4 for USART reply transmission */
DMA1_Channel4->CPAR = (unsigned int)&USART1->TDR;
DMA1_Channel4->CMAR = (unsigned int)&tx_buf;
DMA1_Channel4->CCR = (0<<DMA_CCR_PL_Pos);
DMA1_Channel4->CCR |=
DMA_CCR_DIR /* Read from memory */
| (0<<DMA_CCR_MSIZE_Pos) /* 8 bit */
| (0<<DMA_CCR_PSIZE_Pos) /* 8 bit */
| DMA_CCR_MINC
| DMA_CCR_TCIE;
SYSCFG->CFGR1 |= SYSCFG_CFGR1_USART1TX_DMA_RMP;
NVIC_EnableIRQ(USART1_IRQn);
NVIC_SetPriority(USART1_IRQn, 4);
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
NVIC_SetPriority(DMA1_Channel2_3_IRQn, 3);
NVIC_EnableIRQ(DMA1_Channel4_5_IRQn);
NVIC_SetPriority(DMA1_Channel4_5_IRQn, 5);
}
int errcnt = 0;
@ -313,10 +393,8 @@ int main(void) {
RCC->CFGR |= (2<<RCC_CFGR_SW_Pos);
SystemCoreClockUpdate();
LL_Init1msTick(SystemCoreClock);
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_DMAEN | RCC_AHBENR_CRCEN;
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN | RCC_APB2ENR_USART1EN;
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_SYSCFGEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
GPIOA->MODER |=
@ -365,31 +443,27 @@ int main(void) {
SysTick_Config(SystemCoreClock/1000); /* 1ms interval */
uart_config();
uint8_t i=0;
int last_sys_time=0;
while (42) {
led_state = (sys_time>>8)&7;
last_sys_time = sys_time;
if (fb_op == FB_FORMAT) {
CRC->CR |= CRC_CR_RESET;
DMA1_Channel4->CNDTR = sizeof(struct framebuf);
DMA1_Channel4->CCR |= DMA_CCR_EN;
DMA1_Channel5->CNDTR = sizeof(struct framebuf);
DMA1_Channel5->CCR |= DMA_CCR_EN;
transpose_data(rx_buf, write_fb);
while (!(DMA1->ISR & DMA_ISR_TCIF4))
;
DMA1->IFCR |= DMA_IFCR_CGIF4;
DMA1_Channel4->CCR &= ~DMA_CCR_EN_Msk;
DMA1_Channel5->CCR &= ~DMA_CCR_EN_Msk;
if (CRC->DR != *(uint32_t *)(rx_buf+sizeof(struct framebuf))) {
fb_op = FB_WRITE;
errcnt++;
} else {
fb_op = FB_UPDATE;
while (fb_op == FB_UPDATE)
;
}
fb_op = FB_UPDATE;
while (fb_op == FB_UPDATE)
;
}
}
}

View file

@ -2,7 +2,8 @@
ENTRY(Reset_Handler)
MEMORY {
FLASH (rx): ORIGIN = 0x08000000, LENGTH = 16K
FLASH (rx): ORIGIN = 0x08000000, LENGTH = 14K
CONFIGFLASH (rw): ORIGIN = 0x08003800, LENGTH = 2K
RAM (xrw): ORIGIN = 0x20000000, LENGTH = 4K
}
@ -31,12 +32,18 @@ SECTIONS {
/* Necessary KEEP sections (see http://sourceware.org/ml/newlib/2005/msg00255.html) */
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .;
/* This is used by the startup in order to initialize the .data section */
_sidata = _etext;
} >FLASH
.configflash : {
. = ALIGN(2048);
*(.configdata)
_econfig = .;
} >CONFIGFLASH
/* This is the initialized data section
The program executes knowing that the data is in the RAM

View file

@ -4,6 +4,12 @@
#include "transpose.h"
uint8_t digit_map[33] = {
0, 1, 2, 3, 28,29,30,31,
4, 5, 6, 7, 24,25,26,27,
8, 9,10,11, 20,21,22,23,
12,13,14,15, 16,17,18,19
};
void transpose_data(volatile uint8_t *rx_buf, volatile struct framebuf *out_fb) {
memset((uint8_t *)out_fb, 0, sizeof(*out_fb));
struct data_format *rxp = (struct data_format *)rx_buf;
@ -15,7 +21,7 @@ void transpose_data(volatile uint8_t *rx_buf, volatile struct framebuf *out_fb)
uint32_t acc = 0;
uint8_t *inp = start_inp++;
for (int digit=0; digit<32; digit++) {
acc |= (*inp & bit_mask) >> bit << digit;
acc |= (*inp & bit_mask) >> bit << digit_map[digit];
inp += sizeof(struct data_format);
}
*outp = acc;
@ -28,7 +34,7 @@ void transpose_data(volatile uint8_t *rx_buf, volatile struct framebuf *out_fb)
uint32_t mask = 1 << bit << (seg*2);
uint32_t acc = 0;
for (int digit=0; digit<32; digit++) {
acc |= (*inp & mask) >> bit >> seg << digit;
acc |= (*inp & mask) >> bit >> (seg*2) << digit_map[digit];
inp += sizeof(struct data_format)/sizeof(uint16_t);
}
frame_data[seg] = acc;