Issue with SPI Communication between ESP32C3 and MCP3461: MISO Problem with Espressif's spi_master Library
Posted: 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: 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:
In the Arduino setup, it communicates perfectly, and when observing the signals on the oscilloscope, the communication is as expected:
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:
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?
According to the converter's datasheet, the communication should be as follows: 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:
- #include <MCP3461.h> //ADC
- #define SLAVE_SELECT_PIN 0
- MCP3461class device1(SLAVE_SELECT_PIN);
- void setup() {
- Serial.begin(115200); // start Serial communication
- SPI.begin(1, 3, 2, 0); // start SPI communication
- Serial.println("Hello");
- MCP3461_INIT(device1); // run sensor initialization
- }
- void loop() {
- Read_MCP3461(device1,voltage);
- Serial.println("");
- delay( 1000 ); // Slow down sampling to 10 Hz. This is just a test.
- }
- void MCP3461_INIT(MCP3461class A2D){ //initalise A2D for Voltage measurement
- Serial.println("initialising MCP3461");
- A2D.beginMCP3461();
- A2D.writeMCP3461 (RESET, 0xFF); //Resets the part for initial use
- delay(100);
- }
- void Read_MCP3461(MCP3461class A2D, float &voltage){
- A2D.writeMCP3461 (LOCK, 0xA5); //WRITE LOCK WITH PASSWORD
- int16_t lock_value = A2D.readMCP3461(LOCK); //CHECK IF UNLOCKED
- Serial.print("Lock value: ");
- Serial.println(lock_value);
- }
- #include <stdio.h>
- #include "freertos/FreeRTOS.h"
- #include "freertos/task.h"
- #include "driver\spi_master.h"
- #include "driver\gpio.h"
- #include "esp_log.h"
- #define CS GPIO_NUM_0
- #define SCLK GPIO_NUM_1
- #define MOSI GPIO_NUM_2
- #define MISO GPIO_NUM_3
- //ADC registers
- #define LOCK 0xD
- #define DEVICE_ADDR 0x1
- //Commands
- #define STATIC_READ 0x1
- #define WRITE 0x2
- #define READ 0x3
- void write (uint8_t ui8address, uint8_t ui8value, spi_device_handle_t spi_settings){
- esp_err_t err;
- err = spi_device_acquire_bus(spi_settings, portMAX_DELAY);
- ESP_ERROR_CHECK(err);
- spi_transaction_t t = {
- .cmd = DEVICE_ADDR << 6 | ui8address << 2 | WRITE,
- .length = 8,
- .flags = SPI_TRANS_USE_TXDATA,
- .tx_data = {ui8value},
- };
- err = spi_device_polling_transmit(spi_settings, &t);
- ESP_ERROR_CHECK(err);
- ESP_LOGI("WRITE", "%#02X at %#02X", ui8value, ui8address);
- spi_device_release_bus(spi_settings);
- }
- uint32_t read (uint8_t ui8address, spi_device_handle_t spi_settings){
- spi_transaction_t t = {
- .cmd = DEVICE_ADDR << 6 | ui8address << 2 | STATIC_READ,
- .rxlength = 8,
- .flags = SPI_TRANS_USE_RXDATA,
- };
- esp_err_t err = spi_device_polling_transmit(spi_settings, &t);
- ESP_ERROR_CHECK(err);
- ESP_LOGI("READ", "%#02X from %#02X", t.rx_data[0], ui8address);
- return t.rx_data[0];
- }
- void pin_config(gpio_num_t pin){
- gpio_reset_pin(pin);
- gpio_set_direction(pin, GPIO_MODE_INPUT_OUTPUT);
- gpio_set_intr_type(pin, GPIO_INTR_DISABLE);
- gpio_set_pull_mode(pin, GPIO_PULLDOWN_ONLY);
- }
- static void cs_high(spi_transaction_t* t){
- gpio_set_level(CS, 1);
- }
- static void cs_low(spi_transaction_t* t){
- gpio_set_level(CS, 0);
- }
- void app_main(void){
- ESP_LOGI("main", "Hello World!");
- //reseting pins and preparing for usage
- pin_config(CS);
- pin_config(SCLK);
- pin_config(MOSI);
- //? config MISO
- gpio_reset_pin(MISO);
- gpio_set_direction(MISO, GPIO_MODE_INPUT); //TESTED IT FOR INPUT AND OUTPUT
- gpio_set_pull_mode(MISO, GPIO_PULLUP_ONLY); //TESTED IT FOR PULLUP AND PULLDOWN
- //INITIALIZING SPI
- spi_bus_config_t buscfg = {
- .mosi_io_num = MOSI,
- .miso_io_num = MISO,
- .sclk_io_num = SCLK,
- .quadwp_io_num = -1,
- .quadhd_io_num = -1,
- .max_transfer_sz = SPI_MAX_DMA_LEN,
- };
- esp_err_t err = spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);
- ESP_ERROR_CHECK(err);
- ESP_LOGI("main", "SPI bus succesfully initialized");
- //init MCP3461
- spi_device_handle_t _spi_settings;
- spi_device_interface_config_t devcfg={
- .command_bits = 8,
- .mode = 0,
- .clock_speed_hz = 1 * 1000 * 1000, //1MHz clock
- .spics_io_num = -1,
- .queue_size = 1,
- .flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_POSITIVE_CS,
- .post_cb = cs_high,
- .pre_cb = cs_low,
- };
- err = spi_bus_add_device(SPI2_HOST, &devcfg, &_spi_settings);
- ESP_ERROR_CHECK(err);
- ESP_LOGI("main", "MCP3461 successfully initialized");
- for (;;){
- write(LOCK, 0xA5, _spi_settings);
- read(LOCK, _spi_settings);
- vTaskDelay(1000/portTICK_RATE_MS);
- }
- }