为什么带有ESP-IDF的SPI与ESP-IDF Arduino端口(AS5048A)不同?

时间:2020-06-15 08:31:20

标签: spi esp32 esp-idf

我已将AS5048A磁编码器连接到ESP32开发板(VSPI / SPI3总线:CS = 5,CLK = 18,MISO = 19,MOSI = 23)。使用ESP IDF版本4.0.1。 Arduino库: https://github.com/espressif/arduino-esp32/tree/idf-release/v4.0

我测试了SPI传输的两个版本: a)有 b)没有 Arduino ESP-IDF库

Arduino版本通常在不同速度下都能很好地工作。纯粹的IDF很难正确地接收数据。 奇怪的是,纯IDF版本设法在SPI模式3(Arduino在模式1下工作)下发送0x0000和0xFFFF(具有奇偶校验和读/写的读取角度命令),但其他命令失败。同样,0x0000(空命令)返回一些垃圾(0x6000或类似的值,而不是0x00000)。 因此,纯IDF版本可以在SPI模式3下正确读取角度(?!),但其他任何操作都会失败(我想这是偶然的,因为读取角度命令为0xFFFF)。

我尝试了每种模式和许多定时配置。尝试查看Arduino库SPI时,它使用了与IDF本身不同的SPI方法。

有什么帮助/想法吗?下面是代码。

Arduino的实现非常简单:

this->settings = SPISettings(3000000, MSBFIRST, SPI_MODE1);
pinMode(this->_cs, OUTPUT);
SPI.begin();

SPI.beginTransaction(this->settings);

digitalWrite(this->_cs, LOW);
uint16_t response = SPI.transfer16(command);
digitalWrite(this->_cs, HIGH);

遵循纯IDF:

spi_host_device_t spi_host = SPI3_HOST;
spi_device_handle_t spi;   
esp_err_t ret;

spi_bus_config_t buscfg;
memset(&buscfg, 0, sizeof(buscfg));
buscfg.mosi_io_num = pinMOSI;
buscfg.miso_io_num = pinMISO;
buscfg.sclk_io_num = pinCLK;
buscfg.quadwp_io_num = -1;
buscfg.quadhd_io_num = -1;
buscfg.max_transfer_sz = 1;
buscfg.flags = SPICOMMON_BUSFLAG_MASTER ; /*| SPICOMMON_BUSFLAG_IOMUX_PINS ;*/
buscfg.intr_flags = 0;

spi_device_interface_config_t devcfg;
memset(&devcfg, 0, sizeof(devcfg));
devcfg.command_bits = 0;
devcfg.address_bits = 0;
devcfg.dummy_bits = 0;
devcfg.mode = (uint8_t) 1; //SPI_MODE;
devcfg.duty_cycle_pos = 0;
devcfg.cs_ena_pretrans = 0;
devcfg.cs_ena_posttrans = (uint8_t) 0; //CS_ENA_POSTTRANS;
devcfg.clock_speed_hz = 300 * 1000; //SPI_HZ;
devcfg.input_delay_ns = 50; // INPUT_DELAY_NS;
devcfg.spics_io_num = pinCS;
devcfg.flags = SPI_DEVICE_NO_DUMMY ;
devcfg.queue_size = 1;
devcfg.pre_cb = 0;
devcfg.post_cb = 0;

ret = spi_bus_initialize(spi_host, &buscfg, 0); // No DMA 
ESP_ERROR_CHECK(ret);
ret =  spi_bus_add_device(spi_host, &devcfg, &spi);
ESP_ERROR_CHECK(ret);

ESP_LOGI(TAG, "AS5048 device initialized on SPI with MISO=%d, MOSI=%d, CLK=%d, CS=%d, HZ=%d", pinMISO, pinMOSI, pinCLK, pinCS, SPI_HZ);

并传输(cmd是具有奇偶校验和读/写位的uint16_t):

esp_err_t ret;
spi_transaction_t t;

spi_device_acquire_bus(spi, portMAX_DELAY);

memset(&t, 0, sizeof(t));       
t.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA  ; 
*((uint16_t*)t.tx_data) = SPI_SWAP_DATA_TX(cmd, 16);
t.length = 16;                   

//ret =  spi_device_transmit(spi, &t);
ret =  spi_device_polling_transmit(spi, &t);
if(ret != ESP_OK)               
    ESP_LOGE(TAG, "spi_device_transmit() failed");

spi_device_release_bus(spi);
uint16_t response = SPI_SWAP_DATA_RX(*((uint16_t*)t.rx_data), 16);   

1 个答案:

答案 0 :(得分:0)

我刚刚打开了组件的数据表,并注意到它指出SPI WireMode为1。

还有一个表格,其中提到了我在此处包含的其他一些项目。 Time between CSn falling edge and CLK rising edge指定为350ns,最小串行时钟周期为100ns,因此,如果您以10MHz的频率运行,则最多需要等待4个时钟。我认为这不是您正在运行的速度所引起的问题,但要注意一下。

您的Arduino配置显示传输频率为3MHz,并且CS线在传输之前由软件驱动,这可能会处理您的设置时间,并且您的ESP-IDF代码让您运行模式3,但运行频率为300KHz,这应该可以您已经超过了所需的350ns设置时间(文档显示了驱动CS后1 spi的时钟延迟,稍后会详细介绍)。模式3的时钟与模式1的时钟相反,这意味着SPI将在数据线转换的同时尝试读取数据。我的猜测是,您可能会遇到一些逻辑争用,并且在某些情况下它会“正常工作”,因为input_delay_ns参数可能会导致刚好在采样之前更改数据状态的延迟

使用错误的SPI时序模式会使您发疯,因为事情几乎可以正常工作,有时您会得到正确的结果(而且,对于设备或总线布局而言,运行速度过高)可能会导致您同样的痛苦)。为了快速恢复,模式是时钟极性和相位的矩阵。模式1和3彼此极性相反,并且在上升沿或下降沿采样,并且使用错误的时序时,可以在时钟改变状态的同时设置该值。

我赞扬您使用ESP-IDF并摆脱了嵌入式世界的“ Visual Basic” Arduino。如果要尝试接近器件的10MHz最高速度,则还需要使用SPI ctrl2寄存器(0x14)。根据文档,位0-3(默认值为1)指定要驱动的CS线与数据传输开始之间的延迟。

相关问题