Problems with the SPI receive buffer when dma is enabled

MajinFoo
Posts: 9
Joined: Sun Jan 21, 2018 9:06 pm

Problems with the SPI receive buffer when dma is enabled

Postby MajinFoo » Sun Mar 25, 2018 8:29 pm

Hello,

I tried to read and write an external memory chip via SPI. But I have some problems with the esp idf library. If I just write or read everything works without problems. But if I write and read the data is not read correctly into the receive buffer.

In my program I first write 12 bytes and then 12 bytes are read. If I only read, all 12 bytes are read correctly and agree with the bytes written before. When I read after a write operation, one byte more is always set to zero for each write operation. Here's my code:

Code: Select all

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
#include <esp_err.h>
#include "driver/spi_master.h"
#include "driver/spi_common.h"
#include "esp_heap_alloc_caps.h"
#include "string.h"

#define MISO 	19
#define MOSI 	23
#define CLK 	18
#define CS 		5

#define READ	0b00000011 //Read data from memory array beginning at selected address
#define WRITE   0b00000010 //Write data to memory array beginning at selected address
#define WREN    0b00000110 //Set the write enable latch (enable write operations)
#define WRDI    0b00000100 //Reset the write enable latch (disable write operations)
#define RDSR    0b00000101 //Read STATUS register
#define WRSR    0b00000001 //Write STATUS register
#define PE      0b01000010 //Page Erase – erase one page in memory array
#define SE      0b11011000 //Sector Erase – erase one sector in memory array
#define CE      0b11000111 //Chip Erase – erase all sectors in memory array
#define RDID    0b10101011 //Release from Deep power-down and read electronic signature
#define DPD     0b10111001 //Deep Power-Down mode

#define FIRST_ADDRESS 0x00000
#define LAST_ADDRESS  0x1FFFF

esp_err_t write_cmd(spi_device_handle_t spi, uint8_t cmd)
{
    esp_err_t err;
    spi_transaction_ext_t t;
    spi_transaction_ext_t *t_res;
    t_res = &t;
    memset(&t, 0, sizeof(t));
    t.base.length = 0;
    t.base.tx_buffer = NULL;
    t.base.rxlength = 0;
    t.base.rx_buffer = NULL;
    t.base.cmd = cmd;
    t.base.user = (void*)0;
    t.base.flags = SPI_TRANS_VARIABLE_ADDR;
    t.address_bits = 0;
    err = spi_device_queue_trans(spi, (spi_transaction_t*)&t, 100);
    err = spi_device_get_trans_result(spi, (spi_transaction_t**)&t_res, 100);
    return err;
}

esp_err_t write_data(spi_device_handle_t spi, uint8_t *data, uint16_t addr, uint8_t len)
{
    esp_err_t err;
    spi_transaction_t t;
    spi_transaction_t* t_res;
    t_res = &t;
    memset(&t, 0, sizeof(t));
    t.length = len * 8;
    t.tx_buffer = data;
    t.rxlength = 0;
    t.rx_buffer = NULL;
    t.cmd = WRITE;
    t.addr = addr;
    t.user = (void*)0;
    err = spi_device_queue_trans(spi, &t, 100);
    err = spi_device_get_trans_result(spi, (spi_transaction_t**)&t_res, 100);
    return err;
}

esp_err_t read_data(spi_device_handle_t spi, uint8_t *data, uint16_t addr, uint8_t len)
{
    esp_err_t err;
    spi_transaction_t t;
    spi_transaction_t *t_res;
    t_res = &t;
    memset(&t, 0, sizeof(t));
    t.length = len * 8;
    t.tx_buffer = NULL;
    t.rxlength = len * 8;
    t.rx_buffer = data;
    t.cmd = READ;
    t.addr = addr;
    t.user = (void*)1;
    err = spi_device_queue_trans(spi, (spi_transaction_t*)&t, 100);
    err = spi_device_get_trans_result(spi, (spi_transaction_t**)&t_res, 100);
    return err;
}

esp_err_t init_spi(){
	esp_err_t err;
    spi_bus_config_t buscfg={
        .miso_io_num = MISO,
        .mosi_io_num = MOSI,
        .sclk_io_num = CLK,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1
    };
    err = spi_bus_initialize(VSPI_HOST, &buscfg, 1);
    return err;
}

esp_err_t add_slave(spi_device_handle_t* spi){
	esp_err_t err;
    spi_device_interface_config_t devcfg={
    	.command_bits = 8,
		.address_bits = 24,
        .clock_speed_hz = 10000,
        .mode = 0,
        .spics_io_num = CS,
        .queue_size=1,
    };
    err = spi_bus_add_device(VSPI_HOST, &devcfg, spi);
    return err;
}

void spi_task(void *pvParameter)
{
	esp_err_t err;
	spi_device_handle_t spi;
	uint16_t write_count = 0;
	uint8_t* write_buffer = heap_caps_malloc(12, MALLOC_CAP_DMA);
	uint8_t* read_buffer  = heap_caps_malloc(12, MALLOC_CAP_DMA);
	err = init_spi();
	if (err != ESP_OK) printf("Error init_spi()");
	err = add_slave(&spi);
	if (err != ESP_OK) printf("Error add_slave()");

	for(uint8_t i = 0; i < 12; i++){
		write_buffer[i] = i;
	}
	while(1){
		//write Data to EEPROM
		//if I comment out this block the problem disappear
		err = write_cmd(spi, WREN);
		if (err != ESP_OK) printf("Error write_cmd()");
		vTaskDelay(1000);
		err = write_data(spi, write_buffer, 0, 12);
		if (err != ESP_OK) printf("Error write_data()");
		vTaskDelay(1000);

		//Read Data from EEPROM
		err = read_data(spi, read_buffer, 0, 12);
		if (err != ESP_OK) printf("Error read_data()");

		write_count++;
    		printf("\nNumber of Write Operations: %d\n", write_count);
    		printf("---------------------------------\n");
	    	for(int8_t i = 0; i < 12; i++){
	    		printf("read_buffer[%d] = %d\n", i, read_buffer[i]);
	    	}
		vTaskDelay(1000);
	}
}


void app_main(void)
{
	xTaskCreate(&spi_task, "spi_task", 4096, NULL, 5, NULL);
}
And the console output:

Code: Select all

MONITOR
--- idf_monitor on /dev/ttyUSB0 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:4572
load:0x40078000,len:0
load:0x40078000,len:13184
entry 0x40078d38
I (86) cpu_start: Pro cpu up.
I (86) cpu_start: Single core mode
I (87) heap_init: Initializing. RAM available for dynamic allocation:
I (90) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (96) heap_init: At 3FFB1E70 len 0002E190 (184 KiB): DRAM
I (102) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM
I (108) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (115) heap_init: At 40088974 len 0001768C (93 KiB): IRAM
I (121) cpu_start: Pro cpu start user code
I (139) cpu_start: Starting scheduler on PRO CPU.

Number of Write Operations: 1
---------------------------------
read_buffer[0] = 0
read_buffer[1] = 1
read_buffer[2] = 2
read_buffer[3] = 3
read_buffer[4] = 4
read_buffer[5] = 5
read_buffer[6] = 6
read_buffer[7] = 7
read_buffer[8] = 8
read_buffer[9] = 9
read_buffer[10] = 10
read_buffer[11] = 0

Number of Write Operations: 2
---------------------------------
read_buffer[0] = 0
read_buffer[1] = 1
read_buffer[2] = 2
read_buffer[3] = 3
read_buffer[4] = 4
read_buffer[5] = 5
read_buffer[6] = 6
read_buffer[7] = 7
read_buffer[8] = 8
read_buffer[9] = 9
read_buffer[10] = 0
read_buffer[11] = 0

Number of Write Operations: 3
---------------------------------
read_buffer[0] = 0
read_buffer[1] = 1
read_buffer[2] = 2
read_buffer[3] = 3
read_buffer[4] = 4
read_buffer[5] = 5
read_buffer[6] = 6
read_buffer[7] = 7
read_buffer[8] = 8
read_buffer[9] = 0
read_buffer[10] = 0
read_buffer[11] = 0

Number of Write Operations: 4
---------------------------------
read_buffer[0] = 0
read_buffer[1] = 1
read_buffer[2] = 2
read_buffer[3] = 3
read_buffer[4] = 4
read_buffer[5] = 5
read_buffer[6] = 6
read_buffer[7] = 7
read_buffer[8] = 8
read_buffer[9] = 0
read_buffer[10] = 0
read_buffer[11] = 0

Number of Write Operations: 5
---------------------------------
read_buffer[0] = 0
read_buffer[1] = 1
read_buffer[2] = 2
read_buffer[3] = 3
read_buffer[4] = 4
read_buffer[5] = 5
read_buffer[6] = 6
read_buffer[7] = 0
read_buffer[8] = 8
read_buffer[9] = 0
read_buffer[10] = 0
read_buffer[11] = 0

Number of Write Operations: 6
---------------------------------
read_buffer[0] = 0
read_buffer[1] = 1
read_buffer[2] = 2
read_buffer[3] = 3
read_buffer[4] = 4
read_buffer[5] = 5
read_buffer[6] = 0
read_buffer[7] = 0
read_buffer[8] = 8
read_buffer[9] = 0
read_buffer[10] = 0
read_buffer[11] = 0

As you can see with every new write operation one byte less is read into the receive buffer. Sometimes a byte is read in correctly after all, as you can see at read_buffer[8] = 8.

The problem disappears if i just read the data or when I disable DMA:

Code: Select all

 err = spi_bus_initialize(VSPI_HOST, &buscfg, 0);  //disable DMA

Code: Select all

MONITOR
--- idf_monitor on /dev/ttyUSB0 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:4572
load:0x40078000,len:0
load:0x40078000,len:13184
entry 0x40078d38
I (86) cpu_start: Pro cpu up.
I (86) cpu_start: Single core mode
I (87) heap_init: Initializing. RAM available for dynamic allocation:
I (90) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (96) heap_init: At 3FFB1E70 len 0002E190 (184 KiB): DRAM
I (102) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM
I (108) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (115) heap_init: At 40088974 len 0001768C (93 KiB): IRAM
I (121) cpu_start: Pro cpu start user code
I (139) cpu_start: Starting scheduler on PRO CPU.

Number of Write Operations: 1
---------------------------------
read_buffer[0] = 0
read_buffer[1] = 1
read_buffer[2] = 2
read_buffer[3] = 3
read_buffer[4] = 4
read_buffer[5] = 5
read_buffer[6] = 6
read_buffer[7] = 7
read_buffer[8] = 8
read_buffer[9] = 9
read_buffer[10] = 10
read_buffer[11] = 11

Number of Write Operations: 2
---------------------------------
read_buffer[0] = 0
read_buffer[1] = 1
read_buffer[2] = 2
read_buffer[3] = 3
read_buffer[4] = 4
read_buffer[5] = 5
read_buffer[6] = 6
read_buffer[7] = 7
read_buffer[8] = 8
read_buffer[9] = 9
read_buffer[10] = 10
read_buffer[11] = 11

Number of Write Operations: 3
---------------------------------
read_buffer[0] = 0
read_buffer[1] = 1
read_buffer[2] = 2
read_buffer[3] = 3
read_buffer[4] = 4
read_buffer[5] = 5
read_buffer[6] = 6
read_buffer[7] = 7
read_buffer[8] = 8
read_buffer[9] = 9
read_buffer[10] = 10
read_buffer[11] = 11

Number of Write Operations: 4
---------------------------------
read_buffer[0] = 0
read_buffer[1] = 1
read_buffer[2] = 2
read_buffer[3] = 3
read_buffer[4] = 4
read_buffer[5] = 5
read_buffer[6] = 6
read_buffer[7] = 7
read_buffer[8] = 8
read_buffer[9] = 9
read_buffer[10] = 10
read_buffer[11] = 11

Number of Write Operations: 5
---------------------------------
read_buffer[0] = 0
read_buffer[1] = 1
read_buffer[2] = 2
read_buffer[3] = 3
read_buffer[4] = 4
read_buffer[5] = 5
read_buffer[6] = 6
read_buffer[7] = 7
read_buffer[8] = 8
read_buffer[9] = 9
read_buffer[10] = 10
read_buffer[11] = 11
So I think it must have something to do with DMA, but I can't explain it to myself and I'm grateful for any help.

Who is online

Users browsing this forum: Bing [Bot] and 150 guests