cancel
Showing results for 
Search instead for 
Did you mean: 

STM32f4 SPI Busy Flag

spencerashiveley
Associate II
Posted on August 07, 2015 at 03:03

Hello all,

I'm trying to communicate with a nokia 5110 LCD. The nokia 5110 has a slave select bit that I am setting using a GPIO pin (because I'm not entirely sure how the NSS bit for SPI works). My problem is that when I send a transmission I wait for the busy flag to go down before I reset this slave select, the problem is the busy flag never sets so the slave select is being reset immediately and the nokia 5110 doesn't get the data.

here's my initialization code:

SPI_InitTypeDef SPI_InitDef;
GPIO_InitTypeDef GPIO_InitDef;
//Initialization of gpio port A for SPI
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitDef.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitDef.GPIO_Mode = GPIO_Mode_AF; //using alternative function
GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1); //set PA5 to SPI1_Sclk
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1); //set PA6 to MISO (won't be used though, data only flows to Nokia5110)
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1); //set PA7 to MOSI
GPIO_Init(GPIOA, &GPIO_InitDef);
//Initiazation of gpio port C PC4 -> used for Data/Command (D/C) to Nokia 5110
//Data: PC4 is high
//Command: PC4 is low
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
GPIO_InitDef.GPIO_Pin = GPIO_Pin_2| GPIO_Pin_4 | GPIO_Pin_5; //Pin 2 is Reset, Pin 4 is D/C, Pin 5 is CS
GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(GPIOC,&GPIO_InitDef);
//Initialization of SPI1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); //enable clock for SPI1
SPI_InitDef.SPI_Direction = SPI_Direction_1Line_Tx;//only using Tx
SPI_InitDef.SPI_Mode = SPI_Mode_Master;//STM32f4 is master
SPI_InitDef.SPI_DataSize = SPI_DataSize_8b;
SPI_InitDef.SPI_CPOL = SPI_CPOL_Low; //Sclk is low in between transmissions
SPI_InitDef.SPI_CPHA = SPI_CPHA_1Edge;//clock data in on rising edge
SPI_InitDef.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;// clk frequency = APB2/32 = 84MHz/32 = 2.625MHz
SPI_InitDef.SPI_FirstBit = SPI_FirstBit_LSB; //data is transmitted LSB first
SPI_InitDef.SPI_NSS = SPI_NSS_Soft;
SPI_Init(SPI1, &SPI_InitDef);//initialize spi1
SPI_Cmd(SPI1, ENABLE);//enable spi1

and here is my SPI transmission:

void static lcdwrite(enum typeOfWrite type, char message){
//SPI isn't quite working yet, Busy flag never seems to go high. Possibly because of NSS pin
if(type == COMMAND){
// wait until SSI0 not busy/transmit FIFO empty
while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE)){};
GPIO_ResetBits(GPIOC, GPIO_Pin_4|GPIO_Pin_5);
SPI1->DR = message; // command out, wait until SSI0 not busy/transmit FIFO empty
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY)){};
GPIOC->ODR |= (0x1<<
5
);
} else{
while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE)){}; // wait until transmit FIFO not full
GPIO_ResetBits(GPIOC,GPIO_Pin_5); //Chip select is active low
GPIO_SetBits(GPIOC, GPIO_Pin_4);
SPI1->DR = message;
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY)){}; //wait until transmission complete (not working)
GPIOC->ODR |= (0x1<<5); // bring chip select high
}
}

Any help would be greatly appreciated. the function SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) keeps returning 0 so the while loop is skipped.

#!stm32f4-disco
2 REPLIES 2
Posted on August 07, 2015 at 04:31

''During discontinuous communications, there is a 2 APB clock period delay between the

 

write operation to SPI_DR and the BSY bit setting. As a consequence, in transmit-only

 

mode, it is mandatory to wait first until TXE is set and then until BSY is cleared after writing the last data.''

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
spencerashiveley
Associate II
Posted on August 07, 2015 at 15:58

So I found what you were talking about in the reference manual. I tried adding a wait loop to wait for the TXE flag, but that flag never seems to go low in the first place. This seems to imply that data is written directly to the register. So adding that loop didn't help. Any ideas?

here's the new code:

void static lcdwrite(enum typeOfWrite type, char message){ 
//SPI isn't quite working yet, TXE flag never goes low and busy flag never sseems to go high. Possibly because of NSS pin?
if(type == COMMAND){
// wait until SSI0 not busy/transmit FIFO empty
while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE)){};
GPIO_ResetBits(GPIOC, GPIO_Pin_4|GPIO_Pin_5);
SPI1->DR = message; // command out // wait until SSI0 not busy/transmit FIFO empty
while(!(SPI1->SR & SPI_I2S_FLAG_TXE));
while(SPI1->SR & SPI_I2S_FLAG_BSY);
//while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY)){};
GPIOC->ODR |= (0x1<<
5
);
} else{
while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE)){}; // wait until transmit FIFO not full
GPIO_ResetBits(GPIOC,GPIO_Pin_5);
GPIO_SetBits(GPIOC, GPIO_Pin_4);
SPI1->DR = message;
while(!(SPI1->SR & SPI_I2S_FLAG_TXE)); //wait until TXE flag is set
while(SPI1->SR & SPI_I2S_FLAG_BSY); //wait for SPI to be not busy.
//while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY));
GPIOC->ODR |= (0x1<<5); // data out
}
}