Skip to content

SPI commands hang on SPI_PARAM_LOCK() #7556

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
stuartpittaway opened this issue Dec 6, 2022 · 5 comments
Closed
1 task done

SPI commands hang on SPI_PARAM_LOCK() #7556

stuartpittaway opened this issue Dec 6, 2022 · 5 comments

Comments

@stuartpittaway
Copy link

stuartpittaway commented Dec 6, 2022

Board

ESP32 DEVKITC

Device Description

DevKITC ESP32 module running on custom PCB for DIYBMS controller.

Hardware Configuration

VSPI port being used on pins GPIO18(CLK), GPIO19(MISO), GPIO23 (MOSI) and GPIO4 CS

This communicates with XPT2046 touch screen controller.

Version

v2.0.5

IDE Name

PlatformIO

Operating System

Windows 10

Flash frequency

40M

PSRAM enabled

yes

Upload speed

921000

Description

This is existing code which has worked (and still works) on v2.0.3 Arduino ESP32 framework.

On 2.0.4 and 2.0.5, the code hangs when calling beginTransaction on the VSPI bus.

This appears to be caused by an infinite loop when calling the macro SPI_PARAM_LOCK() which attempts to obtain a semaphore (xSemaphoreTake)

If I add #define CONFIG_DISABLE_HAL_LOCKS 1 to the top of the debug sketch provided - the code works as expected, and no longer hangs.

This appears to be related to the code added in issue #6425

I'm using this framework library reference in my platformio.ini file

platform_packages =
   framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.5

Sketch

#define USE_ESP_IDF_LOG 1
static constexpr const char *const TAG = "vspi";
#include <Arduino.h>
#include <SPI.h>
#include "esp_log.h"

SPIClass vspi;

#define TOUCH_CHIPSELECT GPIO_NUM_4

struct TouchScreenValues
{
  bool touched;
  uint8_t pressure;
  uint16_t X;
  uint16_t Y;
};


void setup()
{
  esp_log_level_set(TAG, esp_log_level_t::ESP_LOG_DEBUG);
  Serial.begin(115200, SERIAL_8N1);
  ESP_LOGD(TAG, "Configure VSPI");
  vspi = SPIClass(VSPI);

  // Don't use hardware chip selects on VSPI
  vspi.setHwCs(false);
  vspi.setBitOrder(MSBFIRST);
  vspi.setDataMode(SPI_MODE0);
  // 10mhz
  vspi.setFrequency(10000000);

  // GPIO18(CLK), GPIO19(MISO), GPIO23 (MOSI)
  // and normally GPIO5 (CS) - although not used on my board replaced with GPIO4
  vspi.begin(GPIO_NUM_18, GPIO_NUM_19, GPIO_NUM_23, TOUCH_CHIPSELECT);

  pinMode(TOUCH_CHIPSELECT,OUTPUT);

  ESP_LOGD(TAG, "end of setup");
}
TouchScreenValues TouchScreenUpdate()
{
  /*
      Features and Specification of XPT2046
      https://components101.com/admin/sites/default/files/component_datasheet/XPT2046-Datasheet.pdf
  */
  // Z is touch (depth)
  const uint8_t ADD_Z1 = 0B00110000;
  const uint8_t ADD_Z2 = 0B01000000;
  const uint8_t ADD_X = 0B00010000;
  const uint8_t ADD_Y = 0B01010000;
  const uint8_t STARTBIT = 0B10000000;
  const uint8_t PWR_ALLOFF = 0B00000000;
  const uint8_t PWR_REFOFF_ADCON = 0B00000001;
  const uint8_t ADC_DIFFERENTIAL = 0B00000000;

  const uint8_t ADC_8BIT = 0B00001000;
  const uint8_t ADC_12BIT = 0B00000000;

  TouchScreenValues reply;
  reply.touched = false;
  reply.pressure = 0;
  reply.X = 0;
  reply.Y = 0;

  ESP_LOGD(TAG, "1");
  // *** CODE HANGS ON THIS CALL ****
  vspi.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
  ESP_LOGD(TAG, "2");

  digitalWrite(TOUCH_CHIPSELECT, LOW);
  ESP_LOGD(TAG, "3");

  // We don't need accurate touch pressure for this application, so
  // only read Z2 register, we just want a boolean value at the end of the day

  // The transfers are always a step behind, so the transfer reads the previous value/command
  vspi.write(STARTBIT | PWR_REFOFF_ADCON | ADC_8BIT | ADC_DIFFERENTIAL | ADD_Z1);
  ESP_LOGD(TAG, "4");

  // Read Z2 (1 byte) and request X
  reply.pressure = vspi.transfer(STARTBIT | PWR_REFOFF_ADCON | ADC_12BIT | ADC_DIFFERENTIAL | ADD_X);
  ESP_LOGD(TAG, "5");

  // Read X (2 bytes) and request Y
  reply.X = vspi.transfer16(STARTBIT | PWR_REFOFF_ADCON | ADC_12BIT | ADC_DIFFERENTIAL | ADD_Y) >> 3;
  ESP_LOGD(TAG, "6");
  // Take Y reading, then power down after this sample
  reply.Y = vspi.transfer16(STARTBIT | PWR_ALLOFF | ADC_8BIT | ADC_DIFFERENTIAL | ADD_Z2) >> 3;
  ESP_LOGD(TAG, "7");

  // Final transfer to ensure device goes into sleep
  // In order to turn the reference off, an additional write to the XPT2046 is required after the channel has been converted.  Page 24 datasheet
  // uint16_t Z2 =
  vspi.transfer(0);
  ESP_LOGD(TAG, "8");

  digitalWrite(TOUCH_CHIPSELECT, HIGH);
  vspi.endTransaction();

  reply.touched = reply.pressure > 135 && reply.X > 0;
  ESP_LOGI(TAG, "Touch = touch=%i pressure=%u x=%u y=%u", reply.touched, reply.pressure, reply.X, reply.Y);
  return reply;
}

void loop()
{
  ESP_LOGD(TAG, "Loop");
  TouchScreenUpdate();
  delay(5000);
}

Debug Message

No error message - code hangs.

The debug output gets as far as outputting "1" to console.

Other Steps to Reproduce

Tested 2.0.4 and 2.0.5 both fail. 2.0.3 works.

I have checked existing issues, online documentation and the Troubleshooting Guide

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.
@stuartpittaway stuartpittaway added the Status: Awaiting triage Issue is waiting for triage label Dec 6, 2022
@me-no-dev
Copy link
Member

In global you should have SPIClass vspi(VSPI); instead of just SPIClass vspi; and then in setup() you should delete vspi = SPIClass(VSPI);. Try with that first

@mrengineer7777
Copy link
Collaborator

For the pre-compiled libraries in arduino-esp32, sdkconfig.h already disables HAL locks. #define CONFIG_DISABLE_HAL_LOCKS 1.
Are you using Arduino as an IDF component?

Looking at PR 6425, SPI.h has #include "freertos/FreeRTOS.h", which brings in sdkconfig.h. Thus SPI_PARAM_LOCK() should do nothing.

@VojtechBartoska VojtechBartoska added the Type: Question Only question label Dec 8, 2022
@stuartpittaway
Copy link
Author

stuartpittaway commented Dec 8, 2022

Thank you @me-no-dev using SPIClass vspi(VSPI); instead of creating an instance in the setup() function now works.

However, the original code was the way it was as it was wrapped inside a class (hardware abstraction layer), so the SPIClass was created dynamically.

This might be worth noting for future reference, as this is a change in behaviour between 2.0.3 and newer .4 and .5 versions.

Other people may run into similar issues.

@me-no-dev
Copy link
Member

@stuartpittaway it is worth looking into. Change of behavior comes probably from this change. At the same time, properly specifying which SPI bus you will use in the global is the correct way, even though it worked before.

@VojtechBartoska
Copy link
Contributor

@stuartpittaway Can this be considered as answered?

@VojtechBartoska VojtechBartoska added Resolution: Awaiting response Waiting for response of author and removed Status: Awaiting triage Issue is waiting for triage labels Feb 16, 2023
@VojtechBartoska VojtechBartoska added Status: Solved and removed Resolution: Awaiting response Waiting for response of author labels Feb 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants