Hi,
Ive been trying to understand the SPI polling technique from FRDM-KL25Z(master) with my PIC18F46K22(slave). This worked flawlessly, I could detect all the packets sent over this channel. Now I thought of using my MCP23S17(I/O Expander) with the FRDM-KL25Z. Since ive already tried sending the same instructions on PIC18F and it worked well there I was assuming it would work here as well. But there was absolutely no response from the MCP module. Just to verify ive bricked the module or not i checked with PIC18F and yet again it worked just fine. Ive attached the code its a modification of the existing SPI Looping technique in Master mode available in KSDK1.2.0 examples folder.
C:\Freescale\KSDK_1.2.0\examples\frdmkl25z\driver_examples\spi\spi_polling
My code would read as follows:
#include <string.h>
#include "fsl_spi_master_driver.h"
#include "fsl_clock_manager.h"
#include "fsl_debug_console.h"
#include "board.h"
#include <stdio.h>
// MCP23S17 SPI Slave Device
#define SPI_SLAVE_ID 0x40
#define SPI_SLAVE_ADDR 0x07 // A2=0,A1=0,A0=0
#define SPI_SLAVE_WRITE 0x00
#define SPI_SLAVE_READ 0x01
// MCP23S17 Registers Definition for BANK=0 (default)
#define IODIRA 0x00
#define IODIRB 0x10
#define IOCONA 0x0A
#define GPPUA 0x06
#define GPPUB 0x16
#define GPIOA_Exp 0x09
#define GPIOB_Exp 0x19
/*******************************************************************************
* Definitions
******************************************************************************/
#define SPI_MASTER_INSTANCE (0) /*! User change define to choose SPI instance */
#define TRANSFER_SIZE (64)
#define TRANSFER_BAUDRATE (500000U) /*! Transfer baudrate - 500k */
#define MASTER_TRANSFER_TIMEOUT (5000U) /*! Transfer timeout of master - 5s */
/* Setup the board as a spi master */
int main (void)
{
uint32_t spiSourceClock;
SPI_Type * spiBaseAddr = g_spiBase[SPI_MASTER_INSTANCE];;
/* init the hardware, this also sets up up the SPI pins for each specific SoC */
hardware_init();
OSA_Init();
// Enable clock for SPI
CLOCK_SYS_EnableSpiClock(SPI_MASTER_INSTANCE);
// configure the run-time state struct with the source clock value
spiSourceClock = CLOCK_SYS_GetSpiFreq(SPI_MASTER_INSTANCE);
// Reset the SPI module to it's default state, which includes SPI disabled
SPI_HAL_Init(spiBaseAddr);
// Set SPI to master mode
SPI_HAL_SetMasterSlave(spiBaseAddr, kSpiMaster);
// Set slave select to GPIO output mode
SPI_HAL_SetSlaveSelectOutputMode(spiBaseAddr, kSpiSlaveSelect_AsGpio); /*Change introduced by me since the data need to be sent 3bytes at a time, i.e. 1)SlaveID, 2)Register,3)value*/
// Set the SPI pin mode to normal mode
SPI_HAL_SetPinMode(spiBaseAddr, kSpiPinMode_Normal);
Usr_SPI0_EN; //Defined and configured in gpio_pins.h,pin_mux.c and board.h
Usr_SPI_ON;
// SPI system Enable
SPI_HAL_Enable(spiBaseAddr);
// Configure the bus to access the provided device.
SPI_HAL_SetBaud(spiBaseAddr, TRANSFER_BAUDRATE, spiSourceClock);
// Setup format as same as slave
SPI_HAL_SetDataFormat(spiBaseAddr, kSpiClockPolarity_ActiveHigh, kSpiClockPhase_FirstEdge, kSpiMsbFirst);
// Disable module to clear the shift register
SPI_HAL_Disable(spiBaseAddr);
SPI_HAL_Enable(spiBaseAddr);
//IOCONA register is set to 0x88
Usr_SPI_OFF;
SPI_HAL_WriteDataBlocking(spiBaseAddr, SPI_SLAVE_ID);
SPI_HAL_WriteDataBlocking(spiBaseAddr, IOCONA);
SPI_HAL_WriteDataBlocking(spiBaseAddr, 0x88); //Tried 0x80 as well for Address mode disbaled
Usr_SPI_ON;
//PORTA of IO-expander is set to Output mode
Usr_SPI_OFF;
SPI_HAL_WriteDataBlocking(spiBaseAddr,SPI_SLAVE_ID);
SPI_HAL_WriteDataBlocking(spiBaseAddr, IODIRA);
SPI_HAL_WriteDataBlocking(spiBaseAddr, 0x00);
Usr_SPI_ON;
//Set all pins of PORTA high
Usr_SPI_OFF;
SPI_HAL_WriteDataBlocking(spiBaseAddr, SPI_SLAVE_ID);
SPI_HAL_WriteDataBlocking(spiBaseAddr, GPIOA_Exp);
SPI_HAL_WriteDataBlocking(spiBaseAddr, 0xFF);
Usr_SPI_ON;
while(1)
{
}
}
/*******************************************************************************
* EOF
******************************************************************************/
Regards,
Nelson Lobo
Original Attachment has been moved to: spi_polling-.zip
Solved! Go to Solution.
Dear Nelson,
Regarding your second question, If you use the SPI module of Kl25 as master and want to transfer multiple bytes using the same function so the CS pin toggles once for all the bytes, you can not use the /SS pin of master SPI to generate the output signal to select the slave SPI automatically. I suggest you connect any GPIO pin(even the /SS pin of KL25 can be configured as GPIO output function) of Kl25 to the /SS pin of slave SPI, while the SPI of KL25 is master. Before you transfer the first byte, you can clear the GPIO, then write the first byte to SPI data register, poll the SPTEF bit in SPIx_S, if the bit is set, write the second byte, then poll the SPTEF bit in SPIx_S, ...when the required byte has transfered, set the GPIO, and have a delay. In the process, you have to set the CPHA bit so that the MISO bit is valid by the edge of SPSCK signal.
Regarding your first question, pls check if there are signals for the SPSCK, MOSI,MISO and /SS, if there is issue, pls check the SPI register in the debugger of the tools. I am not clear what your issue is now.
Hope it can help you.
BR
Xiangjun Rong
Hi,
In the attachment please do the following for pin_mux.c:
PORT_HAL_SetMuxMode(PORTC,4u,kPortMuxAsGpio); /* PCS0 */
// PORT_HAL_SetMuxMode(PORTC,4u,kPortMuxAlt2); /* PCS0 */
Since we will be using it as GPIO.
Also is there any way i could send multiple bytes using the same function so the CS pin toggles once for all the bytes, just as my case for MCP23S17.
If there's a better alternative to control this IO expander, Im all ears :smileywink:.
Regards,
Nelson Lobo
Dear Nelson,
Regarding your second question, If you use the SPI module of Kl25 as master and want to transfer multiple bytes using the same function so the CS pin toggles once for all the bytes, you can not use the /SS pin of master SPI to generate the output signal to select the slave SPI automatically. I suggest you connect any GPIO pin(even the /SS pin of KL25 can be configured as GPIO output function) of Kl25 to the /SS pin of slave SPI, while the SPI of KL25 is master. Before you transfer the first byte, you can clear the GPIO, then write the first byte to SPI data register, poll the SPTEF bit in SPIx_S, if the bit is set, write the second byte, then poll the SPTEF bit in SPIx_S, ...when the required byte has transfered, set the GPIO, and have a delay. In the process, you have to set the CPHA bit so that the MISO bit is valid by the edge of SPSCK signal.
Regarding your first question, pls check if there are signals for the SPSCK, MOSI,MISO and /SS, if there is issue, pls check the SPI register in the debugger of the tools. I am not clear what your issue is now.
Hope it can help you.
BR
Xiangjun Rong
Hi xiangjun.rong,
Based on your comments i did use delays in the appropriate instance and now the code works just fine.
Here is the code:
#include <string.h>
#include "fsl_spi_master_driver.h"
#include "fsl_clock_manager.h"
#include "fsl_debug_console.h"
#include "board.h"
#include <stdio.h>
// MCP23S17 SPI Slave Device
#define SPI_SLAVE_ID 0x40
#define SPI_SLAVE_ADDR 0x07 // A2=0,A1=0,A0=0
#define SPI_SLAVE_WRITE 0x00
#define SPI_SLAVE_READ 0x01
// MCP23S17 Registers Definition for BANK=0 (default)
#define IODIRA 0x00
#define IODIRB 0x10
#define IOCONA 0x0A
#define GPPUA 0x06
#define GPPUB 0x16
#define GPIOA_Exp 0x09
#define GPIOB_Exp 0x19
/*******************************************************************************
* Definitions
******************************************************************************/
#define SPI_MASTER_INSTANCE (0) /*! User change define to choose SPI instance */
#define TRANSFER_SIZE (64)
#define TRANSFER_BAUDRATE (1000000U) /*! Transfer baudrate - 500k */
#define MASTER_TRANSFER_TIMEOUT (5000U) /*! Transfer timeout of master - 5s */
void wait_tcy(unsigned int wait);
/* Setup the board as a spi master */
int main (void)
{
uint32_t spiSourceClock;
SPI_Type * spiBaseAddr = g_spiBase[SPI_MASTER_INSTANCE];;
/* init the hardware, this also sets up up the SPI pins for each specific SoC */
hardware_init();
OSA_Init();
// Enable clock for SPI
CLOCK_SYS_EnableSpiClock(SPI_MASTER_INSTANCE);
// configure the run-time state struct with the source clock value
spiSourceClock = CLOCK_SYS_GetSpiFreq(SPI_MASTER_INSTANCE);
// Reset the SPI module to it's default state, which includes SPI disabled
SPI_HAL_Init(spiBaseAddr);
// Set SPI to master mode
SPI_HAL_SetMasterSlave(spiBaseAddr, kSpiMaster);
// Set slave select to GPIO output mode
SPI_HAL_SetSlaveSelectOutputMode(spiBaseAddr, kSpiSlaveSelect_AsGpio); /*Change introduced by me since the data need to be sent 3bytes at a time, i.e. 1)SlaveID, 2)Register,3)value*/
// Set the SPI pin mode to normal mode
SPI_HAL_SetPinMode(spiBaseAddr, kSpiPinMode_Normal);
Usr_SPI0_EN; //Defined and configured in gpio_pins.h,pin_mux.c and board.h
Usr_SPI_OFF;
// SPI system Enable
SPI_HAL_Enable(spiBaseAddr);
// Configure the bus to access the provided device.
SPI_HAL_SetBaud(spiBaseAddr, TRANSFER_BAUDRATE, spiSourceClock);
// Setup format as same as slave
SPI_HAL_SetDataFormat(spiBaseAddr, kSpiClockPolarity_ActiveHigh, kSpiClockPhase_FirstEdge, kSpiMsbFirst);
// Disable module to clear the shift register
SPI_HAL_Disable(spiBaseAddr);
SPI_HAL_Enable(spiBaseAddr);
//IOCONA register is set to 0x88
Usr_SPI_ON;
SPI_HAL_WriteDataBlocking(spiBaseAddr, SPI_SLAVE_ID);
SPI_HAL_WriteDataBlocking(spiBaseAddr, IOCONA);
SPI_HAL_WriteDataBlocking(spiBaseAddr, 0x88); //Tried 0x80 as well for Address mode disbaled
OSA_TimeDelay(1); //wait for 1ms
Usr_SPI_OFF;
//PORTA of IO-expander is set to Output mode
Usr_SPI_ON;
SPI_HAL_WriteDataBlocking(spiBaseAddr,SPI_SLAVE_ID);
SPI_HAL_WriteDataBlocking(spiBaseAddr, IODIRA);
SPI_HAL_WriteDataBlocking(spiBaseAddr, 0x00);
OSA_TimeDelay(1); //wait for 1ms
Usr_SPI_OFF;
//Set all pins of PORTA high
Usr_SPI_ON;
SPI_HAL_WriteDataBlocking(spiBaseAddr, SPI_SLAVE_ID);
SPI_HAL_WriteDataBlocking(spiBaseAddr, GPIOA_Exp);
SPI_HAL_WriteDataBlocking(spiBaseAddr, 0x05);
OSA_TimeDelay(1); //wait for 1ms
Usr_SPI_OFF;
while(1)
{
//Set all pins of PORTA high
Usr_SPI_ON;
SPI_HAL_WriteDataBlocking(spiBaseAddr, SPI_SLAVE_ID);
SPI_HAL_WriteDataBlocking(spiBaseAddr, GPIOA_Exp);
SPI_HAL_WriteDataBlocking(spiBaseAddr, 0x05);
OSA_TimeDelay(1); //wait for 1ms
Usr_SPI_OFF;
OSA_TimeDelay(1000); //wait for 1sec
//Set all pins of PORTA high
Usr_SPI_ON;
SPI_HAL_WriteDataBlocking(spiBaseAddr, SPI_SLAVE_ID);
SPI_HAL_WriteDataBlocking(spiBaseAddr, GPIOA_Exp);
SPI_HAL_WriteDataBlocking(spiBaseAddr, 0x00);
OSA_TimeDelay(1); //wait for 1ms
Usr_SPI_OFF;
OSA_TimeDelay(1000); //wait for 1sec
}
}
void wait_tcy(unsigned int wait)
{
do
{
;
}while(--wait!=0);
}
/*******************************************************************************
* EOF
******************************************************************************/
I did try waiting for 100 time cycles instead of 1ms which according to the datasheet should be sufficient but doesn't work always,
This isn't the case in PIC18f controllers wherein you could toggle the GPIO to disable SPI immediately. Am i missing something???
Regards,
Nelson Lobo