Issue with SPI Communication between ESP32C3 and MCP3461: MISO Problem with Espressif's spi_master Library

at-cirillo
Posts: 2
Joined: Fri Jul 21, 2023 12:53 pm

Issue with SPI Communication between ESP32C3 and MCP3461: MISO Problem with Espressif's spi_master Library

Postby at-cirillo » Fri Jul 21, 2023 1:06 pm

I am trying to build an SPI communication between an ESP32C3 and the analog-to-digital converter MCP3461 (https://www.microchip.com/content/dam/m ... 06404C.pdf). For some reason, my MISO line doesn't behave as expected when using the spi_master library from IDF (Espressif).

According to the converter's datasheet, the communication should be as follows:
Pasted image 20230721093137.png
Pasted image 20230721093137.png (61.84 KiB) Viewed 989 times
Essentially, I send a command via MOSI(SDI), and MISO(SDO) returns an acknowledgment from the converter (the process is similar for reading). I managed to achieve this using Arduino's SPI libraries and compiling it for my ESP32C3:
  1. #include <MCP3461.h> //ADC
  2. #define SLAVE_SELECT_PIN 0
  3.  
  4. MCP3461class device1(SLAVE_SELECT_PIN);
  5.  
  6. void setup() {
  7.   Serial.begin(115200); // start Serial communication
  8.   SPI.begin(1, 3, 2, 0); // start SPI communication
  9.   Serial.println("Hello");
  10.   MCP3461_INIT(device1); // run sensor initialization
  11. }
  12.  
  13.  
  14. void loop() {
  15.   Read_MCP3461(device1,voltage);
  16.   Serial.println("");
  17.   delay( 1000 ); // Slow down sampling to 10 Hz. This is just a test.
  18. }
  19.  
  20.  
  21. void MCP3461_INIT(MCP3461class A2D){ //initalise A2D for Voltage measurement
  22.   Serial.println("initialising MCP3461");
  23.   A2D.beginMCP3461();
  24.   A2D.writeMCP3461 (RESET, 0xFF);   //Resets the part for initial use
  25.   delay(100);
  26. }
  27.  
  28.  
  29. void Read_MCP3461(MCP3461class A2D, float &voltage){
  30.   A2D.writeMCP3461 (LOCK, 0xA5); //WRITE LOCK WITH PASSWORD
  31.   int16_t lock_value = A2D.readMCP3461(LOCK); //CHECK IF UNLOCKED
  32.  
  33.   Serial.print("Lock value: ");
  34.   Serial.println(lock_value);
  35. }
In the Arduino setup, it communicates perfectly, and when observing the signals on the oscilloscope, the communication is as expected:
Pasted image 20230720130825.png
Pasted image 20230720130825.png (158.36 KiB) Viewed 989 times
But, for some reason, when trying to use the spi_master library from Espressif to build the communication, the first phase of MISO (which passes the acknowledgment and status bits) does not work correctly. The high signals work well, but for some strange reason, during the low signals, the MISO line stays at around 2.4V, neither high nor low. The most confusing part is that the second phase of MISO during the read operation, which shows the value in a register, works perfectly, and I can read the value in my code:
Pasted image 20230720134106.png
Pasted image 20230720134106.png (150.39 KiB) Viewed 989 times
  1. #include <stdio.h>
  2. #include "freertos/FreeRTOS.h"
  3. #include "freertos/task.h"
  4. #include "driver\spi_master.h"
  5. #include "driver\gpio.h"
  6. #include "esp_log.h"
  7.  
  8. #define CS GPIO_NUM_0
  9. #define SCLK GPIO_NUM_1
  10. #define MOSI GPIO_NUM_2
  11. #define MISO GPIO_NUM_3
  12.  
  13. //ADC registers
  14. #define LOCK 0xD
  15.  
  16. #define DEVICE_ADDR 0x1
  17.  
  18. //Commands
  19. #define STATIC_READ 0x1
  20. #define WRITE 0x2
  21. #define READ 0x3
  22.  
  23. void write (uint8_t ui8address, uint8_t ui8value, spi_device_handle_t spi_settings){    
  24.     esp_err_t err;
  25.     err = spi_device_acquire_bus(spi_settings, portMAX_DELAY);
  26.     ESP_ERROR_CHECK(err);
  27.  
  28.     spi_transaction_t t = {
  29.         .cmd = DEVICE_ADDR << 6 | ui8address << 2 | WRITE,
  30.         .length = 8,
  31.         .flags = SPI_TRANS_USE_TXDATA,
  32.         .tx_data = {ui8value},
  33.     };
  34.  
  35.     err = spi_device_polling_transmit(spi_settings, &t);
  36.     ESP_ERROR_CHECK(err);
  37.     ESP_LOGI("WRITE", "%#02X at %#02X", ui8value, ui8address);
  38.    
  39.     spi_device_release_bus(spi_settings);
  40. }
  41. uint32_t read (uint8_t ui8address, spi_device_handle_t spi_settings){
  42.         spi_transaction_t t = {
  43.             .cmd = DEVICE_ADDR << 6 | ui8address << 2 | STATIC_READ,
  44.             .rxlength = 8,
  45.             .flags = SPI_TRANS_USE_RXDATA,
  46.         };
  47.         esp_err_t err = spi_device_polling_transmit(spi_settings, &t);
  48.         ESP_ERROR_CHECK(err);
  49.         ESP_LOGI("READ", "%#02X from %#02X", t.rx_data[0], ui8address);
  50.        
  51.         return t.rx_data[0];
  52. }
  53.  
  54. void pin_config(gpio_num_t pin){
  55.     gpio_reset_pin(pin);
  56.     gpio_set_direction(pin, GPIO_MODE_INPUT_OUTPUT);
  57.     gpio_set_intr_type(pin, GPIO_INTR_DISABLE);
  58.     gpio_set_pull_mode(pin, GPIO_PULLDOWN_ONLY);
  59. }
  60.  
  61. static void cs_high(spi_transaction_t* t){
  62.     gpio_set_level(CS, 1);
  63. }
  64.  
  65. static void cs_low(spi_transaction_t* t){
  66.     gpio_set_level(CS, 0);
  67. }
  68.  
  69.  
  70. void app_main(void){
  71.     ESP_LOGI("main", "Hello World!");
  72.    
  73.     //reseting pins and preparing for usage
  74.     pin_config(CS);
  75.     pin_config(SCLK);
  76.     pin_config(MOSI);
  77.     //? config MISO
  78.     gpio_reset_pin(MISO);
  79.     gpio_set_direction(MISO, GPIO_MODE_INPUT); //TESTED IT FOR INPUT AND OUTPUT
  80.     gpio_set_pull_mode(MISO, GPIO_PULLUP_ONLY); //TESTED IT FOR PULLUP AND PULLDOWN
  81.  
  82.     //INITIALIZING SPI
  83.     spi_bus_config_t buscfg = {
  84.         .mosi_io_num = MOSI,
  85.         .miso_io_num = MISO,
  86.         .sclk_io_num = SCLK,
  87.         .quadwp_io_num = -1,
  88.         .quadhd_io_num = -1,
  89.         .max_transfer_sz = SPI_MAX_DMA_LEN,
  90.     };
  91.  
  92.     esp_err_t err = spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);
  93.     ESP_ERROR_CHECK(err);
  94.     ESP_LOGI("main", "SPI bus succesfully initialized");
  95.  
  96.     //init MCP3461
  97.     spi_device_handle_t _spi_settings;
  98.     spi_device_interface_config_t devcfg={
  99.         .command_bits = 8,
  100.         .mode = 0,
  101.         .clock_speed_hz = 1 * 1000 * 1000, //1MHz clock
  102.         .spics_io_num = -1,
  103.         .queue_size = 1,
  104.         .flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_POSITIVE_CS,
  105.         .post_cb = cs_high,
  106.         .pre_cb = cs_low,
  107.     };
  108.     err = spi_bus_add_device(SPI2_HOST, &devcfg, &_spi_settings);
  109.     ESP_ERROR_CHECK(err);
  110.     ESP_LOGI("main", "MCP3461 successfully initialized");
  111.    
  112.     for (;;){
  113.         write(LOCK, 0xA5, _spi_settings);
  114.         read(LOCK, _spi_settings);
  115.         vTaskDelay(1000/portTICK_RATE_MS);
  116.     }
  117. }
I've tried different configurations for the pins and the SPI interface, but it seems there is an issue in the first phase of the communication. What could be causing this problem?

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

Re: Issue with SPI Communication between ESP32C3 and MCP3461: MISO Problem with Espressif's spi_master Library

Postby ESP_Sprite » Sun Jul 23, 2023 12:48 am

That is very odd. I can't see an immediate explanation for this. Just to double-check: the hardware is exactly the same, right?

at-cirillo
Posts: 2
Joined: Fri Jul 21, 2023 12:53 pm

Re: Issue with SPI Communication between ESP32C3 and MCP3461: MISO Problem with Espressif's spi_master Library

Postby at-cirillo » Mon Jul 24, 2023 4:12 pm

ESP_Sprite wrote:
Sun Jul 23, 2023 12:48 am
That is very odd. I can't see an immediate explanation for this. Just to double-check: the hardware is exactly the same, right?
Yes, exactly same hardware. Didn't even unplug it from my computer before changing codes

wanckl
Posts: 2
Joined: Mon Sep 11, 2023 8:24 am

Re: Issue with SPI Communication between ESP32C3 and MCP3461: MISO Problem with Espressif's spi_master Library

Postby wanckl » Mon Sep 11, 2023 9:00 am

I don't know how Arduino implement your transaction, But from your ADC chips datasheet, if you need check the "ack" phases, it seems actually a full-duplex communication, at least in the "cmd-ack" section, means you need perform them in same transaction so that they are same time.
So you shouldn't set "SPI_DEVICE_HALFDUPLEX" for device flag, and you can config "CS_PIN" into device config, driver will also config CS_PIN for you, otherwise, "SPI_DEVICE_POSITIVE_CS" can also removed if you control CS by your self (or by callbacks).
then combination a full-duplex write & read phase by you self.

But otherwise, seems you can just send cmd but ignore the ack from ADC chip and it still work OK ? :D

Who is online

Users browsing this forum: wxd2024 and 156 guests