SPI Rx DMA not working

I tried the example in the libdaisy documentation, and the docs are old (the NSS config is not used that way anymore) and I can’t get SPI Dma Receive working. The blocking version works just fine. I can also get Tx DMA working. The buffer is in buffer space. Anything I should look at that isn’t documented yet?

Would you be able to provide the code here (or if there’s a lot of surrounding code, a minimal reproduction)? I know you said you simply tried the example, but having the exact code you used would make potentially diagnosing an issue much easier!

Here’s the entire main.cpp:

#include "daisy_seed.h"

using namespace daisy;

#define PROC_SIZE 1024

DaisySeed hw;

static uint8_t DMA_BUFFER_MEM_SECTION usb_cb_buf[32];

static uint32_t usb_cb_count = 0;
static uint32_t usb_cb_len   = 0;

static void DSY_ITCM_MEM_SECTION my_usb_cb(uint8_t *buf, uint32_t *len)
{
    uint32_t n = (*len) - 1;
    if((*len > 1) && (usb_cb_len + n < 30))
    {
        for(uint32_t i = 0; i < n; i++)
            usb_cb_buf[usb_cb_len++] = buf[i];
    }
    usb_cb_count++;
}

SpiHandle spiHandleRx;

static void my_init_spi(SpiHandle *hspi)
{
    SpiHandle::Config spiConf;
    spiConf.periph    = SpiHandle::Config::Peripheral::SPI_6;
    spiConf.mode      = SpiHandle::Config::Mode::SLAVE;
    spiConf.direction = SpiHandle::Config::Direction::TWO_LINES_RX_ONLY;
    spiConf.nss       = SpiHandle::Config::NSS::SOFT;
    //spiConf.nss     = SpiHandle::Config::NSS::HARD_INPUT;
    spiConf.pin_config.nss  = Pin(GPIOPort::PORTA, 4);
    spiConf.pin_config.sclk = Pin(GPIOPort::PORTA, 5);
    spiConf.pin_config.mosi = Pin(GPIOPort::PORTA, 7);
    spiConf.baud_prescaler  = SpiHandle::Config::BaudPrescaler::PS_2;
    spiConf.datasize        = 8;

    hspi->Init(spiConf);
}

static void DSY_ITCM_MEM_SECTION timer_cb(void *ptr)
{
    if(ptr)
        *((bool *)ptr) = true;
}

static uint32_t one_sec;
static uint32_t one_milli;
static uint32_t one_micro;

static bool timed_one_sec   = false;
static bool timed_tenth_sec = false;

static void my_init_timers()
{
    TimerHandle::Config T_config;
    T_config            = TimerHandle::Config();
    T_config.dir        = TimerHandle::Config::CounterDir::UP;
    T_config.enable_irq = true;

    TimerHandle Timer4;
    T_config.periph = TimerHandle::Config::Peripheral::TIM_4;
    T_config.period = 999;
    Timer4.Init(T_config);
    Timer4.SetPrescaler(one_micro * 100);
    Timer4.SetCallback(timer_cb, (void *)&timed_tenth_sec);
    Timer4.Start();

    TimerHandle Timer5;
    T_config.periph = TimerHandle::Config::Peripheral::TIM_5;
    T_config.period = 9999;
    Timer5.Init(T_config);
    Timer5.SetPrescaler(one_micro * 100);
    Timer5.SetCallback(timer_cb, (void *)&timed_one_sec);
    Timer5.Start();
}

uint8_t DMA_BUFFER_MEM_SECTION frame_rx[PROC_SIZE];

int DSY_ITCM_MEM_SECTION main(void)
{
    hw.Init(true);
    hw.StartLog(); // true to wait for connection

    hw.usb_handle.Init(UsbHandle::FS_INTERNAL);
    System::Delay(1); // hack
    hw.usb_handle.SetReceiveCallback(my_usb_cb, UsbHandle::FS_INTERNAL);

    one_sec   = System::GetTickFreq();
    one_milli = one_sec / 1000;
    one_micro = one_milli / 1000;

    my_init_timers();

    my_init_spi(&spiHandleRx);

    uint32_t proc_count  = 0;
    uint32_t proc_time   = 0;
    uint32_t check_count = 0;

    bool serial_on = true;
    bool led_state = false;
    bool use_dma   = false;

    while(true)
    {
        if(timed_tenth_sec)
        {
            timed_tenth_sec = false;

            for(uint32_t i = 0; i < 1024; i++)
            {
                uint16_t m       = 0xC5C5;
                bool     matched = false;
                for(uint8_t j = 0; j < 8; j++)
                {
                    uint8_t k = (m >> j) & 0xFF;
                    if(frame_rx[i] == k)
                    {
                        matched = true;
                        break;
                    }
                }
                if(!matched)
                    check_count++;
                frame_rx[i] = 0;
            }

            uint32_t t0 = System::GetTick();
            if(use_dma)
                spiHandleRx.DmaReceive(frame_rx, PROC_SIZE, 0, 0, 0);
            else
                spiHandleRx.BlockingReceive(frame_rx, PROC_SIZE, 5000);
            proc_time += System::GetTick() - t0;
            proc_count++;

            // Check for any input
            if(usb_cb_count > 0)
            {
                usb_cb_buf[usb_cb_len] = 0;
                if(usb_cb_buf[0] == 'd')
                {
                    serial_on = !serial_on;
                }
                else if(usb_cb_buf[0] == 'm')
                {
                    use_dma = !use_dma;
                    if(use_dma)
                        hw.Print("DMA ON\n");
                    else
                        hw.Print("DMA OFF\n");
                }
                else if(usb_cb_buf[0] == 'r')
                {
                    my_init_spi(&spiHandleRx);
                }
                else
                {
                    hw.Print("\td:  toggle display on/off\n");
                    hw.Print("\tm:  toggle DMA on/off\n");
                    hw.Print("\tr:  Reset SPI\n");
                    if(use_dma)
                        hw.Print("\tDMA ON\n");
                    else
                        hw.Print("\tDMA OFF\n");
                }
                usb_cb_count = 0;
                usb_cb_len   = 0;
            }
        }

        if(timed_one_sec)
        {
            timed_one_sec = false;

            if(serial_on && proc_count)
                hw.Print("PROC:  %2d  %6.3f  %5d\n",
                         proc_count,
                         (float)proc_time / one_milli,
                         check_count);
            proc_count  = 0;
            proc_time   = 0;
            check_count = 0;

            hw.SetLed(led_state);
            led_state = !led_state;
        }
    }
}