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
  1. static esp_err_t spi_master_init(void)
  2. {
  3.  
  4.     esp_err_t ret;
  5.  
  6.     spi_bus_config_t buscfg = {
  7.         .miso_io_num = PIN_NUM_MISO,
  8.         .mosi_io_num = PIN_NUM_MOSI,
  9.         .sclk_io_num = PIN_NUM_CLK,
  10.         .quadwp_io_num = -1,
  11.         .quadhd_io_num = -1,
  12.         .max_transfer_sz = SPI_DEFAULT_BUFFER_LENGTH * 8,
  13.  
  14.     };
  15.  
  16.     // SPI mode, representing a pair of (CPOL, CPHA) configuration:
  17.  
  18.     // 0: (0, 0)  1: (0, 1) 2: (1, 0) 3: (1, 1)
  19.  
  20.     spi_device_interface_config_t devcfg = {
  21.         .clock_speed_hz = SERIAL_CLOCK_SPEED, // for mcp2517 serial clock speed must be less or equal half  of sys clock of mcp2517.
  22.         .mode = 0,                            // SPI mode 0
  23.         .spics_io_num = PIN_NUM_CS,           // CS pin
  24.         .queue_size = 1,
  25.         .input_delay_ns = 20,
  26.         .cs_ena_posttrans = 3,
  27.         //.flags= SPI_DEVICE_HALFDUPLEX,
  28.         // We want to be able to queue 7 transactions at a time
  29.         //.pre_cb=can_spi_pre_transfer_callback,  //Specify pre-transfer callback to handle D/C line
  30.     };
  31.  
  32.     // Initialize the SPI bus
  33. #if (defined DMA_ENABLED && DMA_ENABLED)
  34.  
  35.     ret = spi_bus_initialize(CAN_SPI_HOST, &buscfg, DMA_CHAN);
  36.  
  37. #else
  38.     ret = spi_bus_initialize(CAN_SPI_HOST, &buscfg, 0);
  39. #endif
  40.     ESP_ERROR_CHECK(ret);
  41.  
  42.     // Attach the device to the SPI bus
  43.     ret = spi_bus_add_device(CAN_SPI_HOST, &devcfg, &spi_device);
  44.  
  45.     ESP_ERROR_CHECK(ret);
  46.  
  47.     return ret;
  48. }
and I start spi transaction with calling
  1. spi_transaction_t t;
  2.  
  3.     if (len == 0)
  4.         return ESP_FAIL; // no need to send anything
  5.     // Zero out the transaction
  6.     memset(&t, 0, sizeof(t));
  7.     t.length = len * 8; // Len is in bytes, transaction length is in bits.
  8.     t.tx_buffer = SpiTxData;
  9.  
  10.     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.

ESP_Sprite
Posts: 9711
Joined: Thu Nov 26, 2015 4:08 am

Re: spi master problem

Postby ESP_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

ESP_Sprite wrote:
Mon Jul 24, 2023 12:55 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?

ESP_Sprite
Posts: 9711
Joined: Thu Nov 26, 2015 4:08 am

Re: spi master problem

Postby ESP_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

ESP_Sprite wrote:
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.
I get this error when trying to reset mcp2517 here is the code
  1. esp_err_t mcp2517_reset()
  2. {
  3.  
  4.      // Reset device
  5.      if (DRV_CANFDSPI_Reset(MCP2517SPI_INDEX_0) != ESP_OK)
  6.      {
  7.           ESP_LOGE(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_Reset failed: %s\n", __func__, esp_err_to_name(ESP_FAIL));
  8.           return ESP_FAIL;
  9.      }
  10.      else
  11.      {    
  12.           ESP_LOGI(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_Reset successfull: %s\n", __func__, esp_err_to_name(ESP_OK));
  13.          
  14.      }
  15.  
  16.      CAN_OSC_CTRL oscCtrl;
  17.      //CAN_OSC_STATUS osc_status;
  18.  
  19.      if (DRV_CANFDSPI_OscillatorControlObjectReset(&oscCtrl) != ESP_OK)
  20.      {
  21.           ESP_LOGE(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_OscillatorControlObjectReset failed: %s\n", __func__, esp_err_to_name(ESP_FAIL));
  22.           return ESP_FAIL;
  23.      }
  24.      else
  25.      {
  26.           ESP_LOGI(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_OscillatorControlObjectReset successfull: %s\n", __func__, esp_err_to_name(ESP_OK));
  27.      }
  28.      oscCtrl.PllEnable = 1;
  29.      if (DRV_CANFDSPI_OscillatorControlSet(MCP2517SPI_INDEX_0, oscCtrl) != ESP_OK)
  30.      {
  31.           ESP_LOGE(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_OscillatorControlSet failed: %s\n", __func__, esp_err_to_name(ESP_FAIL));
  32.           return ESP_FAIL;
  33.      }
  34.      else
  35.      {
  36.           ESP_LOGI(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_OscillatorControlSet successfull: %s\n", __func__, esp_err_to_name(ESP_OK));
  37.      }
  38.  
  39.      // Enable ECC and initialize RAM
  40.      if (DRV_CANFDSPI_EccEnable(MCP2517SPI_INDEX_0) != ESP_OK)
  41.      {
  42.           ESP_LOGE(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_EccEnable failed: %s\n", __func__, esp_err_to_name(ESP_FAIL));
  43.           return ESP_FAIL;
  44.      }
  45.      else{
  46.           ESP_LOGI(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_EccEnable successfull: %s\n", __func__, esp_err_to_name(ESP_OK));
  47.      }
  48.  
  49.      [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]
  50.      {
  51.           ESP_LOGE(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_RamInit failed: %s\n", __func__, esp_err_to_name(ESP_FAIL));
  52.           return ESP_FAIL;
  53.      }
  54.      else{
  55.           ESP_LOGI(SPI_CONTROLLER_TAG, "%s DRV_CANFDSPI_RamInit successfull: %s\n", __func__, esp_err_to_name(ESP_OK));
  56.      }
  57.      /* DRV_CANFDSPI_OscillatorStatusGet(MCP2517SPI_INDEX_0, &osc_status);
  58.       ets_printf("pll-%d, osc-%d, sclk-%d \r\n", osc_status.PllReady, osc_status.OscReady, osc_status.SclkReady);*/
  59.  
  60.      return ESP_OK;
  61. }
  62.  
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
  1. uint8_t DRV_CANFDSPI_RamInit(CANFDSPI_MODULE_ID index, uint8_t d)
  2. {
  3.     uint8_t txd[SPI_DEFAULT_BUFFER_LENGTH];//SPI_DEFAULT_BUFFER_LENGTH=64
  4.    
  5.     uint8_t spiTransferError = 0;
  6.  
  7.    
  8.     // Prepare data
  9.     for (uint8_t k = 0; k < SPI_DEFAULT_BUFFER_LENGTH; k++)
  10.     {
  11.         txd[k] = d;
  12.        
  13.     }
  14.  
  15.     uint16_t a = cRAMADDR_START;
  16.  
  17.     for (uint8_t k = 0; k < (cRAM_SIZE / SPI_DEFAULT_BUFFER_LENGTH); k++)
  18.     {
  19.         spiTransferError = DRV_CANFDSPI_WriteByteArray(index, a, txd, SPI_DEFAULT_BUFFER_LENGTH);
  20.         if (spiTransferError)
  21.         {
  22.             return -1;
  23.         }
  24.         a += SPI_DEFAULT_BUFFER_LENGTH;
  25.        
  26.     }
  27.  
  28.     return spiTransferError;
  29. }
  1. uint8_t DRV_CANFDSPI_WriteByteArray(CANFDSPI_MODULE_ID index, uint16_t address,
  2.                                     uint8_t *txd, uint16_t nBytes)
  3. {
  4.     uint16_t i;
  5.     uint16_t spiTransferSize = nBytes + 2;
  6.     uint8_t spiTransferError = 0;
  7.  
  8.     // Compose command
  9.     spiTransmitBuffer[0] = (uint8_t)((cINSTRUCTION_WRITE << 4) + ((address >> 8) & 0xF));
  10.     spiTransmitBuffer[1] = (uint8_t)(address & 0xFF);
  11.    
  12.     // Add data
  13.     for (i = 2; i < spiTransferSize; i++)
  14.     {
  15.         spiTransmitBuffer[i] = txd[i - 2];
  16.        
  17.     }
  18.  
  19.     spiTransferError = SPI_TransferData(spiTransmitBuffer, spiReceiveBuffer, spiTransferSize);
  20.    
  21.  
  22.     return spiTransferError;
  23. }
  1. //-----------------------------------------------------------------------------------------------------------------------------------------
  2. esp_err_t SPI_TransferData(const uint8_t *SpiTxData, uint8_t *SpiRxData, uint16_t spiTransferSize)
  3. {
  4.     assert(spi_device != NULL);
  5.    
  6.    
  7.     esp_err_t ret = spi_master_transfer(spi_device, SpiTxData, SpiRxData, spiTransferSize);
  8.  
  9.     return ret;
  10. }
  1. static esp_err_t spi_master_transfer(spi_device_handle_t spi_device, const uint8_t *SpiTxData, uint8_t *SpiRxData, uint16_t len)
  2. {
  3.  
  4.     spi_transaction_t t;
  5.  
  6.     if (len == 0)
  7.         return ESP_FAIL; // no need to send anything
  8.     // Zero out the transaction
  9.     memset(&t, 0, sizeof(t));
  10.     t.length = len * 8; // Len is in bytes, transaction length is in bits.
  11.     t.tx_buffer = SpiTxData;
  12.    
  13.    
  14.    
  15.    
  16.     esp_err_t ret = spi_device_transmit(spi_device, &t);
  17.  
  18.     if (ret != ESP_OK)
  19.     {
  20.         ESP_LOGE(SPI_TAG, "%s spi_device_transmit failed! %s\n", __func__, esp_err_to_name(ESP_FAIL));
  21.         return ESP_FAIL;
  22.     }
  23.  
  24.     return ESP_OK;
  25. }
  1. // Porcelain to do one blocking transmission.
  2. esp_err_t SPI_MASTER_ATTR spi_device_transmit(spi_device_handle_t handle, spi_transaction_t *trans_desc)
  3. {
  4.     esp_err_t ret;
  5.     spi_transaction_t *ret_trans;
  6.     // ToDo: check if any spi transfers in flight
  7.    
  8.     ret = spi_device_queue_trans(handle, trans_desc, portMAX_DELAY);
  9.    
  10.     if (ret != ESP_OK)
  11.  
  12.         return ret;
  13.  
  14.     ret = spi_device_get_trans_result(handle, &ret_trans, portMAX_DELAY);
  15.     if (ret != ESP_OK)
  16.     {
  17.         ESP_LOGI(SPI_TAG, "spi_device_get_trans_result%d", ret);
  18.         return ret;
  19.     };
  20.  
  21.     assert(ret_trans == trans_desc);
  22.     return ESP_OK;
  23. }
  1. 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)
  2. {
  3.    
  4.     esp_err_t ret = check_trans_valid(handle, trans_desc);
  5.     if (ret != ESP_OK)
  6.         return ret;
  7.  
  8.     spi_host_t *host = handle->host;
  9.  
  10.     SPI_CHECK(!spi_bus_device_is_polling(handle), "Cannot queue new transaction while previous polling transaction is not terminated.", ESP_ERR_INVALID_STATE);
  11.  
  12.  
  13.  
  14.     /* Even when using interrupt transfer, the CS can only be kept activated if the bus has been
  15.      * acquired with `spi_device_acquire_bus()` first. */
  16.     if (host->device_acquiring_lock != handle && (trans_desc->flags & SPI_TRANS_CS_KEEP_ACTIVE))
  17.     {
  18.         return ESP_ERR_INVALID_ARG;
  19.     }
  20.  
  21.     spi_trans_priv_t trans_buf;
  22.     ret = setup_priv_desc(trans_desc, &trans_buf, (host->bus_attr->dma_enabled));
  23.     if (ret != ESP_OK)
  24.         return ret;
  25.  
  26. #ifdef CONFIG_PM_ENABLE
  27.     esp_pm_lock_acquire(host->bus_attr->pm_lock);
  28. #endif
  29.     // Send to queue and invoke the ISR.
  30.  
  31.     BaseType_t r = xQueueSend(handle->trans_queue, (void *)&trans_buf, ticks_to_wait);
  32.     if (!r)
  33.     {
  34.         ret = ESP_ERR_TIMEOUT;
  35. #ifdef CONFIG_PM_ENABLE
  36.         // Release APB frequency lock
  37.         esp_pm_lock_release(host->bus_attr->pm_lock);
  38. #endif
  39.         goto clean_up;
  40.     }
  41.  
  42.     // The ISR will be invoked at correct time by the lock with `spi_bus_intr_enable`.
  43.     ret = spi_bus_lock_bg_request(handle->dev_lock);
  44.     if (ret != ESP_OK)
  45.     {
  46.         goto clean_up;
  47.     }
  48.     return ESP_OK;
  49.  
  50. clean_up:
  51.     uninstall_priv_desc(&trans_buf);
  52.     return ret;
  53. }
  1. static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handle, spi_transaction_t *trans_desc)
  2. {
  3.     SPI_CHECK(handle != NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
  4.      
  5.     spi_host_t *host = handle->host;
  6.    
  7.     const spi_bus_attr_t *bus_attr = host->bus_attr;
  8.  
  9. ...
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: No registered users and 88 guests