fix: spi dma

Squashed commit of the following:

commit f0df85e2d18ff36b04443ddb23e645cbbd5bfa58
Author: kuwoyuki <kuwoyuki@cock.li>
Date:   Wed Oct 16 01:36:26 2024 +0600

    fix: SPI DMA

    wait for SPI TXE and BSY flags, also fix korean lib

commit a16b9f769807a78803ba1d7cd10a4a4843827bb2
Author: kuwoyuki <kuwoyuki@cock.li>
Date:   Tue Oct 15 21:09:59 2024 +0600

    moar log

commit 0c457e17ffb956cb5fbbc40865e62f8acf8f2eea
Author: kuwoyuki <kuwoyuki@cock.li>
Date:   Tue Oct 15 14:09:31 2024 +0600

    _

commit a0b6820bc1312e429d04bf0bb39bc2a8b234cfc5
Author: kuwoyuki <kuwoyuki@cock.li>
Date:   Tue Oct 15 13:55:24 2024 +0600

    rewrite w/o interrupts

commit 83c2ab75b326be098bc15698d77ab650b14613e0
Author: kuwoyuki <kuwoyuki@cock.li>
Date:   Tue Oct 15 13:01:41 2024 +0600

    dma config

commit d871fef77d7c1838ac84f02a499f5555f78bc9ce
Author: kuwoyuki <kuwoyuki@cock.li>
Date:   Tue Oct 15 04:47:23 2024 +0600

    more dma
This commit is contained in:
2024-10-16 01:37:31 +06:00
parent 74bc0d25b7
commit 40f1cab745
11 changed files with 145 additions and 150 deletions

View File

@@ -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)

View File

@@ -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();

View File

@@ -54,6 +54,7 @@
//
//*****************************************************************************
#include "socket.h"
#include <stdio.h>
//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<<sn)) && (len > freesize) ) return SOCK_BUSY;
if(getSn_SR(sn) == SOCK_CLOSED) {
return SOCKERR_SOCKCLOSED;
}
if( (sock_io_mode & (1<<sn)) && (len > 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;
}

BIN
notes/SPI_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

BIN
notes/SPI_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

BIN
notes/SPI_DMA_no_irq_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

BIN
notes/SPI_DMA_no_irq_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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) {