Hi
I have an SPI external device that communicate through SPI ( registers and so)
I want to operate the KW40Z in SPI master mode where i will be able to write and read 8 bytes.
I dont need the dspi package that do transfer of data from side to side, just the HAL.
My questions are:
1. is there an example how to do that simple work , because while investigating the subject i see that the SPI device is not linked and its under this define:
FSL_FEATURE_SOC_SPI_COUNT which is 0.
This define close all the SPI HAL Device.
The current options i see now is to dig into the code of the API , enable the SPI and use the Hal_WriteData and ReadData
And configure the SPI to use as Master for external device.
It will be nice if NXP will provide an example project , that is mission is to enable SPI Master and read and write data to the HAL, No interrupts , no fifo , nothing, just read and write directly to the SPI.
Thanks,
Eli
Hi Eli,
I apologize for my late response.
What we have for KW40Z supported in KSDK 1.3 is dspi demo located under
<ksdk_path>\MKW40Z160xxx4\examples\frdmkw40z\driver_examples\dspi
if you would like to work with SPI, please take a look at another demo, for example for FRDM-KL26Z.
If you need direct access to the HAL, please look at SPI driver, where is access to the HAL layer:
E.g. this function in fsl_spi_master_driver.c uses HAL
static spi_status_t SPI_DRV_MasterStartTransfer(uint32_t instance,
const spi_master_user_config_t * device)
{
/* instantiate local variable of type spi_master_state_t and point to global state */
spi_master_state_t * spiState = (spi_master_state_t *)g_spiStatePtr[instance];
uint32_t calculatedBaudRate;
SPI_Type *base = g_spiBase[instance];
/* Check that we're not busy.*/
if (spiState->isTransferInProgress)
{
return kStatus_SPI_Busy;
}
/* Configure bus for this device. If NULL is passed, we assume the caller has
* preconfigured the bus using SPI_DRV_MasterConfigureBus().
* Do nothing for calculatedBaudRate. If the user wants to know the calculatedBaudRate
* then they can call this function separately.
*/
if (device)
{
SPI_DRV_MasterConfigureBus(instance, device, &calculatedBaudRate);
}
/* In order to flush any remaining data in the shift register, disable then enable the SPI */
SPI_HAL_Disable(base);
SPI_HAL_Enable(base);
#if FSL_FEATURE_SPI_16BIT_TRANSFERS
spi_data_bitcount_mode_t bitCount;
bitCount = SPI_HAL_Get8or16BitMode(base);
/* Check the transfer byte count. If bits/frame > 8, meaning 2 bytes if bits/frame > 8, and if
* the transfer byte count is an odd count we'll have to increase the transfer byte count
* by one and assert a flag to indicate to the receive function that it will need to handle
* an extra byte so that it does not inadverently over-write an another byte to the receive
* buffer. For sending the extra byte, we don't care if we read past the send buffer since we
* are only reading from it and the absolute last byte (that completes the final 16-bit word)
* is a don't care byte anyway.
*/
if ((bitCount == kSpi16BitMode) && (spiState->remainingSendByteCount & 1UL))
{
spiState->remainingSendByteCount += 1;
spiState->remainingReceiveByteCount += 1;
spiState->extraByte = true;
}
else
{
spiState->extraByte = false;
}
#endif
/* If the byte count is zero, then return immediately.*/
if (spiState->remainingSendByteCount == 0)
{
SPI_DRV_MasterCompleteTransfer(instance);
return kStatus_SPI_Success;
}
/* Save information about the transfer for use by the ISR.*/
spiState->isTransferInProgress = true;
spiState->transferredByteCount = 0;
/* Make sure TX data register (or FIFO) is empty. If not, return appropriate
* error status. This also causes a read of the status
* register which is required before writing to the data register below.
*/
if (SPI_HAL_IsTxBuffEmptyPending(base) != 1)
{
return kStatus_SPI_TxBufferNotEmpty;
}
#if FSL_FEATURE_SPI_16BIT_TRANSFERS
/* If the module/instance contains a FIFO (and if enabled), proceed with FIFO usage for either
* 8- or 16-bit transfers, else bypass to non-FIFO usage.
*/
if ((g_spiFifoSize[instance] != 0) && (SPI_HAL_GetFifoCmd(base)))
{
/* First fill the FIFO with data */
SPI_DRV_MasterFillupTxFifo(instance);
/* If the remaining RX byte count is less than the RX FIFO watermark, enable
* the TX FIFO empty interrupt. Once the TX FIFO is empty, we are ensured
* that the transmission is complete and can then drain the RX FIFO.
* Else, enable the RX FIFO interrupt based on the watermark. In the IRQ
* handler, another check will be made to see if the remaining RX byte count
* is less than the RX FIFO watermark.
*/
if (spiState->remainingReceiveByteCount < g_spiFifoSize[instance])
{
SPI_HAL_SetIntMode(base, kSpiTxEmptyInt, true); /* TX FIFO empty interrupt */
}
else
{
SPI_HAL_SetFifoIntCmd(base, kSpiRxFifoNearFullInt, true);
}
}
/* Modules that support 16-bit transfers but without FIFO support */
else
{
uint8_t byteToSend = 0;
/* SPI configured for 16-bit transfers, no FIFO */
if (bitCount == kSpi16BitMode)
{
uint8_t byteToSendLow = 0;
uint8_t byteToSendHigh = 0;
if (spiState->sendBuffer)
{
byteToSendLow = *(spiState->sendBuffer);
++spiState->sendBuffer;
/* If the extraByte flag is set and these are the last 2 bytes, then skip this */
if (!((spiState->extraByte) && (spiState->remainingSendByteCount == 2)))
{
byteToSendHigh = *(spiState->sendBuffer);
++spiState->sendBuffer;
}
}
SPI_HAL_WriteDataLow(base, byteToSendLow);
SPI_HAL_WriteDataHigh(base, byteToSendHigh);
spiState->remainingSendByteCount -= 2; /* decrement by 2 */
spiState->transferredByteCount += 2; /* increment by 2 */
}
/* SPI configured for 8-bit transfers, no FIFO */
else
{
if (spiState->sendBuffer)
{
byteToSend = *(spiState->sendBuffer);
++spiState->sendBuffer;
}
SPI_HAL_WriteDataLow(base, byteToSend);
--spiState->remainingSendByteCount;
++spiState->transferredByteCount;
}
/* Only enable the receive interrupt. This should be ok since SPI is a synchronous
* protocol, so every RX interrupt we get, we should be ready to send. However, since
* the SPI has a shift register and data buffer (for transmit and receive), things may not
* be cycle-to-cycle synchronous. To compensate for this, enabling the RX interrupt only
* ensures that we do indeed receive data before sending out the next data word. In the
* ISR we make sure to first check for the RX data buffer full before checking the TX
* data register empty flag.
*/
SPI_HAL_SetIntMode(base, kSpiRxFullAndModfInt, true);
}
#else /* For SPI modules that do not support 16-bit transfers */
/* Start the transfer by writing the first byte. If a send buffer was provided, the byte
* comes from there. Otherwise we just send a zero byte. Note that before writing to the
* data register, the status register must first be read, which was already performed above.
*/
uint8_t byteToSend = 0;
if (spiState->sendBuffer)
{
byteToSend = *(spiState->sendBuffer);
++spiState->sendBuffer;
}
SPI_HAL_WriteData(base, byteToSend);
--spiState->remainingSendByteCount;
++spiState->transferredByteCount;
/* Only enable the receive interrupt. This should be ok since SPI is a synchronous
* protocol, so every RX interrupt we get, we should be ready to send. However, since
* the SPI has a shift register and data buffer (for transmit and receive), things may not
* be cycle-to-cycle synchronous. To compensate for this, enabling the RX interrupt only
* ensures that we do indeed receive data before sending out the next data word. In the
* ISR we make sure to first check for the RX data buffer full before checking the TX
* data register empty flag.
*/
SPI_HAL_SetIntMode(base, kSpiRxFullAndModfInt, true);
#endif
return kStatus_SPI_Success;
}
I hope this helps you.
Best Regards,
Iva