espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.72k stars 7.3k forks source link

SPI example and docs provides no clues on receiving; received data shifted 1bit right (IDFGH-559) #2948

Open mtmsweb opened 5 years ago

mtmsweb commented 5 years ago

Example code provides no clues on how to receive anything from SPI device. Each my try point me to the conclusion that driver doesnt work properly or there is no enough informations to use it. I am trying to test SPI device by sending configuration and than reading configuration register. Code looks like below.

while (1) {
    spi_device_handle_t spi;
    spi_bus_config_t buscfg = {
        .miso_io_num=PIN_NUM_SPI_MISO,
        .mosi_io_num=PIN_NUM_SPI_MOSI,
        .sclk_io_num=PIN_NUM_SPI_CLK,
        .quadwp_io_num=-1, .quadhd_io_num=-1,
    };
    spi_device_interface_config_t devcfg = {
        .spics_io_num=PIN_NUM_SPI_ADC_CS,
        .clock_speed_hz=1*1000*1000, // 1MHz
        .mode=1, // SPI MODE 1
        .command_bits=8, // 8-bit command length
        .address_bits=0, // no address
        .queue_size=2,
    };
    // should I use DMA? Does it work?
    ESP_ERROR_CHECK(spi_bus_initialize(VSPI_HOST, &buscfg, 0/*dma_chan - 0 no DMA*/));
    ESP_ERROR_CHECK(spi_bus_add_device(VSPI_HOST, &devcfg, &spi));

    // how to declare rx_data buffer for DMA usage?
    uint8_t rx_data[10];
    memset(rx_data, 0x00, sizeof(rx_data));

    ESP_LOGE(TAG, "write RESET");
    spi_transaction_t transaction;
    memset(&transaction, 0, sizeof(transaction));
    transaction.cmd = RESET;
    assert(spi_device_polling_transmit(spi, &transaction) == ESP_OK);
    vTaskDelay(1 / portTICK_RATE_MS);

    ESP_LOGE(TAG, "writeDefaultConfig");
    uint8_t data[4] = {DEFAULT_CONFIG_REG0, DEFAULT_CONFIG_REG1, DEFAULT_CONFIG_REG2, DEFAULT_CONFIG_REG3};
    memset(&transaction, 0, sizeof(transaction));
    transaction.cmd = WREG | 0b0000;
    transaction.length = 4*8;
    transaction.tx_buffer = data;
    assert(spi_device_polling_transmit(spi, &transaction) == ESP_OK);

    ESP_LOGE(TAG, "read RREG");
    memset(&transaction, 0, sizeof(transaction));
    transaction.cmd = RREG | 0b0000;
    transaction.rx_buffer = rx_data;
    transaction.rxlength = 4*8;
    // should I set .length equal .rxlength? Does .length count .cmd bytes?
    transaction.length = 4*8; 
    assert(spi_device_polling_transmit(spi, &transaction) == ESP_OK);
    ESP_LOG_BUFFER_HEX("Received", rx_data, 10 );

    memset(rx_data, 0x00, sizeof(rx_data));

    ESP_LOGE(TAG, "read single register");
    uint8_t address = 1;
    memset(&transaction, 0, sizeof(transaction));
    transaction.cmd = RREG | (address<<2);
    transaction.rx_buffer = rx_data;
    transaction.rxlength = 8;
    transaction.length = 8;
    assert(spi_device_polling_transmit(spi, &transaction) == ESP_OK);
    ESP_LOG_BUFFER_HEX("Received", rx_data, 10 );

    ESP_LOGE(TAG, "End");
    spi_bus_remove_device(spi);
    vTaskDelay(2500 / portTICK_RATE_MS);
}

Unfortunately code doesnt work. Random bytes are printed from rx_data. Please point me right track for a solution. There are some, important for me, questions in code comments.

EDIT: Received bytes seems to be not random values but valid values shifted one bit right (0x03 is 0x81 and next byte is 0x80)

ginkgm commented 5 years ago

Hi @mtmsweb , Could you provide the timing diagram of the slave device you are communicating with? The mode should met the timing of the slave. Maybe you can try mode 0 by setting the mode field to 0 in the spi_device_interface_config_t config structure. Mode 0 read and writes half a clock earlier than mode 1.

mtmsweb commented 5 years ago

Slave device is TI's ADC- ADS1220. Datasheet link: http://www.ti.com/lit/ds/symlink/ads1220.pdf Timing about page 38. As I said (edit:or wanted to say) changing mode and even adding .input_delay_ns changes nothing. In each mode I receive same (shifted) data. I got two codes one in arduino (that works- bits are not shifted), one in esp-idf (bites shifted): Arduino:

#include <SPI.h>

#define DEFAULT_CONFIG_REG0 0b00000000
#define DEFAULT_CONFIG_REG1 0b00000000
#define DEFAULT_CONFIG_REG2 0b00000000
#define DEFAULT_CONFIG_REG3 0b00000000

#define ADS1220_CS_PIN    5
#define WREG  0x40
#define RREG  0x20
#define SPI_MASTER_DUMMY    0xFF

void writeSingleRegister(uint8_t address, const uint8_t value) {
  digitalWrite(ADS1220_CS_PIN, LOW);
  SPI.transfer(WREG | (address<<2));
  SPI.transfer(value);
  digitalWrite(ADS1220_CS_PIN,HIGH);
}
uint8_t readRegister(uint8_t address) {
    uint8_t data;
    digitalWrite(ADS1220_CS_PIN,LOW);
    SPI.transfer(RREG|(address<<2));
    data = SPI.transfer(SPI_MASTER_DUMMY);
    digitalWrite(ADS1220_CS_PIN,HIGH);
    return data;
}

void setup() {
    Serial.begin(115200);
    pinMode(ADS1220_CS_PIN, OUTPUT);
    SPI.begin();
    SPI.setDataMode (SPI_MODE1);

    Serial.println("DEFAULT_CONFIG_REG.. : ");
    writeSingleRegister( 0, DEFAULT_CONFIG_REG0 );
    writeSingleRegister( 1, DEFAULT_CONFIG_REG1 );
    writeSingleRegister( 2, DEFAULT_CONFIG_REG2 );
    writeSingleRegister( 3, DEFAULT_CONFIG_REG3 );
    delay(100);
    Serial.println(readRegister(0),HEX);
    Serial.println(readRegister(1),HEX);
    Serial.println(readRegister(2),HEX);
    Serial.println(readRegister(3),HEX);
    Serial.println(" ");
}
void loop() {}

ESP-IDF:

spi_device_handle_t spi;
char * rx_buffer;

void spi_init() {
    spi_bus_config_t buscfg = {
        .miso_io_num=PIN_NUM_SPI_MISO,
        .mosi_io_num=PIN_NUM_SPI_MOSI,
        .sclk_io_num=PIN_NUM_SPI_CLK,
        .quadwp_io_num=-1, .quadhd_io_num=-1,
    };
    spi_device_interface_config_t devcfg = {
        .spics_io_num=PIN_NUM_SPI_ADC_CS,
        .clock_speed_hz=5*1000*1000, // 5MHz
        .mode=1, // SPI MODE 1
        .command_bits=8, // 8-bit command length
        .address_bits=0, // no address
        .queue_size=20,
        //.input_delay_ns = 25 // minimum of td(SCCS) = 25ns
    };
    ESP_ERROR_CHECK(spi_bus_initialize(VSPI_HOST, &buscfg, 1/*dma_chan - 0 no DMA*/));
    ESP_ERROR_CHECK(spi_bus_add_device(VSPI_HOST, &devcfg, &spi));
}
void writeSingleRegister(uint8_t address, const uint8_t value) {
    spi_transaction_t transaction;
    memset(&transaction, 0, sizeof(transaction));
    transaction.cmd = WREG | (address<<2);
    transaction.length = 8;
    transaction.tx_buffer = &value;
    assert(spi_device_polling_transmit(spi, &transaction) == ESP_OK);
}
void readSingleRegister(uint8_t address) {
    spi_transaction_t transaction;
    memset(&transaction, 0, sizeof(transaction));
    transaction.cmd = RREG | (address<<2);
    transaction.length = 8;
    transaction.rx_buffer = rx_buffer;
    assert(spi_device_polling_transmit(spi, &transaction) == ESP_OK);
    ESP_LOG_BUFFER_HEX("readSingleRegister:", rx_buffer, 1 );
}

void spi_task(void *pvParameters) {
    rx_buffer = heap_caps_malloc(4, MALLOC_CAP_DMA);

    spi_init();
    while (1) {
        ESP_LOGI(TAG, "DEFAULT_CONFIG_REG.. : ");
        writeSingleRegister(0, DEFAULT_CONFIG_REG0);
        writeSingleRegister(1, DEFAULT_CONFIG_REG1);
        writeSingleRegister(2, DEFAULT_CONFIG_REG2);
        writeSingleRegister(3, DEFAULT_CONFIG_REG3);
        vTaskDelay(1000 / portTICK_RATE_MS);

        ESP_LOGI(TAG, "Read: ");
        readSingleRegister(0);
        readSingleRegister(1);
        readSingleRegister(2);
        readSingleRegister(3);
        vTaskDelay(5000 / portTICK_RATE_MS);
    }
}

Above example: arduino results 0x00, esp-idf 0x80 (1st bit high)

I am able to simulate IDF behavior in arduino by setting SPI.setDataMode (SPI_MODE2) edit: I am also wondering what happends when I do not set tx_buffer. Random bytes are send or DUMMY 0xFF?