2009-03-31 12:06 PM
SPI Master Receive problem
2011-05-17 04:08 AM
Hi guys,
I am currently working on the STM32 performance stick to evaluate (rather develop software to test our pcb) and I am getting very frustrated with myself. As said, I am using a hitex stm32 together with an ADC over SPI. The SPI MOSI works like a charm and I get the proper response from the ADC (as observed over an oscilloscope). The problem begins with the receiving of the data from the ADC (in fact, from the pin at all). I always get 0xFF on the Data register of the SPI I am using. This is quite frustrating tbh. Now, I have also tested the provided example SPI fullduplex code (from the FW download) and it fails 2 tests. It seems that receiving works when being a slave, but it doesnt seem to work when in Master mode. Here is the code I use: Can anyone give me a hint as to what could possibly be wrong?Code:
u32 get_pressure_value(void) <BR>{ <BR> pressureValue = 0; <BR> GPIO_ResetBits(GPIOC, GPIO_Pin_8); <BR> <BR> //wait for conversion to finish <BR> //while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) == Bit_SET); <BR> <BR> SPI_I2S_SendData(SPI1, READ_OP); <BR> //wait for transfer to complete <BR> while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); <BR> LowReceived = SPI_I2S_ReceiveData(SPI1); <BR> <BR> SPI_I2S_SendData(SPI1, READ_OP); <BR> //wait for transfer to complete <BR> while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); <BR> MedReceived = SPI_I2S_ReceiveData(SPI1); <BR> <BR> SPI_I2S_SendData(SPI1, READ_OP); <BR> //wait for transfer to complete <BR> while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); <BR> HighReceived = SPI_I2S_ReceiveData(SPI1); <BR> <BR> //GPIO_SetBits(GPIOC, GPIO_Pin_8); <BR> pressureValue = LowReceived; <BR> pressureValue = pressureValue << BYTE_SHIFT; <BR> pressureValue = pressureValue & MED_MASK; <BR> <BR> pressureValue = pressureValue | MedReceived; <BR> pressureValue = pressureValue << BYTE_SHIFT; <BR> pressureValue = pressureValue & HIGH_MASK; <BR> <BR> pressureValue = pressureValue | HighReceived; <BR> <BR> GPIO_SetBits(GPIOC, GPIO_Pin_8); <BR> <BR> return pressureValue;
[ This message was edited by: wattos on 30-03-2009 18:50 ]2011-05-17 04:08 AM
and the initialization:
Code:
void pressure_GPIO() { GPIO_InitTypeDef GPIO_InitStructure; /* Configure SPI1 pins: SCK, MISO and MOSI ---------------------------------*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); //Chip select pin GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_SetBits(GPIOC, GPIO_Pin_8); } void pressure_config() { int i; SPI_InitTypeDef SPI_InitStructure; SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //biderectional sending SPI_InitStructure.SPI_Mode = SPI_Mode_Master; // STM32 is the master SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 8b send and receive SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; // idle clock is high SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; // capture data on 2nd edge SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; // chip select managed by software not hardware SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //the rate at which we send + receive. we downscale by 16 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // send most significant but first SPI_InitStructure.SPI_CRCPolynomial = 7; // CRC calculation. Not important for us SPI_Init(SPI1, &SPI_InitStructure); /* Enable SPI1 */ SPI_Cmd(SPI1, ENABLE); //wait for the buffer to be empty before trying to send anything while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); /* Send SPI1 data */ GPIO_ResetBits(GPIOC, GPIO_Pin_8); //reset adc, 1111111111111.... 32 one's on the input will reset the adc for(i=0; i < 4; i++){ SPI_I2S_SendData(SPI1,RESET_OP); //wait for transfer to WAIT_FOR_TRANSFER_COMPLETION; } //delay 1 millisecond after the reset of the adc delay(1); SPI_I2S_SendData(SPI1, WRITE_MODE_REGISTER ); WAIT_FOR_TRANSFER_COMPLETION; SPI_I2S_SendData(SPI1, 0 ); WAIT_FOR_TRANSFER_COMPLETION; SPI_I2S_SendData(SPI1, 0x41 ); WAIT_FOR_TRANSFER_COMPLETION; SPI_I2S_SendData(SPI1, CONTINUOUS_READ); WAIT_FOR_TRANSFER_COMPLETION; GPIO_SetBits(GPIOC, GPIO_Pin_8); }2011-05-17 04:08 AM
forgive me - haven't time this day to read all of your listing.
Are you aware that STM32 NSS-CS pin is not hardware/automatic driven low? This is likely explanation of why you work ok as slave (NSS-CS) pin ''normal/customary'' while slave - in unique STM32 mistake mode when used as master. Several posts down you can read long list of forum ''protests'' - until lead clients complain appears our urgings will continue unheeded...2011-05-17 04:08 AM
Hey,
Thanks for the speedy answer. So are you saying, that as a Master I need to set the NSS register to receive any data? I was under the impression that NSS is only used to select slaves (I am using PC8 for that as we have several slaves) So after reading the documentation, Is it true that I need to set SSM and SSI bits for my master to receive any input? Is this because of multi master support? So what I need to call is: void SPI_NSSInternalSoftwareConfig(SPI_TypeDef* SPIx, u16 SPI_NSSInternalSoft) right? [ This message was edited by: wattos on 30-03-2009 20:07 ] [ This message was edited by: wattos on 30-03-2009 20:14 ]2011-05-17 04:08 AM
I'm on the road - don't have access to all details.
Goal was to alert you to the fact that ''if'' your ADC-SPI_Slave requires a CS (low going) standard SPI control signal - STM32 does NOT generate this automatically via hardware. You must do this via software! (ugh) Check your SPI_ADC data sheet carefully - some SPI slaves allow their CS pin to be ''tied'' to ground. Then you may ignore the STM32s lack of standard SPI signal generation. However some slaves ''require'' that the CS pin toggle - in this case you will have to ''wiggle'' this pin via your software...2011-05-17 04:08 AM
Hey,
Thanks for your time. As said, I already have a custom Slave select PC8 which I use just like a GPIO. The reason for this is that on our final PCB we have multiple Slaves so we also need multiple cs anyways2011-05-17 04:08 AM
Hey,
Again, I really appreciate your quick response. I however think I am not being clear. I have no problems with the ADC/. I have already studied the datasheet and the input to the ADC is correct and it reacts properly to all input. The problem is the STM32 itself. No matter what is on the MISO pin it always returns 0xFF (I grounded the MISO and still received 0xFF instead of 0x00). That is my real problem, I somehow cannot get the right values from the SPI peripheral. Thanks again for your time btw. the SPI example in the firmware library has exactly the same problem [ This message was edited by: wattos on 30-03-2009 22:43 ]2011-05-17 04:08 AM
Going ''wheels up'' in moments...
Your custom slave-select pcb must satisfy the needs of each/every slave SPI device. Some of these - especially ADCs - may require that the CS line toggle per each conversion. Be sure that your hardware and your hw's interaction with STM32 NSS_CS meets your slave's spec. (I'd scope the Slave CS pin after studying its data-sheet) Should your pcb ''look for'' an active low NSS_CS as an input from the STM32 - you will have to generate this signal manually in software. This is what I've sought to convey. As always - suggest that you use simplest SPI device you have/can find to gain mastery of the STM32. There are good examples in code libraries...2011-05-17 04:08 AM
Early in your posting - ''SPI receive works when in Slave mode.'' If this is the same pin that you later use in Master mode - and which fails - I would closely compare your set-up and enabling of Master mode SPI. (especially clocks) I bet that you have set-up mistake.
I would look for the simplest STM32 library code with SPI master mode - and attempt to implement that. If this still fails I would revert to SPI Slave mode - and confirm that your MISO pin still works. I recall that there are neat ''loop-back'' examples - which may enable you to test 2 SPI ports within a single exercise. As always - devil is in details - STM32 does work in SPI (with NSS_CS exception/forum protest)...