feat: SPI DMA
Squashed commit of the following: commit c3e1f696b4fbafb6dd30c6934e4c7c181562e055 Author: kuwoyuki <kuwoyuki@cock.li> Date: Sat Oct 12 20:43:12 2024 +0600 chore: spi dma commit d1e7df60be3e06ed85ce8639516e299085d3c72b Author: kuwoyuki <kuwoyuki@cock.li> Date: Sat Oct 12 15:14:11 2024 +0600 static dummies commit 81682428b471f825e3350e37aa74c373b46d4fef Author: kuwoyuki <kuwoyuki@cock.li> Date: Sat Oct 12 14:45:39 2024 +0600 dma works? commit 150c97a4b566712a502d8a2861a2dc0864324d61 Author: kuwoyuki <kuwoyuki@cock.li> Date: Sat Oct 12 02:07:39 2024 +0600 dma?
This commit is contained in:
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -7,6 +7,7 @@
|
||||
"wizchip_conf.h": "c",
|
||||
"socket.h": "c",
|
||||
"type_traits": "c",
|
||||
"compare": "c"
|
||||
"compare": "c",
|
||||
"uart.h": "c"
|
||||
}
|
||||
}
|
||||
9
include/gpio.h
Normal file
9
include/gpio.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef GPIO_H
|
||||
#define GPIO_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Function prototype for initializing GPIO
|
||||
void init_gpio(void);
|
||||
|
||||
#endif // GPIO_H
|
||||
35
include/spi_dma.h
Normal file
35
include/spi_dma.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef SPI_DMA_H
|
||||
#define SPI_DMA_H
|
||||
|
||||
#include "ch32v003fun.h"
|
||||
|
||||
typedef enum {
|
||||
IDLE,
|
||||
TRANSMITTING,
|
||||
RECEIVING,
|
||||
TX_DONE,
|
||||
RX_DONE
|
||||
} transfer_state_t;
|
||||
|
||||
// SPI DMA initialization function
|
||||
void init_spidma(void);
|
||||
|
||||
// SPI DMA buffer read
|
||||
void spidma_read_buffer(uint8_t *buf, uint16_t len);
|
||||
|
||||
// SPI DMA buffer write
|
||||
void spidma_write_buffer(uint8_t *buf, uint16_t len);
|
||||
|
||||
// SPI (non-DMA) byte read
|
||||
uint8_t spi_read_byte();
|
||||
|
||||
// SPI (non-DMA) byte write
|
||||
void spi_write_byte(uint8_t byte);
|
||||
|
||||
// activate CS
|
||||
void spi_select(void);
|
||||
|
||||
// deactivate CS
|
||||
void spi_unselect(void);
|
||||
|
||||
#endif // SPI_DMA_H
|
||||
@@ -12,6 +12,6 @@
|
||||
(UART_BAUD_RATE)) // USART1
|
||||
|
||||
// Function prototypes
|
||||
void setup_uart(int uart_brr);
|
||||
void init_uart(int uart_brr);
|
||||
|
||||
#endif // UART_H
|
||||
|
||||
@@ -4,21 +4,27 @@
|
||||
#include <stdint.h>
|
||||
|
||||
// Sets the CS pin low
|
||||
void W5500_Select(void);
|
||||
void w5500_select(void);
|
||||
|
||||
// Sets the CS pin high
|
||||
void W5500_Unselect(void);
|
||||
void w5500_unselect(void);
|
||||
|
||||
// Reads a byte via SPI
|
||||
uint8_t W5500_ReadByte(void);
|
||||
uint8_t w5500_read_byte(void);
|
||||
|
||||
// Writes a byte via SPI
|
||||
void W5500_WriteByte(uint8_t byte);
|
||||
void w5500_write_byte(uint8_t byte);
|
||||
|
||||
// Reads multiple bytes via SPI
|
||||
void W5500_ReadBuff(uint8_t* buff, uint16_t len);
|
||||
void w5500_read_buffer(uint8_t* buff, uint16_t len);
|
||||
|
||||
// Writes multiple bytes via SPI
|
||||
void W5500_WriteBuff(uint8_t* buff, uint16_t len);
|
||||
void w5500_write_buffer(uint8_t* buff, uint16_t len);
|
||||
|
||||
// Initializes the W5500 chip
|
||||
void configure_network(void);
|
||||
|
||||
// resolves a domain name
|
||||
void resolve_domain_name(const char* domain_name);
|
||||
|
||||
#endif // W5500_H
|
||||
|
||||
@@ -8,9 +8,8 @@
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:genericCH32V203C8T6]
|
||||
[env]
|
||||
platform = https://git.hye.su/mira/platform-ch32v.git
|
||||
|
||||
platform_packages =
|
||||
toolchain-riscv @ https://git.hye.su/mira/toolchain-riscv-linux.git ; gcc 14.2.0
|
||||
framework-ch32v003fun @ https://github.com/cnlohr/ch32v003fun.git ; upstream cnlohr repo
|
||||
@@ -19,7 +18,8 @@ framework = ch32v003fun
|
||||
upload_protocol = wlink # isp, minichlink, wch-link, wlink
|
||||
build_unflags = -march=rv32imacxw
|
||||
build_flags = -march=rv32imac -Wall -Wextra
|
||||
; dbg
|
||||
; build_type = debug
|
||||
; debug_build_unflags = -Og
|
||||
; debug_build_flags = -Os -ggdb3 -g3
|
||||
|
||||
[env:local]
|
||||
platform_packages =
|
||||
toolchain-riscv @ symlink:///home/mira/src/xpack-riscv-none-elf-gcc-14.2.0-2 ; gcc 14.2.0
|
||||
framework-ch32v003fun @ https://github.com/cnlohr/ch32v003fun.git ; upstream cnlohr repo
|
||||
|
||||
13
src/gpio.c
Normal file
13
src/gpio.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "gpio.h"
|
||||
|
||||
#include "ch32v003fun.h"
|
||||
|
||||
void init_gpio(void) {
|
||||
// Enable clock for GPIOB
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOB;
|
||||
|
||||
// GPIOB Configuration: Pins 3 and 4 as Output, Push-Pull, 10MHz
|
||||
GPIOB->CFGLR &= ~((0xF << (4 * 3)) | (0xF << (4 * 4)));
|
||||
GPIOB->CFGLR |= ((GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 3)) |
|
||||
((GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 4));
|
||||
}
|
||||
203
src/main.c
203
src/main.c
@@ -1,197 +1,26 @@
|
||||
#include <DHCP/dhcp.h>
|
||||
#include <DNS/dns.h>
|
||||
#include <W5500/w5500.h>
|
||||
#include <socket.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ch32v003fun.h"
|
||||
#include "gpio.h"
|
||||
#include "spi_dma.h"
|
||||
#include "uart.h"
|
||||
#include "w5500.h"
|
||||
|
||||
#define DHCP_SOCKET 0
|
||||
#define DNS_SOCKET 1
|
||||
#define HTTP_SOCKET 2
|
||||
|
||||
volatile uint32_t count = 0;
|
||||
|
||||
void init_system(void) {
|
||||
SystemInit(); // from ch32v003fun.h
|
||||
|
||||
RCC->APB2PCENR |=
|
||||
RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB; // Enable GPIO clocks
|
||||
|
||||
setup_uart(UART_BRR_APB1); // 115200 baud
|
||||
}
|
||||
|
||||
void init_gpio(void) {
|
||||
// GPIO PB3 pp
|
||||
GPIOB->CFGLR &= ~(0xf << (4 * 3));
|
||||
GPIOB->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 3);
|
||||
|
||||
// GPIO PB4 pp
|
||||
GPIOB->CFGLR &= ~(0xf << (4 * 4));
|
||||
GPIOB->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 4);
|
||||
}
|
||||
|
||||
void init_spi(void) {
|
||||
// Enable SPI1
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_SPI1;
|
||||
|
||||
// CS on PA4, 10MHz Output, open-drain
|
||||
GPIOA->CFGLR &= ~(0xf << (4 * 4));
|
||||
GPIOA->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD) << (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
|
||||
GPIOA->CFGLR &= ~(0xf << (4 * 6));
|
||||
GPIOA->CFGLR |= (GPIO_CNF_IN_FLOATING) << (4 * 6);
|
||||
|
||||
// MISO on PA6, 10MHz Output, alt func, push-pull
|
||||
GPIOA->CFGLR &= ~(0xf << (4 * 7));
|
||||
GPIOA->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 7);
|
||||
|
||||
// SPI1->CTLR1 = (0 << 15) | // BIDIMODE
|
||||
// (0 << 14) | // BIDIOE
|
||||
// (0 << 13) | // CRCEN
|
||||
// (0 << 12) | // CRCNEXT
|
||||
// (0 << 11) | // DFF
|
||||
// (0 << 10) | // RXONLY
|
||||
// (1 << 9) | // SSM
|
||||
// (0 << 8) | // SSI
|
||||
// (0 << 7) | // LSBFIRST
|
||||
// (0 << 6) | // SPE (Enable SPI)
|
||||
// (1 << 5) | // BR[2] (Set baud rate)
|
||||
// (0 << 4) | // BR[1]
|
||||
// (0 << 3) | // BR[0]
|
||||
// (1 << 2) | // MSTR (Master mode)
|
||||
// (0 << 1) | // CPOL
|
||||
// (0); // CPHA
|
||||
|
||||
// reset control register
|
||||
SPI1->CTLR1 = 0;
|
||||
|
||||
// set prescaler
|
||||
// 011: FPCLK/16
|
||||
SPI1->CTLR1 = (SPI1->CTLR1 & ~SPI_CTLR1_BR) | (0x3 << 3);
|
||||
|
||||
// set clock polarity and phase
|
||||
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_1Edge);
|
||||
|
||||
// configure NSS pin, master mode
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
|
||||
// CH32V203 is master
|
||||
SPI1->CTLR1 |= SPI_Mode_Master;
|
||||
|
||||
// set data direction and configure data pins
|
||||
SPI1->CTLR1 |= SPI_Direction_2Lines_FullDuplex;
|
||||
|
||||
// disable I2S mode
|
||||
SPI1->I2SCFGR &= SPI_Mode_Select;
|
||||
SPI1->CTLR1 &= ~(SPI_CTLR1_DFF); // DFF 16bit data-length enable, writable
|
||||
// only when SPE is 0
|
||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||
}
|
||||
|
||||
volatile int ip_assigned = 0;
|
||||
|
||||
void Callback_IPAssigned(void) {
|
||||
printf("Callback: IP assigned! Leased time: %ld sec\r\n", getDHCPLeasetime());
|
||||
ip_assigned = 1;
|
||||
}
|
||||
|
||||
void Callback_IPConflict(void) { printf("Callback: IP conflict!\r\n"); }
|
||||
|
||||
// 1K should be enough, see https://forum.wiznet.io/t/topic/1612/2
|
||||
uint8_t dhcp_buffer[1024];
|
||||
// 1K seems to be enough for this buffer as well
|
||||
uint8_t dns_buffer[1024];
|
||||
void init_system(void);
|
||||
|
||||
int main(void) {
|
||||
init_system();
|
||||
configure_network();
|
||||
resolve_domain_name("hye.su");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void init_system(void) {
|
||||
SystemInit();
|
||||
|
||||
init_gpio();
|
||||
init_spi();
|
||||
|
||||
printf("SystemClk: %u\r\n", (unsigned)FUNCONF_SYSTEM_CORE_CLOCK);
|
||||
|
||||
printf("Registering W5500 callbacks...\r\n");
|
||||
reg_wizchip_cs_cbfunc(W5500_Select, W5500_Unselect);
|
||||
reg_wizchip_spi_cbfunc(W5500_ReadByte, W5500_WriteByte);
|
||||
// reg_wizchip_spiburst_cbfunc(W5500_ReadBuff, W5500_WriteBuff);
|
||||
|
||||
printf("Calling wizchip_init()...\r\n");
|
||||
uint8_t rx_tx_buff_sizes[] = {2, 2, 2, 2, 2, 2, 2, 2};
|
||||
wizchip_init(rx_tx_buff_sizes, rx_tx_buff_sizes);
|
||||
|
||||
printf("Calling DHCP_init()...\r\n");
|
||||
wiz_NetInfo net_info = {.mac = {0xEA, 0x11, 0x22, 0x33, 0x44, 0xEA},
|
||||
.dhcp = NETINFO_DHCP};
|
||||
// set MAC address before using DHCP
|
||||
setSHAR(net_info.mac);
|
||||
DHCP_init(DHCP_SOCKET, dhcp_buffer);
|
||||
|
||||
uint8_t version = getVERSIONR();
|
||||
|
||||
printf("W5500 VERSIONR: 0x%02X\n", version);
|
||||
|
||||
printf("Registering DHCP callbacks...\r\n");
|
||||
reg_dhcp_cbfunc(Callback_IPAssigned, Callback_IPAssigned,
|
||||
Callback_IPConflict);
|
||||
|
||||
printf("Calling DHCP_run()...\r\n");
|
||||
// actually should be called in a loop, e.g. by timer
|
||||
uint32_t ctr = 1e5;
|
||||
while ((!ip_assigned) && (ctr > 0)) {
|
||||
DHCP_run();
|
||||
ctr--;
|
||||
}
|
||||
if (!ip_assigned) {
|
||||
printf("\r\nIP was not assigned :(\r\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
getIPfromDHCP(net_info.ip);
|
||||
getGWfromDHCP(net_info.gw);
|
||||
getSNfromDHCP(net_info.sn);
|
||||
|
||||
uint8_t dns[4];
|
||||
getDNSfromDHCP(dns);
|
||||
|
||||
printf(
|
||||
"IP: %d.%d.%d.%d\r\nGW: %d.%d.%d.%d\r\nNet: %d.%d.%d.%d\r\nDNS: "
|
||||
"%d.%d.%d.%d\r\n",
|
||||
net_info.ip[0], net_info.ip[1], net_info.ip[2], net_info.ip[3],
|
||||
net_info.gw[0], net_info.gw[1], net_info.gw[2], net_info.gw[3],
|
||||
net_info.sn[0], net_info.sn[1], net_info.sn[2], net_info.sn[3], dns[0],
|
||||
dns[1], dns[2], dns[3]);
|
||||
|
||||
printf("Calling wizchip_setnetinfo()...\r\n");
|
||||
wizchip_setnetinfo(&net_info);
|
||||
|
||||
printf("Calling DNS_init()...\r\n");
|
||||
DNS_init(DNS_SOCKET, dns_buffer);
|
||||
|
||||
const char domain_name[] = "hye.su";
|
||||
uint8_t addr[4];
|
||||
int8_t res;
|
||||
uint8_t retries = 0;
|
||||
|
||||
while (retries < 2) {
|
||||
Delay_Ms(250);
|
||||
|
||||
printf("Resolving domain name \"%s\"...\r\n", domain_name);
|
||||
|
||||
res = DNS_run(dns, (uint8_t *)domain_name, addr);
|
||||
|
||||
if (res == 1) {
|
||||
printf("Result: %d.%d.%d.%d\r\n", addr[0], addr[1], addr[2], addr[3]);
|
||||
} else {
|
||||
printf("DNS_run() failed, res = %d. Retries: %u\r\n", res, retries);
|
||||
}
|
||||
|
||||
retries++;
|
||||
}
|
||||
}
|
||||
init_uart(UART_BRR_APB1);
|
||||
// init_spi();
|
||||
init_spidma();
|
||||
}
|
||||
|
||||
163
src/spi_dma.c
Normal file
163
src/spi_dma.c
Normal file
@@ -0,0 +1,163 @@
|
||||
#include "spi_dma.h"
|
||||
|
||||
#include "ch32v003fun.h"
|
||||
|
||||
volatile transfer_state_t tx_state = IDLE;
|
||||
volatile transfer_state_t rx_state = IDLE;
|
||||
|
||||
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); }
|
||||
|
||||
void spi_select(void) {
|
||||
GPIOA->BCR = (1 << 4); // Set PA4 (CS) low
|
||||
}
|
||||
|
||||
void spi_unselect(void) {
|
||||
GPIOA->BSHR = (1 << 4); // Set PA4 (CS) high
|
||||
}
|
||||
|
||||
void init_spidma(void) {
|
||||
// Enable clock for GPIOA and SPI1
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1;
|
||||
// Enable clock for DMA1
|
||||
RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
|
||||
|
||||
// SPI1 Pin Configuration
|
||||
// CS on PA4, 10MHz Output, open-drain
|
||||
GPIOA->CFGLR &= ~(0xf << (4 * 4));
|
||||
GPIOA->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD) << (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
|
||||
GPIOA->CFGLR &= ~(0xf << (4 * 6));
|
||||
GPIOA->CFGLR |= (GPIO_CNF_IN_FLOATING) << (4 * 6);
|
||||
// MISO on PA6, 10MHz Output, alt func, push-pull
|
||||
GPIOA->CFGLR &= ~(0xf << (4 * 7));
|
||||
GPIOA->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 7);
|
||||
|
||||
// Reset and Configure SPI1
|
||||
SPI1->CTLR1 = 0; // Clear CTLR1 initially
|
||||
|
||||
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_8 | // Baud rate prescaler
|
||||
SPI_NSS_Soft; // Software NSS management
|
||||
|
||||
// Enable TX and RX DMA
|
||||
SPI1->CTLR2 = SPI_CTLR2_TXDMAEN | SPI_CTLR2_RXDMAEN;
|
||||
|
||||
SPI1->I2SCFGR &= SPI_Mode_Select; // Disable I2S mode
|
||||
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;
|
||||
|
||||
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_EnableIRQ(DMA1_Channel3_IRQn);
|
||||
NVIC_EnableIRQ(DMA1_Channel2_IRQn);
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "ch32v003fun.h"
|
||||
|
||||
// Write multiple chars to UART
|
||||
int _write(int fd, const char *buf, int size) {
|
||||
int _write(__attribute__((unused)) int fd, const char *buf, int size) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
while (!(USART2->STATR & USART_FLAG_TC)); // Wait for transmission complete
|
||||
USART2->DATAR = *buf++; // Send character
|
||||
@@ -18,8 +18,8 @@ int putchar(int c) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void setup_uart(int uart_brr) {
|
||||
// RCC->APB2PCENR |= RCC_APB2Periph_GPIOA; // Enable GPIOA on APB2
|
||||
void init_uart(int uart_brr) {
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA; // Enable GPIOA on APB2
|
||||
RCC->APB1PCENR |= RCC_APB1Periph_USART2; // Enable USART2 on APB1
|
||||
|
||||
GPIOA->CFGLR &= ~(0xf << (4 * 2)); // Clear bits for PA2
|
||||
|
||||
127
src/w5500.c
127
src/w5500.c
@@ -1,46 +1,123 @@
|
||||
#include "w5500.h"
|
||||
|
||||
#include <DHCP/dhcp.h>
|
||||
#include <DNS/dns.h>
|
||||
#include <W5500/w5500.h>
|
||||
#include <socket.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ch32v003fun.h"
|
||||
// #include "spi.h"
|
||||
#include "spi_dma.h"
|
||||
|
||||
static inline uint8_t SPI_is_RX_empty() { return SPI1->STATR & SPI_STATR_RXNE; }
|
||||
// Definitions for socket indexes
|
||||
#define DHCP_SOCKET 0
|
||||
#define DNS_SOCKET 1
|
||||
#define HTTP_SOCKET 2
|
||||
|
||||
static inline void SPI_wait_not_busy() {
|
||||
while ((SPI1->STATR & SPI_STATR_BSY) != 0);
|
||||
}
|
||||
// Global variables
|
||||
volatile uint32_t count = 0;
|
||||
volatile int ip_assigned = 0;
|
||||
|
||||
static inline uint8_t SPI_transfer(uint8_t data) {
|
||||
while (!(SPI1->STATR & SPI_STATR_TXE));
|
||||
// SPI_wait_not_busy();
|
||||
SPI1->DATAR = data;
|
||||
// Global buffers for DHCP and DNS
|
||||
uint8_t dhcp_buffer[1024];
|
||||
uint8_t dns_buffer[1024];
|
||||
|
||||
while (!(SPI1->STATR & SPI_STATR_RXNE));
|
||||
return SPI1->DATAR;
|
||||
}
|
||||
|
||||
void W5500_Select(void) {
|
||||
void w5500_select(void) {
|
||||
GPIOA->BCR = (1 << 4); // Set PA4 (CS) low
|
||||
// Delay_Ms(2);
|
||||
}
|
||||
|
||||
void W5500_Unselect(void) {
|
||||
void w5500_unselect(void) {
|
||||
GPIOA->BSHR = (1 << 4); // Set PA4 (CS) high
|
||||
// Delay_Ms(2);
|
||||
}
|
||||
|
||||
uint8_t W5500_ReadByte() {
|
||||
return SPI_transfer(0xFF); // dummy byte to init read
|
||||
// Function to handle IP assignment details
|
||||
void handle_ip_assigned(void) {
|
||||
printf("IP Assigned!\n");
|
||||
|
||||
wiz_NetInfo net_info;
|
||||
getIPfromDHCP(net_info.ip);
|
||||
getGWfromDHCP(net_info.gw);
|
||||
getSNfromDHCP(net_info.sn);
|
||||
|
||||
uint8_t dns[4];
|
||||
getDNSfromDHCP(dns);
|
||||
|
||||
printf(
|
||||
"IP: %d.%d.%d.%d\nGW: %d.%d.%d.%d\nNet: %d.%d.%d.%d\nDNS: "
|
||||
"%d.%d.%d.%d\n",
|
||||
net_info.ip[0], net_info.ip[1], net_info.ip[2], net_info.ip[3],
|
||||
net_info.gw[0], net_info.gw[1], net_info.gw[2], net_info.gw[3],
|
||||
net_info.sn[0], net_info.sn[1], net_info.sn[2], net_info.sn[3], dns[0],
|
||||
dns[1], dns[2], dns[3]);
|
||||
|
||||
wizchip_setnetinfo(&net_info);
|
||||
}
|
||||
|
||||
void W5500_WriteByte(uint8_t byte) { SPI_transfer(byte); }
|
||||
// Callback functions
|
||||
void callback_ip_assigned(void) {
|
||||
printf("Callback: IP assigned! Leased time: %u sec\n", getDHCPLeasetime());
|
||||
ip_assigned = 1;
|
||||
}
|
||||
|
||||
void W5500_ReadBuff(uint8_t* buffer, uint16_t len) {
|
||||
for (uint16_t i = 0; i < len; i++) {
|
||||
buffer[i] = W5500_ReadByte();
|
||||
void callback_ip_conflict(void) { printf("Callback: IP conflict!\n"); }
|
||||
|
||||
void configure_network(void) {
|
||||
printf("Starting network configuration...\n");
|
||||
|
||||
// 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_spiburst_cbfunc(spidma_read_buffer, spidma_write_buffer);
|
||||
|
||||
uint8_t rx_tx_buff_sizes[] = {2, 2, 2, 2, 2, 2, 2, 2};
|
||||
wizchip_init(rx_tx_buff_sizes, rx_tx_buff_sizes);
|
||||
|
||||
// Start DHCP process
|
||||
wiz_NetInfo net_info = {.mac = {0xEA, 0x11, 0x22, 0x33, 0x44, 0xEA},
|
||||
.dhcp = NETINFO_DHCP};
|
||||
setSHAR(net_info.mac);
|
||||
DHCP_init(DHCP_SOCKET, dhcp_buffer);
|
||||
|
||||
// Register DHCP callbacks
|
||||
reg_dhcp_cbfunc(callback_ip_assigned, callback_ip_assigned,
|
||||
callback_ip_conflict);
|
||||
|
||||
// Attempt to acquire an IP address using DHCP
|
||||
const uint32_t max_attempts = 1e5;
|
||||
for (uint32_t attempt = 0; !ip_assigned && attempt < max_attempts;
|
||||
++attempt) {
|
||||
DHCP_run();
|
||||
}
|
||||
|
||||
if (!ip_assigned) {
|
||||
printf("\r\nIP was not assigned :(\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
handle_ip_assigned();
|
||||
}
|
||||
|
||||
void W5500_WriteBuff(uint8_t* buffer, uint16_t len) {
|
||||
for (uint16_t i = 0; i < len; i++) {
|
||||
W5500_WriteByte(buffer[i]);
|
||||
void resolve_domain_name(const char* domain_name) {
|
||||
printf("Resolving domain name \"%s\"...\n", domain_name);
|
||||
|
||||
DNS_init(DNS_SOCKET, dns_buffer);
|
||||
// cloudflare dns
|
||||
uint8_t dns[] = {1, 1, 1, 1};
|
||||
uint8_t addr[4];
|
||||
int8_t res;
|
||||
uint8_t retries = 0;
|
||||
|
||||
while (retries < 3) {
|
||||
Delay_Ms(250);
|
||||
|
||||
res = DNS_run(dns, (uint8_t*)domain_name, addr);
|
||||
if (res == 1) {
|
||||
printf("Result: %d.%d.%d.%d\n", addr[0], addr[1], addr[2], addr[3]);
|
||||
break;
|
||||
} else {
|
||||
printf("DNS_run() failed, res = %d. Retries: %u\n", res, retries);
|
||||
}
|
||||
retries++;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user