X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fstmf0%2Fao_spi_stm.c;h=5e76d6c3946c31ff534a6006b76d3987d7908bbf;hb=eaf2ee0f498b519d64e1664a2b8c66c52ac1497c;hp=55bf59d2f6d6dd4f61b36d56ddc461ba9c76808c;hpb=9f9d77b6d025d8285e362e53a8f728ec47adb234;p=fw%2Faltos diff --git a/src/stmf0/ao_spi_stm.c b/src/stmf0/ao_spi_stm.c index 55bf59d2..5e76d6c3 100644 --- a/src/stmf0/ao_spi_stm.c +++ b/src/stmf0/ao_spi_stm.c @@ -3,7 +3,8 @@ * * 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. + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of @@ -41,8 +42,6 @@ static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = { static uint8_t spi_dev_null; - - #define SPI_CR2 ((0 << STM_SPI_CR2_LDMA_TX) | \ (0 << STM_SPI_CR2_LDMA_RX) | \ (1 << STM_SPI_CR2_FRXTH) | \ @@ -62,12 +61,86 @@ static uint8_t spi_dev_null; (0 << STM_SPI_CR2_TXDMAEN) | \ (0 << STM_SPI_CR2_RXDMAEN)) +#if DEBUG +static struct { + uint8_t task; + uint8_t which; + AO_TICK_TYPE tick; + uint16_t len; +} spi_tasks[64]; +static uint8_t spi_task_index; + +static void +validate_spi(struct stm_spi *stm_spi, int which, uint16_t len) +{ + uint32_t sr = stm_spi->sr; + + if (stm_spi != &stm_spi2) + return; + spi_tasks[spi_task_index].task = ao_cur_task ? ao_cur_task->task_id : 0; + spi_tasks[spi_task_index].which = which; + spi_tasks[spi_task_index].tick = ao_time(); + spi_tasks[spi_task_index].len = len; + spi_task_index = (spi_task_index + 1) & (63); + if (sr & (1 << STM_SPI_SR_FRE)) + ao_panic(0x40 | 1); + if (sr & (1 << STM_SPI_SR_BSY)) + ao_panic(0x40 | 2); + if (sr & (1 << STM_SPI_SR_OVR)) + ao_panic(0x40 | 3); + if (sr & (1 << STM_SPI_SR_MODF)) + ao_panic(0x40 | 4); + if (sr & (1 << STM_SPI_SR_UDR)) + ao_panic(0x40 | 5); + if ((sr & (1 << STM_SPI_SR_TXE)) == 0) + ao_panic(0x40 | 6); + if (sr & (1 << STM_SPI_SR_RXNE)) + ao_panic(0x40 | 7); + if (which != 5 && which != 6 && which != 13) + if (ao_cur_task->task_id != ao_spi_mutex[1]) + ao_panic(0x40 | 8); +} +#else +#define validate_spi(stm_spi, which, len) do { (void) (which); (void) (len); } while (0) +#endif + +static void +ao_spi_run(uint8_t id, uint8_t which, uint16_t len) +{ + struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi; + uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index; + uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index; + + validate_spi(stm_spi, which, len); + + stm_spi->cr2 = SPI_CR2_DMA; + + ao_dma_start(miso_dma_index); + ao_dma_start(mosi_dma_index); + + ao_arch_critical( + while (!ao_dma_done[miso_dma_index]) + ao_sleep(&ao_dma_done[miso_dma_index]); + ); + + while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0); + while (stm_spi->sr & (1 << STM_SPI_SR_BSY)); + + validate_spi(stm_spi, which+1, len); + + stm_spi->cr2 = 0; + + ao_dma_done_transfer(mosi_dma_index); + ao_dma_done_transfer(miso_dma_index); +} + void ao_spi_send(const void *block, uint16_t len, uint8_t spi_index) { - struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi; - uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index; - uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index; + uint8_t id = AO_SPI_INDEX(spi_index); + struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi; + uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index; + uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index; /* Set up the transmit DMA to deliver data */ ao_dma_set_transfer(mosi_dma_index, @@ -84,9 +157,6 @@ ao_spi_send(const void *block, uint16_t len, uint8_t spi_index) (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) | (0 << STM_DMA_CCR_TCIE)); - /* Clear RXNE */ - (void) stm_spi->dr; - /* Set up the receive DMA -- when this is done, we know the SPI unit * is idle. Without this, we'd have to poll waiting for the BSY bit to * be cleared @@ -105,24 +175,16 @@ ao_spi_send(const void *block, uint16_t len, uint8_t spi_index) (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) | (1 << STM_DMA_CCR_TCIE)); - stm_spi->cr2 = SPI_CR2_DMA; - - ao_dma_start(miso_dma_index); - ao_dma_start(mosi_dma_index); - ao_arch_critical( - while (!ao_dma_done[miso_dma_index]) - ao_sleep(&ao_dma_done[miso_dma_index]); - ); - ao_dma_done_transfer(mosi_dma_index); - ao_dma_done_transfer(miso_dma_index); + ao_spi_run(id, 1, len); } void ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index) { - struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi; - uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index; - uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index; + uint8_t id = AO_SPI_INDEX(spi_index); + struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi; + uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index; + uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index; /* Set up the transmit DMA to deliver data */ ao_dma_set_transfer(mosi_dma_index, @@ -139,9 +201,6 @@ ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index) (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) | (0 << STM_DMA_CCR_TCIE)); - /* Clear RXNE */ - (void) stm_spi->dr; - /* Set up the receive DMA -- when this is done, we know the SPI unit * is idle. Without this, we'd have to poll waiting for the BSY bit to * be cleared @@ -160,40 +219,67 @@ ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index) (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) | (1 << STM_DMA_CCR_TCIE)); - stm_spi->cr2 = SPI_CR2_DMA; - ao_dma_start(miso_dma_index); - ao_dma_start(mosi_dma_index); - ao_arch_critical( - while (!ao_dma_done[miso_dma_index]) - ao_sleep(&ao_dma_done[miso_dma_index]); - ); - ao_dma_done_transfer(mosi_dma_index); - ao_dma_done_transfer(miso_dma_index); + ao_spi_run(id, 3, len); } void -ao_spi_send_sync(void *block, uint16_t len, uint8_t spi_index) +ao_spi_start_bytes(uint8_t spi_index) { - uint8_t *b = block; - struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi; + uint8_t id = AO_SPI_INDEX(spi_index); + struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi; stm_spi->cr2 = SPI_CR2_SYNC; + validate_spi(stm_spi, 5, 0xffff); +} - /* Clear RXNE */ +void +ao_spi_stop_bytes(uint8_t spi_index) +{ + uint8_t id = AO_SPI_INDEX(spi_index); + struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi; + + while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0) + ; + while (stm_spi->sr & (1 << STM_SPI_SR_BSY)) + ; + /* Clear the OVR flag */ (void) stm_spi->dr; + (void) stm_spi->sr; + validate_spi(stm_spi, 6, 0xffff); + stm_spi->cr2 = 0; +} + +void +ao_spi_send_sync(const void *block, uint16_t len, uint8_t spi_index) +{ + uint8_t id = AO_SPI_INDEX(spi_index); + const uint8_t *b = block; + struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi; + stm_spi->cr2 = SPI_CR2_SYNC; + + validate_spi(stm_spi, 7, len); while (len--) { while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE))); stm_spi->dr = *b++; } + while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0) + ; + while (stm_spi->sr & (1 << STM_SPI_SR_BSY)) + ; + /* Clear the OVR flag */ + (void) stm_spi->dr; + (void) stm_spi->sr; + validate_spi(stm_spi, 8, len); } void ao_spi_recv(void *block, uint16_t len, uint8_t spi_index) { - struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi; - uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index; - uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index; + uint8_t id = AO_SPI_INDEX(spi_index); + struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi; + uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index; + uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index; spi_dev_null = 0xff; @@ -212,9 +298,6 @@ ao_spi_recv(void *block, uint16_t len, uint8_t spi_index) (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) | (0 << STM_DMA_CCR_TCIE)); - /* Clear RXNE */ - (void) stm_spi->dr; - /* Set up the receive DMA to capture data */ ao_dma_set_transfer(miso_dma_index, &stm_spi->dr, @@ -230,26 +313,16 @@ ao_spi_recv(void *block, uint16_t len, uint8_t spi_index) (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) | (1 << STM_DMA_CCR_TCIE)); - stm_spi->cr2 = SPI_CR2_DMA; - ao_dma_start(miso_dma_index); - ao_dma_start(mosi_dma_index); - - /* Wait until the SPI unit is done */ - ao_arch_critical( - while (!ao_dma_done[miso_dma_index]) - ao_sleep(&ao_dma_done[miso_dma_index]); - ); - - ao_dma_done_transfer(mosi_dma_index); - ao_dma_done_transfer(miso_dma_index); + ao_spi_run(id, 9, len); } void ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index) { - struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi; - uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index; - uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index; + uint8_t id = AO_SPI_INDEX(spi_index); + struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi; + uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index; + uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index; /* Set up transmit DMA to send data */ ao_dma_set_transfer(mosi_dma_index, @@ -266,9 +339,6 @@ ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index) (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) | (0 << STM_DMA_CCR_TCIE)); - /* Clear RXNE */ - (void) stm_spi->dr; - /* Set up the receive DMA to capture data */ ao_dma_set_transfer(miso_dma_index, &stm_spi->dr, @@ -284,18 +354,7 @@ ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index) (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) | (1 << STM_DMA_CCR_TCIE)); - stm_spi->cr2 = SPI_CR2_DMA; - ao_dma_start(miso_dma_index); - ao_dma_start(mosi_dma_index); - - /* Wait until the SPI unit is done */ - ao_arch_critical( - while (!ao_dma_done[miso_dma_index]) - ao_sleep(&ao_dma_done[miso_dma_index]); - ); - - ao_dma_done_transfer(mosi_dma_index); - ao_dma_done_transfer(miso_dma_index); + ao_spi_run(id, 11, len); } static void @@ -303,32 +362,24 @@ ao_spi_disable_index(uint8_t spi_index) { /* Disable current config */ - switch (AO_SPI_INDEX(spi_index)) { - case STM_SPI_INDEX(1): - switch (spi_index) { - case AO_SPI_1_PA5_PA6_PA7: - stm_gpio_set(&stm_gpioa, 5, 1); - stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT); - stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT); - stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT); - break; - case AO_SPI_1_PB3_PB4_PB5: - stm_gpio_set(&stm_gpiob, 3, 1); - stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT); - stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT); - stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT); - break; - } + switch (spi_index) { + case AO_SPI_1_PA5_PA6_PA7: + stm_gpio_set(&stm_gpioa, 5, 1); + stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT); + stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT); + stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT); break; - case STM_SPI_INDEX(2): - switch (spi_index) { - case AO_SPI_2_PB13_PB14_PB15: - stm_gpio_set(&stm_gpiob, 13, 1); - stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT); - stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT); - stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT); - break; - } + case AO_SPI_1_PB3_PB4_PB5: + stm_gpio_set(&stm_gpiob, 3, 1); + stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT); + stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT); + stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT); + break; + case AO_SPI_2_PB13_PB14_PB15: + stm_gpio_set(&stm_gpiob, 13, 1); + stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT); + stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT); + stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT); break; } } @@ -336,29 +387,21 @@ ao_spi_disable_index(uint8_t spi_index) static void ao_spi_enable_index(uint8_t spi_index) { - switch (AO_SPI_INDEX(spi_index)) { - case STM_SPI_INDEX(1): - switch (spi_index) { - case AO_SPI_1_PA5_PA6_PA7: - stm_afr_set(&stm_gpioa, 5, STM_AFR_AF0); - stm_afr_set(&stm_gpioa, 6, STM_AFR_AF0); - stm_afr_set(&stm_gpioa, 7, STM_AFR_AF0); - break; - case AO_SPI_1_PB3_PB4_PB5: - stm_afr_set(&stm_gpiob, 3, STM_AFR_AF0); - stm_afr_set(&stm_gpiob, 4, STM_AFR_AF0); - stm_afr_set(&stm_gpiob, 5, STM_AFR_AF0); - break; - } + switch (spi_index) { + case AO_SPI_1_PA5_PA6_PA7: + stm_afr_set(&stm_gpioa, 5, STM_AFR_AF0); + stm_afr_set(&stm_gpioa, 6, STM_AFR_AF0); + stm_afr_set(&stm_gpioa, 7, STM_AFR_AF0); break; - case STM_SPI_INDEX(2): - switch (spi_index) { - case AO_SPI_2_PB13_PB14_PB15: - stm_afr_set(&stm_gpiob, 13, STM_AFR_AF0); - stm_afr_set(&stm_gpiob, 14, STM_AFR_AF0); - stm_afr_set(&stm_gpiob, 15, STM_AFR_AF0); - break; - } + case AO_SPI_1_PB3_PB4_PB5: + stm_afr_set(&stm_gpiob, 3, STM_AFR_AF0); + stm_afr_set(&stm_gpiob, 4, STM_AFR_AF0); + stm_afr_set(&stm_gpiob, 5, STM_AFR_AF0); + break; + case AO_SPI_2_PB13_PB14_PB15: + stm_afr_set(&stm_gpiob, 13, STM_AFR_AF0); + stm_afr_set(&stm_gpiob, 14, STM_AFR_AF0); + stm_afr_set(&stm_gpiob, 15, STM_AFR_AF0); break; } } @@ -369,6 +412,20 @@ ao_spi_config(uint8_t spi_index, uint32_t speed) uint8_t id = AO_SPI_INDEX(spi_index); struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi; + if (spi_index != ao_spi_index[id]) { + + /* Disable old config + */ + ao_spi_disable_index(ao_spi_index[id]); + + /* Enable new config + */ + ao_spi_enable_index(spi_index); + + /* Remember current config + */ + ao_spi_index[id] = spi_index; + } stm_spi->cr2 = SPI_CR2; stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) | /* Three wire mode */ (0 << STM_SPI_CR1_BIDIOE) | @@ -384,21 +441,6 @@ ao_spi_config(uint8_t spi_index, uint32_t speed) (1 << STM_SPI_CR1_MSTR) | (0 << STM_SPI_CR1_CPOL) | /* Format 0 */ (0 << STM_SPI_CR1_CPHA)); - - if (spi_index != ao_spi_index[id]) { - - /* Disable old config - */ - ao_spi_disable_index(ao_spi_index[id]); - - /* Enable new config - */ - ao_spi_enable_index(spi_index); - - /* Remember current config - */ - ao_spi_index[id] = spi_index; - } } uint8_t @@ -439,20 +481,73 @@ ao_spi_channel_init(uint8_t spi_index) ao_spi_disable_index(spi_index); stm_spi->cr1 = 0; - (void) stm_spi->sr; stm_spi->cr2 = SPI_CR2_SYNC; + + /* Clear any pending data and error flags */ + (void) stm_spi->dr; + (void) stm_spi->sr; } +#if DEBUG +void +ao_spi_dump_cmd(void) +{ + int s; + + for (s = 0; s < 64; s++) { + int i = (spi_task_index + s) & 63; + if (spi_tasks[i].which) { + int t; + const char *name = "(none)"; + for (t = 0; t < ao_num_tasks; t++) + if (ao_tasks[t]->task_id == spi_tasks[i].task) { + name = ao_tasks[t]->name; + break; + } + printf("%2d: %5d task %2d which %2d len %5d %s\n", + s, + spi_tasks[i].tick, + spi_tasks[i].task, + spi_tasks[i].which, + spi_tasks[i].len, + name); + } + } + for (s = 0; s < STM_NUM_SPI; s++) { + struct stm_spi *spi = ao_spi_stm_info[s].stm_spi; + + printf("%1d: mutex %2d index %3d miso dma %3d mosi dma %3d", + s, ao_spi_mutex[s], ao_spi_index[s], + ao_spi_stm_info[s].miso_dma_index, + ao_spi_stm_info[s].mosi_dma_index); + printf(" cr1 %04x cr2 %02x sr %03x\n", + spi->cr1, spi->cr2, spi->sr); + } + +} + +static const struct ao_cmds ao_spi_cmds[] = { + { ao_spi_dump_cmd, "S\0Dump SPI status" }, + { 0, NULL } +}; +#endif + void ao_spi_init(void) { #if HAS_SPI_1 +#ifndef SPI_1_PA5_PA6_PA7 +#error SPI_1_PA5_PA6_PA7 undefined +#endif # if SPI_1_PA5_PA6_PA7 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR); stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR); stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR); # endif +# ifndef SPI_1_PB3_PB4_PB5 +# error SPI_1_PB3_PB4_PB5 undefined +# endif # if SPI_1_PB3_PB4_PB5 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN); stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR); @@ -475,4 +570,7 @@ ao_spi_init(void) ao_spi_index[1] = AO_SPI_CONFIG_NONE; ao_spi_channel_init(STM_SPI_INDEX(2)); #endif +#if DEBUG + ao_cmd_register(&ao_spi_cmds[0]); +#endif }