spi master problem

nouwon
Posts: 7
Joined: Sat Mar 27, 2021 9:23 am

spi master problem

Postby nouwon » Sun Jul 23, 2023 8:53 pm

I have an application in which I interface mcp2517 with esp32.Recently I migrated to idf 5.0.Prior to migration the code was working.
I initialize the spi as follows

Code: Untitled.c Select all


static esp_err_t spi_master_init(void)
{

esp_err_t ret;

spi_bus_config_t buscfg = {
.miso_io_num = PIN_NUM_MISO,
.mosi_io_num = PIN_NUM_MOSI,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = SPI_DEFAULT_BUFFER_LENGTH * 8,

};

// SPI mode, representing a pair of (CPOL, CPHA) configuration:

// 0: (0, 0) 1: (0, 1) 2: (1, 0) 3: (1, 1)

spi_device_interface_config_t devcfg = {
.clock_speed_hz = SERIAL_CLOCK_SPEED, // for mcp2517 serial clock speed must be less or equal half of sys clock of mcp2517.
.mode = 0, // SPI mode 0
.spics_io_num = PIN_NUM_CS, // CS pin
.queue_size = 1,
.input_delay_ns = 20,
.cs_ena_posttrans = 3,
//.flags= SPI_DEVICE_HALFDUPLEX,
// We want to be able to queue 7 transactions at a time
//.pre_cb=can_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line
};

// Initialize the SPI bus
#if (defined DMA_ENABLED && DMA_ENABLED)

ret = spi_bus_initialize(CAN_SPI_HOST, &buscfg, DMA_CHAN);

#else
ret = spi_bus_initialize(CAN_SPI_HOST, &buscfg, 0);
#endif
ESP_ERROR_CHECK(ret);

// Attach the device to the SPI bus
ret = spi_bus_add_device(CAN_SPI_HOST, &devcfg, &spi_device);

ESP_ERROR_CHECK(ret);

return ret;
}
and I start spi transaction with calling

Code: Untitled.c Select all


spi_transaction_t t;

if (len == 0)
return ESP_FAIL; // no need to send anything
// Zero out the transaction
memset(&t, 0, sizeof(t));
t.length = len * 8; // Len is in bytes, transaction length is in bits.
t.tx_buffer = SpiTxData;

esp_err_t ret = spi_device_transmit(spi_device, &t);
The problem is that in the fifth transaction spi_device is changing during runtime and I get Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.

Core 0 register dump:
PC : 0x4008b55b PS : 0x00060530 A0 : 0x8008bb41 A1 : 0x3ffbb9c0
0x4008b55b: check_trans_valid at C:/Users/tufan/esp/esp-idf/components/driver/spi_master.c:735 (discriminator 2)

A2 : 0x3ffdffff A3 : 0x3ffbba70 A4 : 0x00000000 A5 : 0x00000080
A6 : 0x00000000 A7 : 0x00000005 A8 : 0x3ffbbbc0 A9 : 0x3ffbbb80
A10 : 0x000004ac A11 : 0x3f404528 A12 : 0x3f40498c A13 : 0x0000048e
A14 : 0x3f404528 A15 : 0x3f404f0c SAR : 0x00000004 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000088 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xfffffffe


Backtrace: 0x4008b558:0x3ffbb9c0 0x4008bb3e:0x3ffbb9f0 0x4008bc2a:0x3ffbba30 0x400dba7a:0x3ffbba60 0x400dbb3c:0x3ffbbac0 0x400da99d:0x3ffbbae0 0x400dae91:0x3ffbbb00 0x400d8e00:0x3ffbbb80 0x400d8e98:0x3ffbbbc0 0x400d89f3:0x3ffbbbf0 0x400d8a50:0x3ffbbc20 0x401ae786:0x3ffbbc50 0x40092a6d:0x3ffbbc80
0x4008b558: check_trans_valid at C:/Users/tufan/esp/esp-idf/components/driver/spi_master.c:733 (discriminator 2)

0x4008bb3e: spi_device_queue_trans at C:/Users/tufan/esp/esp-idf/components/driver/spi_master.c:866

0x4008bc2a: spi_device_transmit at C:/Users/tufan/esp/esp-idf/components/driver/spi_master.c:944

0x400dba7a: spi_master_transfer at C:/Users/tufan/esp/ble_spp_server/components/mcp2517/spi.c:130

0x400dbb3c: SPI_TransferData at C:/Users/tufan/esp/ble_spp_server/components/mcp2517/spi.c:57

0x400da99d: DRV_CANFDSPI_WriteByteArray at C:/Users/tufan/esp/ble_spp_server/components/mcp2517/mcp2517.c:441

0x400dae91: DRV_CANFDSPI_RamInit at C:/Users/tufan/esp/ble_spp_server/components/mcp2517/mcp2517.c:2779

0x400d8e00: mcp2517_reset at C:/Users/tufan/esp/ble_spp_server/main/spi_controller.c:190 (discriminator 13)

0x400d8e98: spi_controller_init at C:/Users/tufan/esp/ble_spp_server/main/spi_controller.c:92 (discriminator 13)

0x400d89f3: tasks_init at C:/Users/tufan/esp/ble_spp_server/main/main.c:50

0x400d8a50: app_main at C:/Users/tufan/esp/ble_spp_server/main/main.c:29

0x401ae786: main_task at C:/Users/tufan/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/port_common.c:131 (discriminator 2)

0x40092a6d: vPortTaskWrapper at C:/Users/tufan/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:154



at
static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handle, spi_transaction_t *trans_desc)
{
SPI_CHECK(handle != NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);

spi_host_t *host = handle->host;
handle->host becomes 0.

Any help will be highly appreciated.

Sprite
Espressif staff
Espressif staff
Posts: 10596
Joined: Thu Nov 26, 2015 4:08 am

Re: spi master problem

Postby Sprite » Mon Jul 24, 2023 12:55 am

Potentially a buffer overflow in the variable 'above' it.

nouwon
Posts: 7
Joined: Sat Mar 27, 2021 9:23 am

Re: spi master problem

Postby nouwon » Mon Jul 24, 2023 7:29 am

Potentially a buffer overflow in the variable 'above' it.
Do you mean the txBuffer of the transaction?If not will you please clarify it?

Sprite
Espressif staff
Espressif staff
Posts: 10596
Joined: Thu Nov 26, 2015 4:08 am

Re: spi master problem

Postby Sprite » Mon Jul 24, 2023 7:32 am

The spi_device pointer you have is stored in memory somewhere. There's likely some buffer located at a lower address in memory that overflows, overwriting the spi_device pointer. Check where your spi_device pointer is declared in your code, then see if there's a variable declared before that that may be overflowing. Alternatively, attach the entire code and we can take a look.

nouwon
Posts: 7
Joined: Sat Mar 27, 2021 9:23 am

Re: spi master problem

Postby nouwon » Mon Jul 24, 2023 9:42 am

The spi_device pointer you have is stored in memory somewhere. There's likely some buffer located at a lower address in memory that overflows, overwriting the spi_device pointer. Check where your spi_device pointer is declared in your code, then see if there's a variable declared before that that may be overflowing. Alternatively, attach the entire code and we can take a look.
I get this error when trying to reset mcp2517 here is the code

Code: Untitled.c Select all


esp_err_t mcp2517_reset()
{

// Reset device
if (DRV_CANFDSPI_Reset(MCP2517SPI_INDEX_0) != ESP_OK)
{
ESP_LOGE(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_Reset failed: %s\n", __func__, esp_err_to_name(ESP_FAIL));
return ESP_FAIL;
}
else
{
ESP_LOGI(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_Reset successfull: %s\n", __func__, esp_err_to_name(ESP_OK));

}

CAN_OSC_CTRL oscCtrl;
//CAN_OSC_STATUS osc_status;

if (DRV_CANFDSPI_OscillatorControlObjectReset(&oscCtrl) != ESP_OK)
{
ESP_LOGE(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_OscillatorControlObjectReset failed: %s\n", __func__, esp_err_to_name(ESP_FAIL));
return ESP_FAIL;
}
else
{
ESP_LOGI(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_OscillatorControlObjectReset successfull: %s\n", __func__, esp_err_to_name(ESP_OK));
}
oscCtrl.PllEnable = 1;
if (DRV_CANFDSPI_OscillatorControlSet(MCP2517SPI_INDEX_0, oscCtrl) != ESP_OK)
{
ESP_LOGE(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_OscillatorControlSet failed: %s\n", __func__, esp_err_to_name(ESP_FAIL));
return ESP_FAIL;
}
else
{
ESP_LOGI(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_OscillatorControlSet successfull: %s\n", __func__, esp_err_to_name(ESP_OK));
}

// Enable ECC and initialize RAM
if (DRV_CANFDSPI_EccEnable(MCP2517SPI_INDEX_0) != ESP_OK)
{
ESP_LOGE(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_EccEnable failed: %s\n", __func__, esp_err_to_name(ESP_FAIL));
return ESP_FAIL;
}
else{
ESP_LOGI(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_EccEnable successfull: %s\n", __func__, esp_err_to_name(ESP_OK));
}

[b][u][size=150][size=200][size=150][color=#FF0000]if (DRV_CANFDSPI_RamInit(MCP2517SPI_INDEX_0, 0xff) != ESP_OK)[/color][/size][/size][/size][/u][/b]
{
ESP_LOGE(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_RamInit failed: %s\n", __func__, esp_err_to_name(ESP_FAIL));
return ESP_FAIL;
}
else{
ESP_LOGI(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_RamInit successfull: %s\n", __func__, esp_err_to_name(ESP_OK));
}
/* DRV_CANFDSPI_OscillatorStatusGet(MCP2517SPI_INDEX_0, &osc_status);
ets_printf("pll-%d, osc-%d, sclk-%d \r\n", osc_status.PllReady, osc_status.OscReady, osc_status.SclkReady);*/

return ESP_OK;
}
and the log output:
I (1156) spi_master: SPI3: New device added to CS0, effective clock: 13333kHz
I (1166) SPI_CONTROLLER: spi_controller_init spi initialized: ESP_OK
I (1166) SPI_CONTROLLER: mcp2517_reset DRV_CANFDSPI_Reset successfull: ESP_OK
I (1176) SPI_CONTROLLER: mcp2517_reset DRV_CANFDSPI_OscillatorControlObjectReset successfull: ESP_OK
I (1196) SPI_CONTROLLER: mcp2517_reset DRV_CANFDSPI_OscillatorControlSet successfull: ESP_OK
I (1206) SPI_CONTROLLER: mcp2517_reset DRV_CANFDSPI_EccEnable successfull: ESP_OK

Problem occurs in RAMInit

Code: Untitled.c Select all


uint8_t DRV_CANFDSPI_RamInit(CANFDSPI_MODULE_ID index, uint8_t d)
{
uint8_t txd[SPI_DEFAULT_BUFFER_LENGTH];//SPI_DEFAULT_BUFFER_LENGTH=64

uint8_t spiTransferError = 0;


// Prepare data
for (uint8_t k = 0; k < SPI_DEFAULT_BUFFER_LENGTH; k++)
{
txd[k] = d;

}

uint16_t a = cRAMADDR_START;

for (uint8_t k = 0; k < (cRAM_SIZE / SPI_DEFAULT_BUFFER_LENGTH); k++)
{
spiTransferError = DRV_CANFDSPI_WriteByteArray(index, a, txd, SPI_DEFAULT_BUFFER_LENGTH);
if (spiTransferError)
{
return -1;
}
a += SPI_DEFAULT_BUFFER_LENGTH;

}

return spiTransferError;
}

Code: Untitled.c Select all


uint8_t DRV_CANFDSPI_WriteByteArray(CANFDSPI_MODULE_ID index, uint16_t address,
uint8_t *txd, uint16_t nBytes)
{
uint16_t i;
uint16_t spiTransferSize = nBytes + 2;
uint8_t spiTransferError = 0;

// Compose command
spiTransmitBuffer[0] = (uint8_t)((cINSTRUCTION_WRITE << 4) + ((address >> 8) & 0xF));
spiTransmitBuffer[1] = (uint8_t)(address & 0xFF);

// Add data
for (i = 2; i < spiTransferSize; i++)
{
spiTransmitBuffer[i] = txd[i - 2];

}

spiTransferError = SPI_TransferData(spiTransmitBuffer, spiReceiveBuffer, spiTransferSize);


return spiTransferError;
}

Code: Untitled.c Select all


//-----------------------------------------------------------------------------------------------------------------------------------------
esp_err_t SPI_TransferData(const uint8_t *SpiTxData, uint8_t *SpiRxData, uint16_t spiTransferSize)
{
assert(spi_device != NULL);


esp_err_t ret = spi_master_transfer(spi_device, SpiTxData, SpiRxData, spiTransferSize);

return ret;
}

Code: Untitled.c Select all


static esp_err_t spi_master_transfer(spi_device_handle_t spi_device, const uint8_t *SpiTxData, uint8_t *SpiRxData, uint16_t len)
{

spi_transaction_t t;

if (len == 0)
return ESP_FAIL; // no need to send anything
// Zero out the transaction
memset(&t, 0, sizeof(t));
t.length = len * 8; // Len is in bytes, transaction length is in bits.
t.tx_buffer = SpiTxData;




esp_err_t ret = spi_device_transmit(spi_device, &t);

if (ret != ESP_OK)
{
ESP_LOGE(SPI_TAG, "%s spi_device_transmit failed! %s\n", __func__, esp_err_to_name(ESP_FAIL));
return ESP_FAIL;
}

return ESP_OK;
}

Code: Untitled.c Select all


// Porcelain to do one blocking transmission.
esp_err_t SPI_MASTER_ATTR spi_device_transmit(spi_device_handle_t handle, spi_transaction_t *trans_desc)
{
esp_err_t ret;
spi_transaction_t *ret_trans;
// ToDo: check if any spi transfers in flight

ret = spi_device_queue_trans(handle, trans_desc, portMAX_DELAY);

if (ret != ESP_OK)

return ret;

ret = spi_device_get_trans_result(handle, &ret_trans, portMAX_DELAY);
if (ret != ESP_OK)
{
ESP_LOGI(SPI_TAG, "spi_device_get_trans_result%d", ret);
return ret;
};

assert(ret_trans == trans_desc);
return ESP_OK;
}

Code: Untitled.c Select all

esp_err_t SPI_MASTER_ATTR spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait)
{

esp_err_t ret = check_trans_valid(handle, trans_desc);
if (ret != ESP_OK)
return ret;

spi_host_t *host = handle->host;

SPI_CHECK(!spi_bus_device_is_polling(handle), "Cannot queue new transaction while previous polling transaction is not terminated.", ESP_ERR_INVALID_STATE);



/* Even when using interrupt transfer, the CS can only be kept activated if the bus has been
* acquired with `spi_device_acquire_bus()` first. */
if (host->device_acquiring_lock != handle && (trans_desc->flags & SPI_TRANS_CS_KEEP_ACTIVE))
{
return ESP_ERR_INVALID_ARG;
}

spi_trans_priv_t trans_buf;
ret = setup_priv_desc(trans_desc, &trans_buf, (host->bus_attr->dma_enabled));
if (ret != ESP_OK)
return ret;

#ifdef CONFIG_PM_ENABLE
esp_pm_lock_acquire(host->bus_attr->pm_lock);
#endif
// Send to queue and invoke the ISR.

BaseType_t r = xQueueSend(handle->trans_queue, (void *)&trans_buf, ticks_to_wait);
if (!r)
{
ret = ESP_ERR_TIMEOUT;
#ifdef CONFIG_PM_ENABLE
// Release APB frequency lock
esp_pm_lock_release(host->bus_attr->pm_lock);
#endif
goto clean_up;
}

// The ISR will be invoked at correct time by the lock with `spi_bus_intr_enable`.
ret = spi_bus_lock_bg_request(handle->dev_lock);
if (ret != ESP_OK)
{
goto clean_up;
}
return ESP_OK;

clean_up:
uninstall_priv_desc(&trans_buf);
return ret;
}

Code: Untitled.c Select all


static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handle, spi_transaction_t *trans_desc)
{
SPI_CHECK(handle != NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);

spi_host_t *host = handle->host;

const spi_bus_attr_t *bus_attr = host->bus_attr;

...
and down below I declare the spi_device

#include <string.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "rom/ets_sys.h"
#include "esp_system.h"
#include "driver/gpio.h"
#include "spi.h"
#include "driver/spi_master.h"
#include "esp_err.h"
#include "esp_log.h"
#include "mcp2517_defines.h"

#define SPI_TAG "SPI"

#define CAN_SPI_HOST VSPI_HOST
#define DMA_CHAN 2
#define DMA_ENABLED 1

#define SERIAL_CLOCK_SPEED 12500000
#define PIN_NUM_MISO 19
#define PIN_NUM_MOSI 23
#define PIN_NUM_CLK 18
#define PIN_NUM_CS 5

spi_device_handle_t spi_device = NULL;

extern esp_err_t receive_canFrame();
/* Local function prototypes */
static esp_err_t spi_master_init(void);
static esp_err_t spi_master_transfer(spi_device_handle_t spi_device, const uint8_t *SpiTxData, uint8_t *SpiRxData, uint16_t len);
static esp_err_t spi_master_read(uint8_t spiSlaveDeviceIndex, const uint8_t *SpiTxData, uint8_t *SpiRxData, uint16_t len);

//! SPI Initialization

esp_err_t SPI_Initialize(void);

//! SPI Read/Write Transfer
esp_err_t SPI_TransferData(const uint8_t *SpiTxData, uint8_t *SpiRxData, uint16_t spiTransferSize);
esp_err_t SPI_ReadData(uint8_t spiSlaveDeviceIndex, const uint8_t *SpiTxData, uint8_t *SpiRxData, uint16_t spiTransferSize);

nouwon
Posts: 7
Joined: Sat Mar 27, 2021 9:23 am

Re: spi master problem

Postby nouwon » Fri Jul 28, 2023 11:21 am

The problem was that in my case the transfer size should be multiples of 4.
In the above code total transfer size becomes 66 with the addition of 2 command bytes to the 64 bytes of data.
This is not allowed when dma is enbaled.
Case closed.

Who is online

Users browsing this forum: Baidu [Spider], PetalBot, Qwantbot and 4 guests