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",
|
"wizchip_conf.h": "c",
|
||||||
"socket.h": "c",
|
"socket.h": "c",
|
||||||
"type_traits": "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
|
(UART_BAUD_RATE)) // USART1
|
||||||
|
|
||||||
// Function prototypes
|
// Function prototypes
|
||||||
void setup_uart(int uart_brr);
|
void init_uart(int uart_brr);
|
||||||
|
|
||||||
#endif // UART_H
|
#endif // UART_H
|
||||||
|
|||||||
@@ -4,21 +4,27 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// Sets the CS pin low
|
// Sets the CS pin low
|
||||||
void W5500_Select(void);
|
void w5500_select(void);
|
||||||
|
|
||||||
// Sets the CS pin high
|
// Sets the CS pin high
|
||||||
void W5500_Unselect(void);
|
void w5500_unselect(void);
|
||||||
|
|
||||||
// Reads a byte via SPI
|
// Reads a byte via SPI
|
||||||
uint8_t W5500_ReadByte(void);
|
uint8_t w5500_read_byte(void);
|
||||||
|
|
||||||
// Writes a byte via SPI
|
// Writes a byte via SPI
|
||||||
void W5500_WriteByte(uint8_t byte);
|
void w5500_write_byte(uint8_t byte);
|
||||||
|
|
||||||
// Reads multiple bytes via SPI
|
// 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
|
// 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
|
#endif // W5500_H
|
||||||
|
|||||||
@@ -8,9 +8,8 @@
|
|||||||
; Please visit documentation for the other options and examples
|
; Please visit documentation for the other options and examples
|
||||||
; https://docs.platformio.org/page/projectconf.html
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
[env:genericCH32V203C8T6]
|
[env]
|
||||||
platform = https://git.hye.su/mira/platform-ch32v.git
|
platform = https://git.hye.su/mira/platform-ch32v.git
|
||||||
|
|
||||||
platform_packages =
|
platform_packages =
|
||||||
toolchain-riscv @ https://git.hye.su/mira/toolchain-riscv-linux.git ; gcc 14.2.0
|
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
|
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
|
upload_protocol = wlink # isp, minichlink, wch-link, wlink
|
||||||
build_unflags = -march=rv32imacxw
|
build_unflags = -march=rv32imacxw
|
||||||
build_flags = -march=rv32imac -Wall -Wextra
|
build_flags = -march=rv32imac -Wall -Wextra
|
||||||
; dbg
|
|
||||||
; build_type = debug
|
[env:local]
|
||||||
; debug_build_unflags = -Og
|
platform_packages =
|
||||||
; debug_build_flags = -Os -ggdb3 -g3
|
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));
|
||||||
|
}
|
||||||
201
src/main.c
201
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 <stdio.h>
|
||||||
|
|
||||||
#include "ch32v003fun.h"
|
#include "ch32v003fun.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "spi_dma.h"
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
#include "w5500.h"
|
#include "w5500.h"
|
||||||
|
|
||||||
#define DHCP_SOCKET 0
|
void init_system(void);
|
||||||
#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];
|
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
init_system();
|
init_system();
|
||||||
|
configure_network();
|
||||||
|
resolve_domain_name("hye.su");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_system(void) {
|
||||||
|
SystemInit();
|
||||||
|
|
||||||
init_gpio();
|
init_gpio();
|
||||||
init_spi();
|
init_uart(UART_BRR_APB1);
|
||||||
|
// init_spi();
|
||||||
printf("SystemClk: %u\r\n", (unsigned)FUNCONF_SYSTEM_CORE_CLOCK);
|
init_spidma();
|
||||||
|
|
||||||
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++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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"
|
#include "ch32v003fun.h"
|
||||||
|
|
||||||
// Write multiple chars to UART
|
// 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++) {
|
for (int i = 0; i < size; i++) {
|
||||||
while (!(USART2->STATR & USART_FLAG_TC)); // Wait for transmission complete
|
while (!(USART2->STATR & USART_FLAG_TC)); // Wait for transmission complete
|
||||||
USART2->DATAR = *buf++; // Send character
|
USART2->DATAR = *buf++; // Send character
|
||||||
@@ -18,8 +18,8 @@ int putchar(int c) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_uart(int uart_brr) {
|
void init_uart(int uart_brr) {
|
||||||
// RCC->APB2PCENR |= RCC_APB2Periph_GPIOA; // Enable GPIOA on APB2
|
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA; // Enable GPIOA on APB2
|
||||||
RCC->APB1PCENR |= RCC_APB1Periph_USART2; // Enable USART2 on APB1
|
RCC->APB1PCENR |= RCC_APB1Periph_USART2; // Enable USART2 on APB1
|
||||||
|
|
||||||
GPIOA->CFGLR &= ~(0xf << (4 * 2)); // Clear bits for PA2
|
GPIOA->CFGLR &= ~(0xf << (4 * 2)); // Clear bits for PA2
|
||||||
|
|||||||
131
src/w5500.c
131
src/w5500.c
@@ -1,46 +1,123 @@
|
|||||||
#include "w5500.h"
|
#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 "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() {
|
// Global variables
|
||||||
while ((SPI1->STATR & SPI_STATR_BSY) != 0);
|
volatile uint32_t count = 0;
|
||||||
}
|
volatile int ip_assigned = 0;
|
||||||
|
|
||||||
static inline uint8_t SPI_transfer(uint8_t data) {
|
// Global buffers for DHCP and DNS
|
||||||
while (!(SPI1->STATR & SPI_STATR_TXE));
|
uint8_t dhcp_buffer[1024];
|
||||||
// SPI_wait_not_busy();
|
uint8_t dns_buffer[1024];
|
||||||
SPI1->DATAR = data;
|
|
||||||
|
|
||||||
while (!(SPI1->STATR & SPI_STATR_RXNE));
|
void w5500_select(void) {
|
||||||
return SPI1->DATAR;
|
|
||||||
}
|
|
||||||
|
|
||||||
void W5500_Select(void) {
|
|
||||||
GPIOA->BCR = (1 << 4); // Set PA4 (CS) low
|
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
|
GPIOA->BSHR = (1 << 4); // Set PA4 (CS) high
|
||||||
// Delay_Ms(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t W5500_ReadByte() {
|
// Function to handle IP assignment details
|
||||||
return SPI_transfer(0xFF); // dummy byte to init read
|
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) {
|
||||||
void W5500_ReadBuff(uint8_t* buffer, uint16_t len) {
|
printf("Callback: IP assigned! Leased time: %u sec\n", getDHCPLeasetime());
|
||||||
for (uint16_t i = 0; i < len; i++) {
|
ip_assigned = 1;
|
||||||
buffer[i] = W5500_ReadByte();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void W5500_WriteBuff(uint8_t* buffer, uint16_t len) {
|
void callback_ip_conflict(void) { printf("Callback: IP conflict!\n"); }
|
||||||
for (uint16_t i = 0; i < len; i++) {
|
|
||||||
W5500_WriteByte(buffer[i]);
|
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 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