how to use DMA SPI mode for nucleo 446RE and W5500

As the title describes i want to use DMA mode to burst write data to W5500 which is connected via SPI. Currently i have the communication working in normal SPI mode but I want to incorporate DMA mode.

I am also using Wiznet IOLibrary and Socket API to send data from w5500 back to my computer via TCP.

My code for DMA mode, it is not sending any data currently to the connected port -

#include “mbed.h”
#include “w5500_spi.h”
#include “socket.h”

#define WIZCHIP W5500
#define WIZCHIP_IO_MODE WIZCHIP_IO_MODE_SPI_VDM
#define WAIT_TIME 1000 // msec
#define BUFFERLENGTH 12000
#define SOCKET_N 1

DigitalOut led1(LED1);
SPI spi1(D11, D12, D13);
DigitalOut cs(D10);
DigitalOut rst(D4);
DigitalOut toggle(D14);

wiz_NetInfo net_info = {
.mac = {0x00, 0x08, 0xdc, 0xab, 0xcd, 0xef},
.ip = {192, 168, 1, 15},
.sn = {255, 255, 255, 0},
.gw = {192, 168, 1, 1},
.dns = {8, 8, 8, 8},
.dhcp = NETINFO_STATIC
};

wiz_PhyConf phyConf = {
.by = PHY_CONFBY_SW,
.mode = PHY_MODE_MANUAL,
.speed = PHY_SPEED_100,
.duplex = PHY_DUPLEX_FULL,
};

char buf[BUFFERLENGTH] = {0};

// DMA configuration
#define DMA_CHANNEL 3
#define DMA_STREAM DMA2_Stream5

DMA_HandleTypeDef dma_tx;

void dmaInit() {
__HAL_RCC_DMA2_CLK_ENABLE();

dma_tx.Instance = DMA_STREAM;
dma_tx.Init.Channel = DMA_CHANNEL;
dma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
dma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
dma_tx.Init.MemInc = DMA_MINC_ENABLE;
dma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
dma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
dma_tx.Init.Mode = DMA_NORMAL;
dma_tx.Init.Priority = DMA_PRIORITY_LOW;

HAL_DMA_Init(&dma_tx);

}

void spiDmaSend(const uint8_t *data, uint32_t size) {
HAL_DMA_DeInit(&dma_tx);
dma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
dma_tx.Init.MemInc = DMA_MINC_ENABLE;
dma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
dma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
dma_tx.Init.Mode = DMA_NORMAL;
dma_tx.Init.Priority = DMA_PRIORITY_LOW;
dma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
dma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
dma_tx.Init.MemBurst = DMA_MBURST_INC4;
dma_tx.Init.PeriphBurst = DMA_PBURST_INC4;
dma_tx.Instance->CR = 0; // Disable the DMA stream
dma_tx.Instance->M0AR = (uint32_t)data;
dma_tx.Instance->NDTR = size;
dma_tx.Instance->CR = DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_EN;

while (dma_tx.Instance->CR & DMA_SxCR_EN); // Wait for DMA transfer to complete

}

int main() {
spi1.format(8, 0);
spi1.frequency(20000000);

toggle.write(0);

w5500Init(&spi1, &cs, &rst);

int8_t err;

if (ctlwizchip(CW_SET_PHYCONF, (void*) &phyConf) == -1) {
    printf("Failed to set phyconf\n\r");
    return -1;
}

if (ctlnetwork(CN_SET_NETINFO, (void*) &net_info) == -1) {
    printf("Failed to set netinfo\n\r");
    return -1;
}

wiz_PhyConf currentStatus;
ctlwizchip(CW_GET_PHYSTATUS, (void*) &currentStatus);

printf("Speed is %d Mb/s. ", currentStatus.speed == PHY_SPEED_100 ? 100 : 10);
printf("%s.\n\r", currentStatus.duplex == PHY_DUPLEX_FULL ? "Full Duplex" : "Half Duplex");

err = socket(SOCKET_N, Sn_MR_TCP, 1234, SF_TCP_NODELAY);
if (err != SOCK_OK) {
    printf("Failed to open socket. Error %d\n\r", err);
    return -1;
}

err = listen(SOCKET_N);
if (err != SOCK_OK) {
    printf("Failed to listen/accept socket. Error %d\n\r", err);
    return -1;
}

uint8_t sock_state = 0;
while (sock_state != SOCK_ESTABLISHED) {
    getsockopt(SOCKET_N, SO_STATUS, (void*) &sock_state);
    printf("Sock State is: %d\n\r", sock_state);
    thread_sleep_for(WAIT_TIME);
}

printf("Client connected!\n\r");

Timer t;

dmaInit();

while (true) {
    for (int i = 0; i < BUFFERLENGTH - 1; i++) {
        buf[i] = 'A' + (i % 26);
    }
    buf[BUFFERLENGTH - 1] = '\0';

    t.reset();
    t.start();

    toggle.write(1);
    spiDmaSend((const uint8_t*)buf, strlen(buf));
    toggle.write(0);

    t.stop();
    float elapsed_time = t.read();

    int num_bytes_transmitted = strlen(buf);
    float transfer_speed = (num_bytes_transmitted / elapsed_time) * 8 / 1000000.0f;

    printf("Sent %d bytes in %.6f seconds, transfer speed: %.8f Mbps\n", num_bytes_transmitted, elapsed_time, transfer_speed);

    memset(buf, 0, BUFFERLENGTH);

    led1 = !led1;
    thread_sleep_for(1000);
}

}

1 Like