mirror of
https://github.com/espressif/openthread.git
synced 2026-09-24 01:47:41 +00:00
spi-hdlc-adapter: Fixes for C̅S̅ delay (#338)
This commit makes sure that the specified delay period between the assertion of C̅S̅ and the start of the SPI clock is enforced. In order for this to work, both the delay part and the data part must be in the same `ioctl()` call. The previous code (which used two `ioctl()` calls) was entirely broken. The trick is that not all Linux SPI drivers support multi-part SPI transactions. When `spi-hdlc-adapter` is used with such devices, the `--spi-cs-delay=0` argument must be added. This causes the delay part of the transaction to be omitted entirely.
This commit is contained in:
committed by
Jonathan Hui
parent
3f67c16faf
commit
3a694016a1
@@ -123,10 +123,10 @@ static int sIntGpioValueFd = -1;
|
||||
static int sHdlcInputFd = -1;
|
||||
static int sHdlcOutputFd = -1;
|
||||
|
||||
static int sSpiSpeed = 1000000; // in Hz
|
||||
static int sSpiSpeed = 1000000; // in Hz (default: 1MHz)
|
||||
static uint8_t sSpiMode = 0;
|
||||
static int sSpiCsDelay = 1 * USEC_PER_MSEC;
|
||||
static int sSpiTransactionDelay = 1 * USEC_PER_MSEC;
|
||||
static int sSpiCsDelay = 20;
|
||||
static int sSpiTransactionDelay = 200;
|
||||
|
||||
static uint16_t sSpiRxPayloadSize;
|
||||
static uint8_t sSpiRxFrameBuffer[MAX_FRAME_SIZE + SPI_RX_ALIGN_ALLOWANCE_MAX];
|
||||
@@ -295,22 +295,6 @@ static uint16_t spi_header_get_data_len(const uint8_t *header)
|
||||
return ( header[3] + (header[4] << 8) );
|
||||
}
|
||||
|
||||
static void spi_cs_delay(void)
|
||||
{
|
||||
struct spi_ioc_transfer xfer = {
|
||||
.tx_buf = (unsigned long)NULL,
|
||||
.rx_buf = (unsigned long)NULL,
|
||||
.len = 0,
|
||||
.delay_usecs = sSpiCsDelay,
|
||||
.speed_hz = sSpiSpeed,
|
||||
.bits_per_word = 8,
|
||||
.cs_change = false,
|
||||
};
|
||||
|
||||
// We don't care if this fails.
|
||||
ioctl(sSpiDevFd, SPI_IOC_MESSAGE(1), &xfer);
|
||||
}
|
||||
|
||||
static uint8_t* get_real_rx_frame_start(void)
|
||||
{
|
||||
uint8_t* ret = sSpiRxFrameBuffer;
|
||||
@@ -332,40 +316,62 @@ static int do_spi_xfer(int len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct spi_ioc_transfer xfer = {
|
||||
.tx_buf = (unsigned long)sSpiTxFrameBuffer,
|
||||
.rx_buf = (unsigned long)sSpiRxFrameBuffer,
|
||||
.len = len + HEADER_LEN + sSpiRxAlignAllowance,
|
||||
.delay_usecs = 0,
|
||||
.speed_hz = sSpiSpeed,
|
||||
.bits_per_word = 8,
|
||||
.cs_change = false,
|
||||
struct spi_ioc_transfer xfer[2] =
|
||||
{
|
||||
{ // This part is the delay between C̅S̅ being
|
||||
// asserted and the SPI clock starting. This
|
||||
// is not supported by all Linux SPI drivers.
|
||||
.tx_buf = 0,
|
||||
.rx_buf = 0,
|
||||
.len = 0,
|
||||
.delay_usecs = sSpiCsDelay,
|
||||
.speed_hz = sSpiSpeed,
|
||||
.bits_per_word = 8,
|
||||
.cs_change = false,
|
||||
},
|
||||
{ // This part is the actual SPI transfer.
|
||||
.tx_buf = (unsigned long)sSpiTxFrameBuffer,
|
||||
.rx_buf = (unsigned long)sSpiRxFrameBuffer,
|
||||
.len = len + HEADER_LEN + sSpiRxAlignAllowance,
|
||||
.delay_usecs = 0,
|
||||
.speed_hz = sSpiSpeed,
|
||||
.bits_per_word = 8,
|
||||
.cs_change = false,
|
||||
}
|
||||
};
|
||||
|
||||
if (sSpiCsDelay > 0)
|
||||
{
|
||||
spi_cs_delay();
|
||||
// A C̅S̅ delay has been specified. Start transactions
|
||||
// with both parts.
|
||||
ret = ioctl(sSpiDevFd, SPI_IOC_MESSAGE(2), &xfer[0]);
|
||||
}
|
||||
|
||||
ret = ioctl(sSpiDevFd, SPI_IOC_MESSAGE(1), &xfer);
|
||||
|
||||
if (spi_header_get_flag_byte(sSpiRxFrameBuffer) != 0xFF)
|
||||
else
|
||||
{
|
||||
if (spi_header_get_flag_byte(sSpiRxFrameBuffer) & SPI_HEADER_RESET_FLAG)
|
||||
{
|
||||
sSlaveDidReset = true;
|
||||
}
|
||||
// No C̅S̅ delay has been specified, so we skip the first
|
||||
// part because it causes some SPI drivers to croak.
|
||||
ret = ioctl(sSpiDevFd, SPI_IOC_MESSAGE(1), &xfer[1]);
|
||||
}
|
||||
|
||||
log_debug_buffer("SPI-TX", sSpiTxFrameBuffer, xfer.len);
|
||||
log_debug_buffer("SPI-RX", sSpiRxFrameBuffer, xfer.len);
|
||||
if (ret != -1)
|
||||
{
|
||||
log_debug_buffer("SPI-TX", sSpiTxFrameBuffer, xfer[1].len);
|
||||
log_debug_buffer("SPI-RX", sSpiRxFrameBuffer, xfer[1].len);
|
||||
|
||||
sSpiFrameCount++;
|
||||
if (spi_header_get_flag_byte(sSpiRxFrameBuffer) != 0xFF)
|
||||
{
|
||||
if (spi_header_get_flag_byte(sSpiRxFrameBuffer) & SPI_HEADER_RESET_FLAG)
|
||||
{
|
||||
sSlaveDidReset = true;
|
||||
}
|
||||
}
|
||||
|
||||
sSpiFrameCount++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void debug_spi_header(const char* hint)
|
||||
{
|
||||
if (sVerbose >= LOG_DEBUG)
|
||||
|
||||
Reference in New Issue
Block a user