在大多数情况下,我无法让 LPSPI 在 RT1024 上正常工作。
更新:问题是由于下面解释的令人讨厌的 LPSPI 驱动程序错误造成的。
最好的问候,戴夫
[size=\"5\"]
背景
LPSPI 总线上有 4 个不同的传感器 4。尝试通过从每个传感器读取芯片 ID 来验证操作。
一个传感器 (ND120) 我可以正确读取,因此引脚配置、时钟、硬件似乎都可以。
我只能使用“连续模式”操作其他 3 个传感器,这在这种情况下不是我需要的。
[size=\"5\"]
代码
这是操作 AOK 的 ND120 代码:
typedef struct {
// normal read is just 32-bit pressure and temperature
int16_t pressure;
int16_t temperature;
// extended data read (beyond 4 bytes/32 bits) should get the following:
char model[8];
uint32_t serialNumber;
char softwareVersion[6];
char fill[2]; // because LPSPI API requires mul
tiple of 4 bytes; don\'t know why...
} ND120_output_T;
typedef struct {
uint8_t mode;
uint8_t rate;
// ToDo: ND120: ND120_control_T ctor to assemble fields of mode and rate
} ND120_control_T;
void test_ND120() {
lpspi_master_config_t ND120_LPSPI_MasterConfig =
{
.baudRate = 150000U, /*!< Baud Rate for LPSPI. 6uS cycle = 166,666Hz */
.bitsPerFrame = 8 * sizeof(ND120_output_T),/*!< Bits per frame, minimum 8, maximum 4096.*/
// Clock SPI mode \'00\' (CPOL = CPHA = 0)
.cpol = kLPSPI_ClockPolarityActiveLow,/*!< Clock polarity. */
.cpha = kLPSPI_ClockPhaseSecondEdge, /*!< Clock phase. */
.direction = kLPSPI_MsbFirst,/*!< MSB or LSB data shift direction. */
.pcsToSckDelayInNanoSec = 110000,/*!< PCS to SCK delay time in nanoseconds, setting to 0 sets the minimum delay.
It sets the boundary value if out of range.
spec: 100us */
.lastSckToPcsDelayInNanoSec = 20000, /*!< Last SCK to PCS delay time in nanoseconds, setting to 0 sets the minimum
delay. It sets the boundary value if out of range.
spec: 20us */
.betweenTransferDelayInNanoSec = 0, /*!< After the SCK delay time with nanoseconds, setting to 0 sets the
minimum delay. It sets the boundary value if out of range.*/
.whichPcs = kLPSPI_Pcs0, /*!< Desired Peripheral Chip Select (PCS) - over-ridden in transfer API */
.pcsActiveHighOrLow = kLPSPI_PcsActiveLow, /*!< Desired PCS active high or low */
.pinCfg = kLPSPI_SdiInSdoOut,/*!< Configures which pins are used for input and output data
during single bit transfers.*/
.dataOutConfig = kLpspiDataOutRetained, /*!< Configures if the output data is tristated
* between accesses (LPSPI_PCS is negated). */
/*guess*/.enableInputDelay = false, /*!< Enable master to sample the input data on a delayed SCK. This can help improve slave
setup time. Refer to device data sheet for specific time length. */
};
LPSPI_MasterInit(LPSPI4, &ND120_LPSPI_MasterConfig, BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT); // enables clock and LPSI module
ND120_control_T ctrl = {
.mode = 0,
.rate = 0,
};
ND120_output_T result;
memset(&result,0,sizeof(result));
lpspi_transfer_t t1 =
{
.txData = (uint8_t*)&ctrl, /*!< Send buffer. */
.rxData = (uint8_t*)&result, /*!< Receive buffer. */
.dataSize = sizeof(result), /*!< Transfer bytes. */
/*!< Transfer transfer configuration flags. Set from _lpspi_transfer_config_flag_for_master if
the transfer is used for master or _lpspi_transfer_config_flag_for_slave enumeration if the
transfer is used for slave.*/
.configFlags = kLPSPI_MasterPcs0 /*| kLPSPI_MasterPcsContinuous */,
};
// Reset ND120
GPIO_PinWrite(BOARD_INITPINS_ND120_RESET_GPIO, BOARD_INITPINS_ND120_RESET_PIN, 0);
vTaskDelay(pdMS_TO_TICKS(10));
GPIO_PinWrite(BOARD_INITPINS_ND120_RESET_GPIO, BOARD_INITPINS_ND120_RESET_PIN, 1);
vTaskDelay(pdMS_TO_TICKS(100)); // wait for reset to actually complete
// ND120 Returns:
// {pressure = 5988, temperature = 1, model = \"21DN\\0\\0\\00\", serialNumber = 1163278597, softwareVersion = \"7410\\0\", fill = \"\\0A\"}
status_t s1 = LPSPI_MasterTransferBlocking(LPSPI4, &t1);
assert(s1 == kStatus_Success);
(void)s1;
bool connected = memcmp(result.model,\"21DN\",5)==0;
assert(connected);
(void)connected;
// Can we do it twice?
status_t s2 = LPSPI_MasterTransferBlocking(LPSPI4, &t1);
assert(s2 == kStatus_Success);
(void)s2;
bool connected2 = memcmp(result.model,\"21DN\",5)==0;
assert(connected2);
(void)connected2;
}
使用“连续模式”,我可以从 3 个 BMP581 传感器读取设备 ID:
void test_bmp581() {
// first try, using \'continuous CS\', works before or after ND120 test
uint8_t t1_ReadChipID[2] = {
0x80 /* read operation */ | /* register */ BMP5_REG_CHIP_ID,
0 // dummy, time for data reply
};
uint8_t t1_result[sizeof(t1_ReadChipID)] = {55,66};
lpspi_master_config_t masterConfig =
{
.baudRate = 10000000U, /*!< Baud Rate for LPSPI. 10MHz (12.5MHz spec) */
.bitsPerFrame = 8, /*!< Bits per frame, minimum 8, maximum 4096.*/
// Clock SPI mode \'11\' (CPOL = CPHA = 1)
.cpol = kLPSPI_ClockPolarityActiveLow, /*!< Clock polarity. */
.cpha = kLPSPI_ClockPhaseSecondEdge, /*!< Clock phase. */
.direction = kLPSPI_MsbFirst,/*!< MSB or LSB data shift direction. */
/*guess*/.pcsToSckDelayInNanoSec = 50,/*!< PCS to SCK delay time in nanoseconds, setting to 0 sets the minimum delay.
It sets the boundary value if out of range.
ToDo: T_setup_csb MISSING FROM SPECIFICATION. */
.lastSckToPcsDelayInNanoSec = 50, /*!< Last SCK to PCS delay time in nanoseconds, setting to 0 sets the minimum
delay. It sets the boundary value if out of range.
T_hold_csb = 40ns spec.*/
.betweenTransferDelayInNanoSec = 0, /*!< After the SCK delay time with nanoseconds, setting to 0 sets the
minimum delay. It sets the boundary value if out of range.*/
.whichPcs = kLPSPI_Pcs1, /*!< Desired Peripheral Chip Select (PCS) - over-ridden in transfer API */
.pcsActiveHighOrLow = kLPSPI_PcsActiveLow, /*!< Desired PCS active high or low */
.pinCfg = kLPSPI_SdiInSdoOut,/*!< Configures which pins are used for input and output data
during single bit transfers.*/
.dataOutConfig = kLpspiDataOutRetained, /*!< Configures if the output data is tristated
* between accesses (LPSPI_PCS is negated). */
/*guess*/.enableInputDelay = false, /*!< Enable master to sample the input data on a delayed SCK. This can help improve slave
setup time. Refer to device data sheet for specific time length. */
};
LPSPI_MasterInit(LPSPI4, &masterConfig, BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT); // enables clock and LPSI module
lpspi_transfer_t t1 =
{
.txData = &t1_ReadChipID[0], /*!< Send buffer. */
.rxData = &t1_result[0], /*!< Receive buffer. */
.dataSize = sizeof(t1_result), /*!< Transfer bytes. */
/*!< Transfer transfer configuration flags. Set from _lpspi_transfer_config_flag_for_master if
the transfer is used for master or _lpspi_transfer_config_flag_for_slave enumeration if the
transfer is used for slave.*/
.configFlags = kLPSPI_MasterPcs1 /* Overridden below anyway: | kLPSPI_MasterPcsContinuous */ ,
};
// trying to read multiple devices fails, probably because we\'ve got CS confusion from \'continuous\' mode
// =================== PCS #1 =======================
t1.configFlags = kLPSPI_MasterPcs1 | kLPSPI_MasterPcsContinuous ;
status_t s1 = LPSPI_MasterTransferBlocking(LPSPI4, &t1);
assert(s1 == kStatus_Success);
printf(\"BMP581-1 id (should be x50): x%x\\n\", t1_result[1]);
assert(t1_result[1] == 0x50);
}
如果我尝试不使用连续模式(这是这里需要的),我会得到空白结果:
void test_bmp581() {
uint8_t t1_ReadChipID[2] = {
0x80 /* read operation */ | /* register */ BMP5_REG_CHIP_ID,
0 // dummy, time for data reply
};
uint8_t t1_result[sizeof(t1_ReadChipID)] = {55,66};
lpspi_master_config_t masterConfig =
{
.baudRate = 10000000U, /*!< Baud Rate for LPSPI. 10MHz (12.5MHz spec) */
.bitsPerFrame = 8 * sizeof(t1_result), /*!< Bits per frame, minimum 8, maximum 4096.*/
// Clock SPI mode \'11\' (CPOL = CPHA = 1)
.cpol = kLPSPI_ClockPolarityActiveLow, /*!< Clock polarity. */
.cpha = kLPSPI_ClockPhaseSecondEdge, /*!< Clock phase. */
.direction = kLPSPI_MsbFirst,/*!< MSB or LSB data shift direction. */
/*guess*/.pcsToSckDelayInNanoSec = 50, /*!< PCS to SCK delay time in nanoseconds, setting to 0 sets the minimum delay.
It sets the boundary value if out of range.
ToDo: T_setup_csb MISSING FROM BOSCH SPECIFICATION. */
.lastSckToPcsDelayInNanoSec = 50, /*!< Last SCK to PCS delay time in nanoseconds, setting to 0 sets the minimum
delay. It sets the boundary value if out of range.
T_hold_csb = 40ns spec.*/
.betweenTransferDelayInNanoSec = 0, /*!< After the SCK delay time with nanoseconds, setting to 0 sets the
minimum delay. It sets the boundary value if out of range.*/
.whichPcs = kLPSPI_Pcs1, /*!< Desired Peripheral Chip Select (PCS) - over-ridden in transfer API */
.pcsActiveHighOrLow = kLPSPI_PcsActiveLow, /*!< Desired PCS active high or low */
.pinCfg = kLPSPI_SdiInSdoOut,/*!< Configures which pins are used for input and output data
during single bit transfers.*/
.dataOutConfig = kLpspiDataOutRetained, /*!< Configures if the output data is tristated
* between accesses (LPSPI_PCS is negated). */
/*guess*/.enableInputDelay = false, /*!< Enable master to sample the input data on a delayed SCK. This can help improve slave
setup time. Refer to device data sheet for specific time length. */
};
LPSPI_MasterInit(LPSPI4, &masterConfig, BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT); // enables clock and LPSI module
lpspi_transfer_t t1 =
{
.txData = &t1_ReadChipID[0], /*!< Send buffer. */
.rxData = &t1_result[0], /*!< Receive buffer. */
.dataSize = sizeof(t1_result), /*!< Transfer bytes. */
/*!< Transfer transfer configuration flags. Set from _lpspi_transfer_config_flag_for_master if
the transfer is used for master or _lpspi_transfer_config_flag_for_slave enumeration if the
transfer is used for slave.*/
.configFlags = kLPSPI_MasterPcs1 /* Overridden below anyway: | kLPSPI_MasterPcsContinuous */ ,
};
// ToDo: BMP581: Bug: reads 0x00 0x00
// =================== PCS #1 =======================
t1.configFlags = kLPSPI_MasterPcs1 /*| kLPSPI_MasterPcsContinuous */;
status_t s1 = LPSPI_MasterTransferBlocking(LPSPI4, &t1);
assert(s1 == kStatus_Success);
assert(t1_result[1] == 0x50); // <<< Fails here
}