diff --git a/README.md b/README.md index b498074..6a5df10 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,16 @@ fw for a ch32v203 node w/ w5500 ethernet - SPI DMA only works with [prescalers](https://git.hye.su/mira/ch32-node/src/branch/master/src/spi_dma.c#L140) 8 and 64? - Also, for some reason it needs a ~50ms delay before configuring w5500 when compiled **with** `-O0`, not needed with `-Os`... -Not an interrupt priority issue?: -![LA](notes/2024-10-15-001533_1895x722_scrot.png) +## Diff between SPI w/ and w/o DMA: +### SPI DMA +![SPI_DMA 1](notes/SPI_DMA_no_irq_1.png) +![SPI_DMA 2](notes/SPI_DMA_no_irq_2.png) +### SPI +![SPI 1](notes/SPI_1.png) +![SPI 2](notes/SPI_2.png) +00 09 04 C0 A8 66 01 02 +00 09 04 C0 A8 66 01 02 02 ## ~~previous (DNS Processing)~~ solved by [patching](https://git.hye.su/mira/ch32-node/commit/259d63197e06c1a92b979490d4cd8f0fdb98f8d0#diff-6ba50689ba55dac7cfe3e9b011e594098c931e21) the korean bloatlib (`dns_makequery` in DNS.c) diff --git a/lib/ioLibrary_Driver/W5500/w5500.c b/lib/ioLibrary_Driver/W5500/w5500.c index 68d4cb8..a298953 100644 --- a/lib/ioLibrary_Driver/W5500/w5500.c +++ b/lib/ioLibrary_Driver/W5500/w5500.c @@ -85,7 +85,11 @@ uint8_t WIZCHIP_READ(uint32_t AddrSel) spi_data[2] = (AddrSel & 0x000000FF) >> 0; WIZCHIP.IF.SPI._write_burst(spi_data, 3); } - ret = WIZCHIP.IF.SPI._read_byte(); + if (WIZCHIP.IF.SPI._read_burst) { + WIZCHIP.IF.SPI._read_burst(&ret, 1); + } else { + ret = WIZCHIP.IF.SPI._read_byte(); + } WIZCHIP.CS._deselect(); WIZCHIP_CRITICAL_EXIT(); diff --git a/lib/ioLibrary_Driver/socket.c b/lib/ioLibrary_Driver/socket.c index 412a65d..07995fa 100644 --- a/lib/ioLibrary_Driver/socket.c +++ b/lib/ioLibrary_Driver/socket.c @@ -54,6 +54,7 @@ // //***************************************************************************** #include "socket.h" +#include //M20150401 : Typing Error //#define SOCK_ANY_PORT_NUM 0xC000; @@ -507,6 +508,7 @@ int32_t sendto(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t return SOCKERR_SOCKMODE; } CHECK_SOCKDATA(); + //M20140501 : For avoiding fatal error on memory align mismatched //if(*((uint32_t*)addr) == 0) return SOCKERR_IPINVALID; //{ @@ -518,24 +520,37 @@ int32_t sendto(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t //} // //if(*((uint32_t*)addr) == 0) return SOCKERR_IPINVALID; - if((taddr == 0) && ((getSn_MR(sn)&Sn_MR_MACRAW) != Sn_MR_MACRAW)) return SOCKERR_IPINVALID; - if((port == 0) && ((getSn_MR(sn)&Sn_MR_MACRAW) != Sn_MR_MACRAW)) return SOCKERR_PORTZERO; + if((taddr == 0) && ((getSn_MR(sn)&Sn_MR_MACRAW) != Sn_MR_MACRAW)) { + return SOCKERR_IPINVALID; + } + if((port == 0) && ((getSn_MR(sn)&Sn_MR_MACRAW) != Sn_MR_MACRAW)) { + return SOCKERR_PORTZERO; + } tmp = getSn_SR(sn); //#if ( _WIZCHIP_ < 5200 ) - if((tmp != SOCK_MACRAW) && (tmp != SOCK_UDP) && (tmp != SOCK_IPRAW)) return SOCKERR_SOCKSTATUS; + if((tmp != SOCK_MACRAW) && (tmp != SOCK_UDP) && (tmp != SOCK_IPRAW)) { + return SOCKERR_SOCKSTATUS; + } //#else // if(tmp != SOCK_MACRAW && tmp != SOCK_UDP) return SOCKERR_SOCKSTATUS; //#endif - + setSn_DIPR(sn,addr); setSn_DPORT(sn,port); freesize = getSn_TxMAX(sn); - if (len > freesize) len = freesize; // check size not to exceed MAX size. + if (len > freesize) { + len = freesize; // check size not to exceed MAX size. + } + while(1) { freesize = getSn_TX_FSR(sn); - if(getSn_SR(sn) == SOCK_CLOSED) return SOCKERR_SOCKCLOSED; - if( (sock_io_mode & (1< freesize) ) return SOCK_BUSY; + if(getSn_SR(sn) == SOCK_CLOSED) { + return SOCKERR_SOCKCLOSED; + } + if( (sock_io_mode & (1< freesize) ) { + return SOCK_BUSY; + } if(len <= freesize) break; }; wiz_send_data(sn, buf, len); @@ -558,6 +573,7 @@ int32_t sendto(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t setSn_CR(sn,Sn_CR_SEND); /* wait to process the command... */ while(getSn_CR(sn)); + while(1) { tmp = getSn_IR(sn); @@ -586,6 +602,7 @@ int32_t sendto(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t #endif //M20150409 : Explicit Type Casting //return len; + return (int32_t)len; } diff --git a/notes/SPI_1.png b/notes/SPI_1.png new file mode 100644 index 0000000..454fba4 Binary files /dev/null and b/notes/SPI_1.png differ diff --git a/notes/SPI_2.png b/notes/SPI_2.png new file mode 100644 index 0000000..a842a4c Binary files /dev/null and b/notes/SPI_2.png differ diff --git a/notes/SPI_DMA_no_irq_1.png b/notes/SPI_DMA_no_irq_1.png new file mode 100644 index 0000000..7c0f536 Binary files /dev/null and b/notes/SPI_DMA_no_irq_1.png differ diff --git a/notes/SPI_DMA_no_irq_2.png b/notes/SPI_DMA_no_irq_2.png new file mode 100644 index 0000000..9346e61 Binary files /dev/null and b/notes/SPI_DMA_no_irq_2.png differ diff --git a/src/main.c b/src/main.c index dd6b666..1a15447 100644 --- a/src/main.c +++ b/src/main.c @@ -47,23 +47,23 @@ void message_arrived(MessageData* md) { } } -void print_binary(uint32_t value) { - for (int i = 31; i >= 0; i--) { - DEBUG_PRINT("%d", (value >> i) & 1); - if (i % 4 == 0) printf(" "); // Add space for readability - } - DEBUG_PRINT("\n"); -} +// void print_bin(uint32_t value) { +// for (int i = 31; i >= 0; i--) { +// DEBUG_PRINT("%d", (value >> i) & 1); +// if (i % 4 == 0) printf(" "); +// } +// DEBUG_PRINT("\n"); +// } int main(void) { init_system(); Delay_Ms(55); - uint32_t intsyscr = __get_INTSYSCR(); - DEBUG_PRINT("INTSYSCR Register Configuration:\n"); - DEBUG_PRINT("Hexadecimal: 0x%08X\n", intsyscr); - DEBUG_PRINT("Binary: "); - print_binary(intsyscr); + // uint32_t intsyscr = __get_INTSYSCR(); + // DEBUG_PRINT("INTSYSCR:\n"); + // DEBUG_PRINT("hex: 0x%08X\n", intsyscr); + // DEBUG_PRINT("bin: "); + // print_binary(intsyscr); // DEBUG_PRINT("init_system() done\n"); configure_network(); diff --git a/src/spi_dma.c b/src/spi_dma.c index dda18c8..49ed657 100644 --- a/src/spi_dma.c +++ b/src/spi_dma.c @@ -3,103 +3,11 @@ #include "ch32v003fun.h" #include "debug.h" -volatile transfer_state_t tx_state = IDLE; -volatile transfer_state_t rx_state = IDLE; +#define RX_Channel DMA1_Channel2 +#define TX_Channel DMA1_Channel3 static const uint8_t tx_dummy_byte = 0xFF; -static uint8_t rx_dummy; // Static RX dummy buffer - -static inline void wait_for_transfer_complete(void) { - while (tx_state != TX_DONE || rx_state != RX_DONE); -} - -// static inline void spi_wait_not_busy(void) { -// while ((SPI1->STATR & SPI_STATR_BSY) != 0); -// } - -void set_transfer_states(void) { - tx_state = TRANSMITTING; - rx_state = RECEIVING; -} - -void clear_transfer_states(void) { - tx_state = IDLE; - rx_state = IDLE; -} - -void DMA1_HandleIrq(uint32_t channel_interrupt, - volatile transfer_state_t* state, - transfer_state_t active_state, - transfer_state_t done_state) { - if (DMA1->INTFR & channel_interrupt) { // check if DMA interrupt occurred - DMA1->INTFCR = channel_interrupt; // clear the interrupt flag - if (*state == active_state) { - *state = done_state; - } - } -} -void DMA1_Channel3_IRQHandler(void) __attribute__((interrupt)); -void DMA1_Channel2_IRQHandler(void) __attribute__((interrupt)); - -void DMA1_Channel3_IRQHandler(void) { - DMA1_HandleIrq(DMA1_IT_TC3, &tx_state, TRANSMITTING, TX_DONE); -} - -void DMA1_Channel2_IRQHandler(void) { - DMA1_HandleIrq(DMA1_IT_TC2, &rx_state, RECEIVING, RX_DONE); -} - -void configure_dma(DMA_Channel_TypeDef* tx_channel, uint32_t tx_addr, - DMA_Channel_TypeDef* rx_channel, uint32_t rx_addr, - int rx_circular, uint16_t len) { - // disable DMA channels - tx_channel->CFGR &= ~DMA_CFGR1_EN; - rx_channel->CFGR &= ~DMA_CFGR1_EN; - - // set memory addresses and transfer count - tx_channel->MADDR = tx_addr; - tx_channel->CNTR = len; - rx_channel->MADDR = rx_addr; - rx_channel->CNTR = len; - - // set or clear the circular mode for RX - rx_channel->CFGR = - (rx_channel->CFGR & ~DMA_CFGR1_CIRC) | (rx_circular ? DMA_CFGR1_CIRC : 0); - - // enable DMA channels - tx_channel->CFGR |= DMA_CFGR1_EN; - rx_channel->CFGR |= DMA_CFGR1_EN; -} - -void spidma_read_buffer(uint8_t* buf, uint16_t len) { - set_transfer_states(); - configure_dma(DMA1_Channel3, (uint32_t)&tx_dummy_byte, DMA1_Channel2, - (uint32_t)buf, 0, len); - - wait_for_transfer_complete(); - clear_transfer_states(); -} - -void spidma_write_buffer(uint8_t* buf, uint16_t len) { - set_transfer_states(); - configure_dma(DMA1_Channel3, (uint32_t)buf, DMA1_Channel2, (uint32_t)rx_dummy, - 1, len); - - wait_for_transfer_complete(); - clear_transfer_states(); -} - -uint8_t spi_transfer(uint8_t data) { - while (!(SPI1->STATR & SPI_STATR_TXE)); - SPI1->DATAR = data; - - while (!(SPI1->STATR & SPI_STATR_RXNE)); - return SPI1->DATAR; -} - -uint8_t spi_read_byte() { return spi_transfer(tx_dummy_byte); } - -void spi_write_byte(uint8_t byte) { spi_transfer(byte); } +static uint8_t rx_dummy; void spi_select(void) { GPIOA->BCR = (1 << 4); // Set PA4 (CS) low @@ -109,6 +17,68 @@ void spi_unselect(void) { GPIOA->BSHR = (1 << 4); // Set PA4 (CS) high } +// SPI DMA +void spidma_read_buffer(uint8_t* buf, uint16_t len) { + // tx + TX_Channel->MADDR = (uint32_t)&tx_dummy_byte; + TX_Channel->CNTR = len; + TX_Channel->CFGR &= ~DMA_MemoryInc_Enable; + // rx + RX_Channel->MADDR = (uint32_t)buf; + RX_Channel->CNTR = len; + RX_Channel->CFGR |= DMA_MemoryInc_Enable; + + // enable + RX_Channel->CFGR |= DMA_CFGR1_EN; + TX_Channel->CFGR |= DMA_CFGR1_EN; + + while (!(DMA1->INTFR & DMA1_FLAG_TC2) && !(DMA1->INTFR & DMA1_FLAG_TC3)); + + /** + * In transmission mode, when the DMA has written all the data to be + * transmitted (flag TCIF is set in the DMA_ISR register), the BSY flag can be + * monitored to ensure that the SPI communication is complete. This is + * required to avoid corrupting the last transmission before disabling the SPI + * or entering the Stop mode. The software must first wait until TXE=1 and + * then until BSY=0. + */ + while (!(SPI1->STATR & SPI_STATR_TXE)); + while (SPI1->STATR & SPI_I2S_FLAG_BSY); + + // clear intfr + DMA1->INTFCR |= DMA1_FLAG_TC2 | DMA1_FLAG_TC3; + + RX_Channel->CFGR &= ~DMA_CFGR1_EN; + TX_Channel->CFGR &= ~DMA_CFGR1_EN; +} + +void spidma_write_buffer(uint8_t* buf, uint16_t len) { + // tx + TX_Channel->MADDR = (uint32_t)buf; + TX_Channel->CNTR = len; + TX_Channel->CFGR |= DMA_MemoryInc_Enable; + // rx + RX_Channel->MADDR = (uint32_t)&rx_dummy; + RX_Channel->CNTR = len; + RX_Channel->CFGR &= ~DMA_MemoryInc_Enable; + + // enable + TX_Channel->CFGR |= DMA_CFGR1_EN; + RX_Channel->CFGR |= DMA_CFGR1_EN; + + while (!(DMA1->INTFR & DMA1_FLAG_TC2) && !(DMA1->INTFR & DMA1_FLAG_TC3)); + + // wait for SPI to complete: TXE = 1, then BSY = 0 + while (!(SPI1->STATR & SPI_STATR_TXE)); + while (SPI1->STATR & SPI_I2S_FLAG_BSY); + + // clear intfr + DMA1->INTFCR |= DMA1_FLAG_TC2 | DMA1_FLAG_TC3; + + RX_Channel->CFGR &= ~DMA_CFGR1_EN; + TX_Channel->CFGR &= ~DMA_CFGR1_EN; +} + void init_spidma(void) { // Enable clock for GPIOA and SPI1 RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1; @@ -116,16 +86,16 @@ void init_spidma(void) { RCC->AHBPCENR |= RCC_AHBPeriph_DMA1; // SPI1 Pin Configuration - // CS on PA4, 10MHz Output, open-drain + // CS on PA4, 10MHz Output, push-pull GPIOA->CFGLR &= ~(0xf << (4 * 4)); GPIOA->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 4); // SCK on PA5, 10MHz Output, alt func, push-pull GPIOA->CFGLR &= ~(0xf << (4 * 5)); GPIOA->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 5); - // MOSI on PA7, 10MHz input, floating + // MISO on PA6, 10MHz input, floating GPIOA->CFGLR &= ~(0xf << (4 * 6)); GPIOA->CFGLR |= (GPIO_CNF_IN_FLOATING) << (4 * 6); - // MISO on PA6, 10MHz Output, alt func, push-pull + // MOSI on PA7, 10MHz Output, alt func, push-pull GPIOA->CFGLR &= ~(0xf << (4 * 7)); GPIOA->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 7); @@ -135,9 +105,9 @@ void init_spidma(void) { SPI1->CTLR1 = SPI_Mode_Master | // Master mode SPI_Direction_2Lines_FullDuplex | // Full duplex SPI_DataSize_8b | // 8-bit data frame format - SPI_CPOL_Low | // Clock polarity - SPI_CPHA_1Edge | // Clock phase - SPI_BaudRatePrescaler_64 | // Baud rate prescaler + SPI_CPHA_1Edge | // Clock polarity + SPI_CPOL_Low | // Clock phase + SPI_BaudRatePrescaler_64 | // Baud rate prescaler SPI_NSS_Soft; // Software NSS management // Enable TX and RX DMA @@ -147,22 +117,15 @@ void init_spidma(void) { SPI1->CTLR1 |= SPI_CTLR1_SPE; // Enable SPI // DMA setup - DMA1_Channel3->PADDR = (uint32_t)&SPI1->DATAR; // TX Channel - DMA1_Channel3->CFGR = DMA_M2M_Disable | DMA_Priority_VeryHigh | - DMA_MemoryDataSize_Byte | DMA_PeripheralDataSize_Byte | - DMA_MemoryInc_Enable | DMA_PeripheralInc_Disable | - DMA_Mode_Normal | DMA_DIR_PeripheralDST | DMA_IT_TC; + TX_Channel->PADDR = (uint32_t)&SPI1->DATAR; // TX Channel + TX_Channel->CFGR = DMA_M2M_Disable | DMA_Priority_VeryHigh | + DMA_MemoryDataSize_Byte | DMA_PeripheralDataSize_Byte | + DMA_MemoryInc_Enable | DMA_PeripheralInc_Disable | + DMA_Mode_Normal | DMA_DIR_PeripheralDST; - DMA1_Channel2->PADDR = (uint32_t)&SPI1->DATAR; // RX Channel - DMA1_Channel2->CFGR = DMA_M2M_Disable | DMA_Priority_VeryHigh | - DMA_MemoryDataSize_Byte | DMA_PeripheralDataSize_Byte | - DMA_MemoryInc_Enable | DMA_PeripheralInc_Disable | - DMA_Mode_Normal | DMA_DIR_PeripheralSRC | DMA_IT_TC; - - // NVIC_SetPriority(DMA1_Channel2_IRQn, 0); - // NVIC_SetPriority(DMA1_Channel3_IRQn, 0); - NVIC_SetPriority(DMA1_Channel2_IRQn, 0x20); - NVIC_SetPriority(DMA1_Channel3_IRQn, 0x20); - NVIC_EnableIRQ(DMA1_Channel3_IRQn); - NVIC_EnableIRQ(DMA1_Channel2_IRQn); + RX_Channel->PADDR = (uint32_t)&SPI1->DATAR; // RX Channel + RX_Channel->CFGR = DMA_M2M_Disable | DMA_Priority_VeryHigh | + DMA_MemoryDataSize_Byte | DMA_PeripheralDataSize_Byte | + DMA_MemoryInc_Enable | DMA_PeripheralInc_Disable | + DMA_Mode_Normal | DMA_DIR_PeripheralSRC; } diff --git a/src/systick.c b/src/systick.c index 5e0fab6..ef5ca07 100644 --- a/src/systick.c +++ b/src/systick.c @@ -5,7 +5,7 @@ // ms counter volatile uint32_t systick_millis = 0; -volatile int toggle_state = 0; +// volatile int toggle_state = 0; void init_systick(void) { SysTick->CTLR = 0; @@ -27,12 +27,12 @@ void init_systick(void) { */ void SysTick_Handler(void) __attribute__((interrupt)); void SysTick_Handler(void) { - if (toggle_state) { - GPIOB->BSHR = (1 << 9); // Set PB9 high - } else { - GPIOB->BCR = (1 << 9); // Set PB9 low - } - toggle_state = !toggle_state; + // if (toggle_state) { + // GPIOB->BSHR = (1 << 9); // Set PB9 high + // } else { + // GPIOB->BCR = (1 << 9); // Set PB9 low + // } + // toggle_state = !toggle_state; // Increment the Compare Register for the next trigger // If more than this number of ticks elapse before the trigger is reset, // you may miss your next interrupt trigger diff --git a/src/w5500.c b/src/w5500.c index 60dabbc..4b0b727 100644 --- a/src/w5500.c +++ b/src/w5500.c @@ -58,7 +58,7 @@ void configure_network(void) { // Setup chip select and SPI callbacks reg_wizchip_cs_cbfunc(spi_select, spi_unselect); - reg_wizchip_spi_cbfunc(spi_read_byte, spi_write_byte); + // reg_wizchip_spi_cbfunc(spi_read_byte, spi_write_byte); reg_wizchip_spiburst_cbfunc(spidma_read_buffer, spidma_write_buffer); uint8_t rx_tx_buff_sizes[] = {2, 2, 2, 2, 2, 2, 2, 2}; @@ -76,10 +76,14 @@ void configure_dhcp(void) { callback_ip_conflict); // Attempt to acquire an IP address using DHCP - while (!ip_assigned) { + // retry + uint8_t retries = 0; + + while (!ip_assigned && retries < 30) { DHCP_run(); - Delay_Ms(100); + // Delay_Ms(100); DEBUG_PRINT("DHCP_run()...\n"); + retries++; } if (!ip_assigned) {