Page 1 of 1

关于esp32 wroom 32u 的spi总线时序问题

Posted: Sat Jul 10, 2021 7:41 am
by nash.zhao
env
ubuntu 20.04
idf v4.2.1
我目前在调spi总线,使用SPI3
PIN 参考了https://docs.espressif.com/projects/esp-idf/zh_CN/release-v4.1/api-reference/peripherals/spi_master.html
我执行读命令 command 8bit 读 1byte
cmd 为0x02
我用逻辑分析仪得到的结果是mosi 输出的后8bit全为 HIGH
图见附件
三个有输出的波形分别为 cs clk mosi
可以看出mosi后8bit 为HIGH
该函数我是使用类来实现的如果将该类的管脚分配至SPI2 ,则波形正常。
请问该问题如何解决?

Re: 关于esp32 wroom 32u 的spi总线时序问题

Posted: Sat Jul 10, 2021 7:53 am
by nash.zhao
部分spi代码如下:
uint8_t icm20602_typedef::get_reg(uint8_t addr){
spi_bus.readBytes(device, addr, 1, rx);
//spi_bus.readBytes(device, 0x00, 2, rx);

return rx[0];
}
void icm20602_typedef::write_reg(uint8_t addr, uint8_t val){
tx[0] = val;
ESP_ERROR_CHECK(spi_bus.writeBytes(device, addr, 1, tx));
}
void icm20602_typedef::init(int miso, int mosi, int sclk, int cs)
{
delay_ms(10);
//spi_bus_free(spi_bus.host);
ESP_ERROR_CHECK( spi_bus.begin(mosi, miso, sclk));
ESP_ERROR_CHECK( spi_bus.addDevice(3, 23000, cs, &device));
write_reg(ICM20602_PWR_MGMT_1,0x01);
write_reg(ICM20602_PWR_MGMT_2,0x00);
write_reg(ICM20602_CONFIG,0x03);
write_reg(ICM20602_SMPLRT_DIV,0x00);
write_reg(ICM20602_GYRO_CONFIG,0x18);
write_reg(ICM20602_ACCEL_CONFIG,0x08);
write_reg(ICM20602_ACCEL_CONFIG_2,0x03);
delay_ms(200);
}
void icm20602_typedef::who_am_i(){
uint8_t who;
who = get_reg(0x02);
printf("imu whois : %d\n",who);
//HAL_UART_Transmit(&huart1,&who,1,0xff);
}


//spi 驱动部分
cpp
#include "spi_bus.hpp"
static const char* TAG __attribute__((unused)) = "SPIbus";

static SemaphoreHandle_t _mutex;
spi_device_handle_t spi;
spi_bus_config_t buscfg;//={
spi_device_interface_config_t devcfg;//={
void spi_bus_init(spi_host_device_t _spi_host,
int _miso,
int _mosi,
int _sclk,
int _cs)
{
esp_err_t ret;

ESP_LOGI(TAG, "Initializing bus SPI%d...", _spi_host+1);

// .miso_io_num = _mosi,
// .mosi_io_num = _miso,
// .sclk_io_num = _sclk,
// .quadwp_io_num = -1,
// .quadhd_io_num = -1,
// .max_transfer_sz = 32,
// };
buscfg.miso_io_num = _miso;
buscfg.mosi_io_num = _mosi;
buscfg.sclk_io_num = _sclk,
buscfg.quadwp_io_num = -1;
buscfg.quadhd_io_num = -1;
buscfg.max_transfer_sz = 32;


devcfg.clock_speed_hz=25000*1000, //Clock out at 26 MHz
devcfg.mode=0, //SPI mode 0
devcfg.spics_io_num=_cs, //CS pin
devcfg.queue_size=1, //We want to be able to queue 7 transactions at a time
//.pre_cb=lcd_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line
devcfg.command_bits = 0;
devcfg.address_bits = 8;
devcfg.dummy_bits = 0;
devcfg.duty_cycle_pos = 128; // default 128 = 50%/50% duty gpio_set_direction((gpio_num_t)_miso, GPIO_MODE_INPUT);

//Initialize the SPI bus
ret=spi_bus_initialize(_spi_host, &buscfg, 0);
ESP_ERROR_CHECK(ret);
//Attach the LCD to the SPI bus
ret=spi_bus_add_device(_spi_host, &devcfg, &spi);
ESP_ERROR_CHECK(ret);
_mutex = xSemaphoreCreateMutex();

}
void spi_tx(const uint8_t cmd)
{
esp_err_t ret;
spi_transaction_t t;
memset(&t, 0, sizeof(t)); //Zero out the transaction
t.length=8; //Command is 8 bits
t.tx_buffer=&cmd; //The data is the cmd itself
t.user=(void*)0; //D/C needs to be set to 0
bool success = xSemaphoreTake(_mutex, 5 / portTICK_RATE_MS) == pdTRUE;
if(!success)
printf("Coulnd not acquire spi mutex");
ret=spi_device_polling_transmit(spi, &t); //Transmit!
assert(ret==ESP_OK);
if(xSemaphoreGive(_mutex) != pdTRUE)
{
printf("release failed\n");
}
}



#if defined CONFIG_SPIBUS_LOG_RW_LEVEL_INFO
#define SPIBUS_LOG_RW(format, ... ) ESP_LOGI(TAG, format, ##__VA_ARGS__)
#elif defined CONFIG_SPIBUS_LOG_RW_LEVEL_DEBUG
#define SPIBUS_LOG_RW(format, ... ) ESP_LOGD(TAG, format, ##__VA_ARGS__)
#elif defined CONFIG_SPIBUS_LOG_RW_LEVEL_VERBOSE
#define SPIBUS_LOG_RW(format, ... ) ESP_LOGV(TAG, format, ##__VA_ARGS__)
#endif
#define SPIBUS_LOGE(format, ... ) ESP_LOGE(TAG, format, ##__VA_ARGS__)



/*******************************************************************************
* OBJECTS
******************************************************************************/
SPI hspi = SPI(HSPI_HOST);
SPI vspi = SPI(VSPI_HOST);


/*******************************************************************************
* SETUP
******************************************************************************/
SPI::SPI(spi_host_device_t host) : host(host)
{
}

SPI::~SPI() {
close();
}

esp_err_t SPI::begin(int mosi_io_num, int miso_io_num, int sclk_io_num, int max_transfer_sz) {
spi_bus_config_t config;
// Configuration struct need to be initialized to 0.
memset(&config, 0, sizeof(config));
config.mosi_io_num = mosi_io_num;
config.miso_io_num = miso_io_num;
config.sclk_io_num = sclk_io_num;
config.quadwp_io_num = -1; // -1 not used
config.quadhd_io_num = -1; // -1 not used
config.max_transfer_sz = max_transfer_sz;
return spi_bus_initialize(host, &config, 0); // 0 DMA not used
}

esp_err_t SPI::close() {
return spi_bus_free(host);
}

esp_err_t SPI::addDevice(uint8_t mode, uint32_t clock_speed_hz, int cs_io_num, spi_device_handle_t *handle) {
spi_device_interface_config_t dev_config;
dev_config.command_bits = 0;
dev_config.address_bits = 8;
dev_config.dummy_bits = 0;
dev_config.mode = mode;
dev_config.duty_cycle_pos = 128; // default 128 = 50%/50% duty
dev_config.cs_ena_pretrans = 0; // 0 not used
dev_config.cs_ena_posttrans = 0; // 0 not used
dev_config.clock_speed_hz = clock_speed_hz;
dev_config.spics_io_num = cs_io_num;
dev_config.flags = 0; // 0 not used
dev_config.queue_size = 1;
dev_config.pre_cb = NULL;
dev_config.post_cb = NULL;
return spi_bus_add_device(host, &dev_config, handle);
}

esp_err_t SPI::addDevice(spi_device_interface_config_t *dev_config, spi_device_handle_t *handle) {
dev_config->address_bits = 8; // must be set, SPIbus uses this 8-bits to send the regAddr
return spi_bus_add_device(host, dev_config, handle);
}

esp_err_t SPI::removeDevice(spi_device_handle_t handle) {
return spi_bus_remove_device(handle);
}


/*******************************************************************************
* WRITING
******************************************************************************/
esp_err_t SPI::writeBit(spi_device_handle_t handle, uint8_t regAddr, uint8_t bitNum, uint8_t data) {
uint8_t buffer;
esp_err_t err = readByte(handle, regAddr, &buffer);
if (err) return err;
buffer = data ? (buffer | (1 << bitNum)) : (buffer & ~(1 << bitNum));
return writeByte(handle, regAddr, buffer);
}

esp_err_t SPI::writeBits(spi_device_handle_t handle, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data) {
uint8_t buffer;
esp_err_t err = readByte(handle, regAddr, &buffer);
if (err) return err;
uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1);
data <<= (bitStart - length + 1);
data &= mask;
buffer &= ~mask;
buffer |= data;
return writeByte(handle, regAddr, buffer);
}

esp_err_t SPI::writeByte(spi_device_handle_t handle, uint8_t regAddr, uint8_t data) {
return writeBytes(handle, regAddr, 1, &data);
}

esp_err_t SPI::writeBytes(spi_device_handle_t handle, uint8_t regAddr, size_t length, const uint8_t *data) {
transaction.flags = 0;
transaction.cmd = 0;
transaction.addr = regAddr;// & SPIBUS_WRITE;
transaction.length = length * 8;
transaction.rxlength = 0;
transaction.user = NULL;
transaction.tx_buffer = data;
transaction.rx_buffer = NULL;
esp_err_t err = spi_device_transmit(handle, &transaction);
#if defined CONFIG_SPIBUS_LOG_READWRITES
if (!err) {
char str[length*5+1];
for(size_t i = 0; i < length; i++)
sprintf(str+i*5, "0x%s%X ", (data < 0x10 ? "0" : ""), data);
SPIBUS_LOG_RW("[%s, handle:0x%X] Write %d bytes to__ register 0x%X, data: %s", (host == 1 ? "HSPI" : "VSPI"), (uint32_t)handle, length, regAddr, str);
}
#endif
return err;
}


/*******************************************************************************
* READING
******************************************************************************/
esp_err_t SPI::readBit(spi_device_handle_t handle, uint8_t regAddr, uint8_t bitNum, uint8_t *data) {
return readBits(handle, regAddr, bitNum, 1, data);
}

esp_err_t SPI::readBits(spi_device_handle_t handle, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data) {
uint8_t buffer;
esp_err_t err = readByte(handle, regAddr, &buffer);
if(!err) {
uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1);
buffer &= mask;
buffer >>= (bitStart - length + 1);
*data = buffer;
}
return err;
}

esp_err_t SPI::readByte(spi_device_handle_t handle, uint8_t regAddr, uint8_t *data) {
return readBytes(handle, regAddr, 1, data);
}

esp_err_t SPI::readBytes(spi_device_handle_t handle, uint8_t regAddr, size_t length, uint8_t *data) {
if(length == 0) return ESP_ERR_INVALID_SIZE;
transaction.flags = 0;
transaction.cmd = 0;
transaction.addr = regAddr;// | SPIBUS_READ;
transaction.length = length * 8;
transaction.rxlength = length * 8;
transaction.user = NULL;
transaction.tx_buffer = NULL;
transaction.rx_buffer = data;
//esp_err_t err = spi_device_transmit(handle, &transaction);
esp_err_t err = spi_device_polling_transmit(handle, &transaction);
#if defined CONFIG_SPIBUS_LOG_READWRITES
if (!err) {
char str[length*5+1];
for(size_t i = 0; i < length; i++)
sprintf(str+i*5, "0x%s%X ", (data < 0x10 ? "0" : ""), data);
SPIBUS_LOG_RW("[%s, handle:0x%X] Read_ %d bytes from register 0x%X, data: %s", (host == 1 ? "HSPI" : "VSPI"), (uint32_t)handle, length, regAddr, str);
}
#endif
return err;
}


/×××××××××××××××××××××××××××××××××××××××/
hpp
#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"

#include "sdkconfig.h"
#include "esp_log.h"

#include "function.hpp"

#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "sdkconfig.h"

// /// Configurations of the spi_eeprom
// typedef struct {
// spi_host_device_t host; ///< The SPI host used, set before calling `spi_eeprom_init()`
// gpio_num_t cs_io; ///< CS gpio number, set before calling `spi_eeprom_init()`
// gpio_num_t miso_io; ///< MISO gpio number, set before calling `spi_eeprom_init()`
// bool intr_used; ///< Whether to use polling or interrupt when waiting for write to be done. Set before calling `spi_eeprom_init()`.
// } spi_device_bus_config_t;

// struct spi_context_t{
// spi_bus_config_t cfg; ///< Configuration by the caller.
// spi_device_handle_t spi; ///< SPI device handle
// xSemaphoreHandle ready_sem; ///< Semaphore for ready signal
// };
// typedef struct spi_context_t* spi_handle_t;
void spi_bus_init(spi_host_device_t _spi_host,
int _miso,
int _mosi,
int _sclk,
int _cs);


void spi_tx(const uint8_t cmd);


// Defaults
#define SPIBUS_READ (0x80) /*!< addr | SPIBUS_READ */
#define SPIBUS_WRITE (0x7F) /*!< addr & SPIBUS_WRITE */

// Forward declaration
class SPI;

// Default objects
extern SPI hspi;
extern SPI vspi;


/* ^^^
* SPI
* ^^^ */
typedef
class SPI {

public:
explicit SPI(spi_host_device_t host);
~SPI();
spi_host_device_t host; /*!< HSPI_HOST or VSPI_HOST */
spi_transaction_t transaction;
/**
* @brief Config SPI bus and initialize
* @param mosi_io_num [GPIO number for Master-out Slave-in]
* @param miso_io_num [GPIO number for Master-in Slave-out]
* @param miso_io_num [GPIO number for clock line]
* @param max_transfer_sz [Maximum transfer size, in bytes. Defaults to 4094 if 0.]
* @return - ESP_ERR_INVALID_ARG if configuration is invalid
* - ESP_ERR_INVALID_STATE if host already is in use
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on success
* */
esp_err_t begin(int mosi_io_num, int miso_io_num, int sclk_io_num, int max_transfer_sz = SPI_MAX_DMA_LEN);

/**
* @brief Free the SPI bus
* @warning In order for this to succeed, all devices have to be removed first.
* @return - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_INVALID_STATE if not all devices on the bus are freed
* - ESP_OK on success
* */
esp_err_t close();

/**
* @brief Allocate a device on a SPI bus. (Up to three devices per peripheral)
* @param mode [SPI mode (0-3)]
* @param clock_speed_hz [Clock speed, in Hz]
* @param cs_io_num [ChipSelect GPIO pin for this device, or -1 if not used]
* @param handle [Pointer to variable to hold the device handle]
* @param dev_config [SPI interface protocol config for the device (for more custom configs)]
* @see driver/spi_master.h
* @return - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_NOT_FOUND if host doesn't have any free CS slots
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on success
* */
esp_err_t addDevice(uint8_t mode, uint32_t clock_speed_hz, int cs_io_num, spi_device_handle_t *handle);
esp_err_t addDevice(spi_device_interface_config_t *dev_config, spi_device_handle_t *handle);
esp_err_t removeDevice(spi_device_handle_t handle);

/**
* *** WRITING interface ***
* @brief SPI commands for writing to a 8-bit slave device register.
* All of them returns standard esp_err_t codes. So it can be used
* with ESP_ERROR_CHECK();
* @param handle [SPI device handle]
* @param regAddr [Register address to write to]
* @param bitNum [Bit position number to write to (bit 7~0)]
* @param bitStart [Start bit number when writing a bit-sequence (MSB)]
* @param data [Value(s) to be write to the register]
* @param length [Number of bytes to write (should be within the data buffer size)]
* [writeBits() -> Number of bits after bitStart (including)]
* @return - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t writeBit(spi_device_handle_t handle, uint8_t regAddr, uint8_t bitNum, uint8_t data);
esp_err_t writeBits(spi_device_handle_t handle, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data);
esp_err_t writeByte(spi_device_handle_t handle, uint8_t regAddr, uint8_t data);
esp_err_t writeBytes(spi_device_handle_t handle, uint8_t regAddr, size_t length, const uint8_t *data);

/**
* *** READING interface ***
* @breif SPI commands for reading a 8-bit slave device register.
* All of them returns standard esp_err_t codes.So it can be used
* with ESP_ERROR_CHECK();
* @param handle [SPI device handle]
* @param regAddr [Register address to read from]
* @param bitNum [Bit position number to write to (bit 7~0)]
* @param bitStart [Start bit number when writing a bit-sequence (MSB)]
* @param data [Buffer to store the read value(s)]
* @param length [Number of bytes to read (should be within the data buffer size)]
* @return - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t readBit(spi_device_handle_t handle, uint8_t regAddr, uint8_t bitNum, uint8_t *data);
esp_err_t readBits(spi_device_handle_t handle, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data);
esp_err_t readByte(spi_device_handle_t handle, uint8_t regAddr, uint8_t *data);
esp_err_t readBytes(spi_device_handle_t handle, uint8_t regAddr, size_t length, uint8_t *data);
} SPI_t;


/* Get default objects */
constexpr SPI_t& getSPI(spi_host_device_t host) {
return host == 1 ? hspi : vspi;
}

Re: 关于esp32 wroom 32u 的spi总线时序问题

Posted: Mon Jul 12, 2021 8:22 am
by ESP_Yake
Hi, 我尝试理解你的问题, 使用 SPI3 通过命令读取 1个字节的数据,读出来的是全 0xff,而更换成 SPI2 则可以正常读取数据,不知道我的理解是否正确。
如果我的理解没问题,那么你使用逻辑分析仪有没有对过这两者发的包存在哪些区别,一个正常能读到一个读不到,只能说明发出来的数据不符合 slave 的要求,而这部分的差异只会在波形上。