Dear stack overflow users, I have built a device with a master device, and a network of 10 slaves. All of them communicate via 4 wire SPI. Right now I am writing the program for both boards, and they don't seem to be working, I do not get expected responses.
I have a master board, and 10 of identical slave boards. The protocol is simple - as with SPI any transaction is initiated by the master device, and a command is sent. The selected slave then receives aforemetioned command, sets a busy flag pin high, and checks if it's valid. After parsing the command the busy bin is released, and if the command is valid, same byte as received is sent to the master, otherwise an error marker is sent. After that, any necessary data exchanges are executed. I've tried configuring the IO's as regular portf, and their Alternative Functions, also I tried resetting the SPI periph after each transaction and nothing seems to be working.
This is what I get: https://imgur.com/a/MICEx2f The channels are from the top, respectively: MOSI,MISO,CLK, and busy flag. I get no response from the slave, no matter what. The command is interpreted correctly (debug data from UART), however nothing is sent back.
This is the SPI part of code for the SLAVE device:
uint8_t spi_sendrecv(uint8_t byte)
{
// poczekaj az bufor nadawczy bedzie wolny
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, byte);
// poczekaj na dane w buforze odbiorczym
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
return SPI_I2S_ReceiveData(SPI1);
}
uint8_t SPI_get_cmd_ack(void)
{
uint8_t cmd;
uint8_t valid_flag;
//In cas if the BF pin was left high
BF_OUT_low();
//Let's wait for some data
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
cmd = SPI_I2S_ReceiveData(SPI1);
//cmd = SPI_get_command();
//Check the cmd
BF_OUT_high();
valid_flag = SPI_check_for_valid_cmd(cmd);
//SPI_reset_flush();
BF_OUT_low();
if(valid_flag == CMD_RET_STATUS_VALID)
{
spi_sendrecv(cmd);
return cmd;
}
else
{
spi_sendrecv(CMD_ERROR);
return CMD_ERROR;
}
}
And this is the MASTER part:
//Sends a command to a slave device
//Param1: slave device no, from 0 to 9
//Param2: command to send
//Retval: command send success or failure:
//DATA_TRANSFER_OK or DATA_TRANSFER_ERR
uint8_t SPI_send_command(uint8_t slave_no, uint8_t cmd)
{
uint8_t cnt = 0;
uint8_t rx_cmd;
//SPI_reset();
//Select the correct slave
SPI_select_slave(0);
delay_ms(0);
SPI_select_slave(slave_no);
delay_ms(0);
//Transmit the cmd
SPI_sendrecv(cmd);
//SPI_reset();
//Wait for the busy flag indication
while(SPI_get_busy_flag(slave_no) == Bit_RESET)
{
if(cnt < SPI_RETRY_COUNT)
{
++cnt;
delay_ms(1);
}
else
{
SPI_select_slave(0);
return DATA_TRANSFER_ERR;
}
}
//Same for the busy flag on:
while (SPI_get_busy_flag(slave_no) == Bit_SET)
{
if(cnt < SPI_RETRY_COUNT)
{
++cnt;
delay_ms(1);
}
else
{
SPI_select_slave(0);
return DATA_TRANSFER_ERR;
}
}
rx_cmd = SPI_sendrecv(0);
//SPI_reset();
if(rx_cmd == cmd) return DATA_TRANSFER_OK;
else return DATA_TRANSFER_ERR;
}
And here are the initialization parts of the code, slave and master respectively:
void SPI_init(void)
{
GPIO_InitTypeDef SPI_GPIO;
SPI_InitTypeDef SPI;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
//GPIOA5 SCK
//GPIOA6 MISO
//GPIOA7 MOSI
SPI_GPIO.GPIO_Mode = GPIO_Mode_AF;
SPI_GPIO.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
SPI_GPIO.GPIO_PuPd = GPIO_PuPd_DOWN;
SPI_GPIO.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA, &SPI_GPIO);
SPI_GPIO.GPIO_Pin = GPIO_Pin_15;
SPI_GPIO.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &SPI_GPIO);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource15, GPIO_AF_SPI1);
//Busy flag
SPI_GPIO.GPIO_Mode = GPIO_Mode_OUT;
SPI_GPIO.GPIO_OType = GPIO_OType_PP;
SPI_GPIO.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOC, &SPI_GPIO);
/*SPI_GPIO.GPIO_Mode = GPIO_Mode_IN;
SPI_GPIO.GPIO_PuPd = GPIO_PuPd_UP;
SPI_GPIO.GPIO_Pin = GPIO_Pin_15;
GPIO_Init(GPIOA, &SPI_GPIO);*/
SPI.SPI_CPHA = SPI_CPHA_1Edge;
SPI.SPI_CPOL = SPI_CPOL_Low;
SPI.SPI_DataSize = SPI_DataSize_8b;
SPI.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI.SPI_FirstBit = SPI_FirstBit_MSB;
SPI.SPI_Mode = SPI_Mode_Slave;
SPI.SPI_NSS = SPI_NSS_Hard;
SPI_Init(SPI1, &SPI);
SPI_Cmd(SPI1, ENABLE);
SPI_aux_tim_conf();
}
static void SPI_IO_conf(void)
{
//Struct
GPIO_InitTypeDef SPI_IO;
//CLK
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOE, ENABLE);
//Conf
SPI_IO.GPIO_Mode = GPIO_Mode_AF;
//5 - SCK, 6 - MISO, 7- MOSI
SPI_IO.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7 | GPIO_Pin_6;
SPI_IO.GPIO_PuPd = GPIO_PuPd_DOWN;
SPI_IO.GPIO_OType = GPIO_OType_PP;
SPI_IO.GPIO_Speed = GPIO_Speed_25MHz;
//Init
GPIO_Init(GPIOA, &SPI_IO);
//Connect to SPI periph
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
//For busy flag checking
SPI_IO.GPIO_Mode = GPIO_Mode_IN;
SPI_IO.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 |GPIO_Pin_12 |GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
SPI_IO.GPIO_PuPd = GPIO_PuPd_DOWN;
SPI_IO.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOE, &SPI_IO);
SPI_IO.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOB, &SPI_IO);
}
static void SPI_periph_conf(void)
{
//Struct
SPI_InitTypeDef SPI_conf;
//CLK
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
//Conf
//SysClk = 84000000
//84/64 = 1,3125MHz
SPI_conf.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
SPI_conf.SPI_CPHA = SPI_CPHA_1Edge;
SPI_conf.SPI_CPOL = SPI_CPOL_Low;
//SPI_conf.SPI_CRCPolynomial =
SPI_conf.SPI_DataSize = SPI_DataSize_8b;
SPI_conf.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_conf.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_conf.SPI_Mode = SPI_Mode_Master;
SPI_conf.SPI_NSS = SPI_NSS_Soft;
//Conf, enable
SPI_Init(SPI1, &SPI_conf);
SPI_Cmd(SPI1, ENABLE);
//SPI_Cmd(SPI1, DISABLE);
}
As You can see on the oscillogram, there is no response from the Slave, The expected response is the same command that was sent in the previous cycle by the master. Eg, I send a 0x01 presence command, and the slave should respond with the same byte, after that, any other exchanges should occur, which are not implemented yet.
Best regards, Marek