Problems with the SPI receive buffer when dma is enabled
Posted: 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:
And the console output:
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:
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.
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);
}
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
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