STM32F0 SPI loopback - No data on MISO - stm32

I am trying to loopback the SPI bus on my STM32F0 (with a discovery board, MISO pin connected to MOSI pin).
I am following the tutorial Discovering the STM32 Microcontroller, (edition January 18, 2014), Exercise 6.1 : SPILoopback.
The STM32 is configured as the master.
To send a byte to MOSI pin, the author wrote :
SPI_I2S_SendData (SPIx, *tbuf++);
where :
SPIx is the SPI bus I want to send data
tbuf is the uint8 (in other words an unsigned char ...) I want to send on the bus
To receive this byte from MISO pin, he wrote :
while (SPI_I2S_GetFlagStatus (SPIx, SPI_I2S_FLAG_RXNE) == RESET);
if (rbuf)
{
*rbuf++ = SPI_I2S_ReceiveData(SPIx);
...
...
The flag SPI_I2S_FLAG_RXNE should be SET since I send a data to MOSI pin, and since MOSI pin is connected to MISO pin.
My problem is :
I never go out from the while loop (the SPI_I2S_FLAG_RXNE is never SET, even if I look through the debugger.
(I see CLK and MOSI being alive on my logic analyser, so I'm sure my byte goes out from an electrical point of view.)
It is like the STM32 never received the byte, even if MISO pin is connected on MOSI pin ...
Why ?

It is because on STM32F0, the flag SPI_I2S_FLAG_RXNE is set by default only when 16 bits (so 2 bytes) are received on MISO pin.
If you send 2 bytes and then do you while loop, you should exit of the loop very quickly.
The Reference Manual said (Section SPI status flags) :
The RXNE flag is set depending on the FRXTH bit value in the SPIx_CR2 register:
If FRXTH is set, RXNE goes high and stays high until the RXFIFO level is greater or equal to 1/4 (8-bit).
If FRXTH is cleared, RXNE goes high and stays high until the RXFIFO level is greater than or equal to 1/2 (16-bit).
So, if you want the flag SPI_I2S_FLAG_RXNE to be set when only 1 byte is received, you should use the following function :
SPI_RxFIFOThresholdConfig (SPIx, SPI_RxFIFOThreshold_QF);
SPI_RxFIFOThreshold_QF: RXNE event is generated if the FIFO level is greater or equal to 1/4.
SPI_RxFIFOThreshold_HF: RXNE event is generated if the FIFO level is greater or equal to 1/2. (default value)

Related

STM32F429 GPIO DMA Read and Write

Hello,
I'm making a project where I want to bit-bang the JTAG protocol.
According to the AN4666 provided by ST, DMA + GPIO can achieve high speeds in bit-banging synchronous protocols.
I want to:
Generate N PWM pulses (the CLK signal).
With the falling edge of each pulses, I want to set some GPIO with DMA.
With the rising edge, I want to read from the GPIO using DMA.
What is the best way to achieve these specs using HAL?
even withtout dma you can reach quite high freq bit banged i/o i'll say in range 2 - 10MHz assuming fast enougth mcu and gpio bus clock high enough (48 96MHz)
Clock just wan't be as stable and may suffer "stall" say idle time when iterrupt occur vs dma. but is way simpler
for DMA base , if you use 3 bit of one port, one for clk and one for TDI and one for TDO then use 2 dma one to wr and one that rd on same timer source (if possible) at double rate of the TCK signal
the data in is rebuilt by taking teh i bit of one read data over 2
index like 0 2 4 or 1 3 5 ... depending on edge you want and how you wr clk array in mem is coded.
last if your jtag chain is 8 bit multiple SPI is even simpler and dma easy ;)

STM32 SPI Data Packing

I can't get the SPI on my STM32f3 discovery board (Datasheet) to work with gyroscope sensor (I3G4250D) on the register level. I know I'm sending data since I'm in full duplex and receiving dummy bytes from sensor using 16 bit data packing but when I try to receive using 8 bit access to DR register I get inconsistent values from sensor, sometimes returning one byte 0xff and other times returning 2 bytes 0xffff (at least I think that's what's happening) but no real values from from the sensor register I want to read. I think this has to do with automatic packing of STM32 SPI on my chip but I think I am addressing that by accessing DR register with uint8_t* but it doesn't seem to work. I also want to ask that when I compare the SPI protocol on sensor (datasheet page 24) and STM32 datasheet (page 729) I infer that both CPOL (clock polarity) and CPHA (clock phase) bits in STM32 SPI should be set but I seem to be able to at least send data with or without these bits set...
Here is my SPI Initialization function which includes trying to read bytes at the end of it and a write a byte to sensor register function:
void SPI_Init() {
/* Peripheral Clock Enable */
RCC->AHBENR |= RCC_AHBENR_GPIOEEN|RCC_AHBENR_GPIOAEN;
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
/* GPIO Configuration */
GPIOA->MODER |= GPIO_MODER_MODER5_1|GPIO_MODER_MODER6_1|GPIO_MODER_MODER7_1; //Alternate function
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR5|GPIO_OSPEEDER_OSPEEDR6|GPIO_OSPEEDER_OSPEEDR7; //High speed
GPIOA->AFR[0] |= 0x00500000|0x05000000|0x50000000; //AF for SCK,MISO,MOSI
GPIOE->MODER |= GPIO_MODER_MODER3_0; //Port E for NSS Pin
GPIOE->MODER |= GPIO_MODER_MODER3_0;
/* SPI Configuration */
SPI1->CR2 |= SPI_CR2_FRXTH|SPI_CR2_RXDMAEN; //Enable DMA but DMA is not used
// not sure if I need this?|SPI_CR1_CPOL|SPI_CR1_CPHA;
SPI1->CR1 |= SPI_CR1_BR_1|SPI_CR1_SSM|SPI_CR1_SSI|SPI_CR1_MSTR|SPI_CR1_SPE; //big endian, SPI#6MH, since using software set SPI_CR1_SSI to high for master mode
/* Slave Device Initialization */
SPI_WriteByte(CTRL_REG1_G,0x9f);
SPI_WriteByte(CTRL_REG4_G,0x10);
SPI_WriteByte(CTRL_REG5_G,0x10);
//receive test
uint8_t test =0xff;
uint8_t* spiDrPtr = (__IO uint8_t*)&SPI1->DR;
*spiDrPtr = 0x80|CTRL_REG1_G;
while(!(SPI1->SR & SPI_SR_TXE)){}
//SPI1->CR2 &= ~(SPI_CR2_FRXTH); //this is done in HAL not sure why though
*spiDrPtr = test; //Send dummy
while(!(SPI1->SR & SPI_SR_RXNE)){}
test = *spiDrPtr;
}
static void SPI_WriteByte(uint8_t regAdd, uint8_t data) {
uint8_t arr[2] = {regAdd,data}; //16 bit data packing
SPI1->DR = *((uint16_t*)arr);
}
Any suggestions?
Do not enable DMA if you do not use it.
You need to force 16 bit access (not 32 bits)
static void SPI_WriteByte(uint8_t regAdd, uint8_t data) {
uint8_t arr[2] = {regAdd,data}; //16 bit data packing
*(volatile uint16_t *)&SPI1->DR = *((volatile uint16_t*)arr);
}
Try using FRXTH = 0, and do all DR reads and writes in 16-bit words, then just discard the first byte.
To the later question, about CPOL/CPHA. These bits control SPI transfer format on the bit level. Refer to the following image (from wikipedia).
CPOL = 0, CPHA = 0 is also called "SPI mode 0", data bits are sampled on the SCK rising edge
CPOL = 1, CPHA = 1 is also called "SPI mode 3", data bits are also sampled on the rising edge.
The difference between two modes is SCK level between transfers, and an extra falling edge before the first bit.
Some chips states explicitly that both mode 0 and mode 3 are supported. Yet in the I3G4250D datasheet, section 5.2: "SDI and SDO are,
respectively, the serial port data input and output. These lines are driven at the falling edge
of SPC and should be captured at the rising edge of SPC."
When data is sent to the chip from mcu in mode 0, mcu drives the MOSI line before the first rising edge. Thus a slave chip can recieve valid data in both mode 0 and mode 3. But when data is transfered from chip to the mcu, chip may need the first falling SCK edge to shift/latch first data bit to the MISO line and with mode 0 you'll receive the readings shifted on one bit.
I've emphasised 'may' word, because the chip could still work correcly in both modes, latching the first bit with falling nSS-edge, the manufacturer just didn't do the testings, or doesn't guarantees that it'll work with other revisions and in all conditions.

SPI MISO-MOSI signal are the same on oscilloscope

I try to read a memory cell from a chip with my stm32f103 uC. I send three bytes, one instruction then 2 address bytes. Watching this on a scope I get the MOSI signals back, not the same level, but attenuated. Is that normal? If something's wrong with my chip, should the MOSI signal reflect back on the MISO pin?
You need to send more than 3 bytes master generates the clock. To read something master needs to send dummy bytes.

Reading PWM signals in STM32F407

I am doing a quadcopter using a STM32F407 discovery. I was finally able to stabilize it. Now i am trying to use the RC receiver so i can control my quadcopter movements. Is there a way to read the signal of PWM of my RC receiver channels ??
Also my RC receiver supports PPM and according to what i understand it receives a packet of duty cycles strong textbut still don't know how to receive this.
You can use the SPI interface to encode the PPM (or the PWM) signal of your RC receiver.
General approach:
Connect the PPM signal to the MISO pin and a second one of the controller (simultaneously). MOSI, CLK, and CS pins are not needed.
Initialize the SPI interface with a appropriate clock. With this frequency the signal will be shifted in the controller. Try to use 4kHz.
Depending on the idle state of the signal enable either rising or falling edge interrupt trigger on the second pin. This will used to trigger incoming frames.
If the interrupt occurs disable the trigger temporary and start spi transmission to get several bytes (outgoing ingored and not connected). Depending on the Frame length 8 or 10 Bytes should do it. This will catch frames up to 20ms.
After you get the all bytes enable the trigger again and repeat for the next frame.
The received data should contain the pattern of the pwm/ppm signal.
You should also match the sampling rate and the amount of bytes to receive with your RC receiver.

STM32F427's USART1 sometimes sets 8th data bit as if it would be parity bit

I'm working with STM32F427 UASRT1 via the following class:
void DebugUartOperator::Init() {
// for USART1 and USART6
::RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
// USART1 via PORTA
::RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
::GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
::GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
GPIO_InitTypeDef GPIO_InitStruct;
// fills the struct with the default vals:
// all pins, mode IN, 2MHz, PP, NOPULL
::GPIO_StructInit(&GPIO_InitStruct);
// mission-specific settings:
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
::GPIO_Init (GPIOA, &GPIO_InitStruct);
USART_InitTypeDef USART_InitStruct;
// 9600/8/1/no parity/no HWCtrl/rx+tx
::USART_StructInit(&USART_InitStruct);
USART_InitStruct.USART_BaudRate = 921600;
USART_InitStruct.USART_WordLength = USART_WordLength_9b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_Odd;
::USART_Init(USART1, &USART_InitStruct);
::USART_Cmd(USART1, ENABLE);
}
void DebugUartOperator::SendChar(char a) {
// wait for TX register to become empty
while(::USART_GetFlagStatus(USART1, USART_FLAG_TXE) != SET);
::USART_SendData(USART1, static_cast<uint8_t>(a));
}
The problem is that every now and then USART starts ignoring actual 8th data bit and setting it as a parity bit (odd parity, to be specific). The strangest of all that it sometimes happens even after a long poweroff, without any prior reprogramming or something. For example yesterday evening it was all OK, then next morning I come to work, switch the device on and it starts working the way described. But it's not limited to this, it may randomly appear after some next restart.
That effect is clearly visible with the oscilloscope and with different UART-USB converters used with diffrent programs. It is even possible, once this effect have appeared, to reprogram a microcontroller to transmit test data sets. For example, 0x00 to 0xFF in endless cycle. It does not affect the problem. Changing speeds (down to 9600 bps), bits per word, parity control does not help - the effect remains intact even after repropramming (resulting for example in really abnormal 2 parity bits per byte). Or, at least, while UASRT is being initialized and used in the usual order according to my program's workflow.
The only way to fix it is to make the main() function do the following:
int main() {
DebugUartOperator dua;
dua.Init();
while(1) {
uint8_t i;
while(++i)
dua.SendChar(i);
dua.SendChar(i);
}
}
With this, after reprogramming and restart, the first few bytes (up to 5) are transmitted rotten but then everything works pretty well and continues to work well through further restarts and reprograms.
This effect is observed on 2 different STM32F427s on 2 physically different boards of the same layout. No regularity is noticed in its appearance. Signal polarity and levels conform USART requirements, no noise or bad contacts are dectected during investigation. There seems to be no affection to UASRT1 from the direction of other code used in my program (either mine or library one) or it is buried deeply. CMSIS-OS is used as RTOS in the project, with Keil uVision 5.0.5's RTX OS.
Need help.
In STM's you can specify wordlength for usart / uart transmission but wordlength is a sum of data bits and bit parity. So if you would like to have 8 bit data and even parity bit, you have to specify UART_WORDLENGTH_9B andUART_PARITY_EVEN.
You can also have 9 bits of data, with no parity. In reference manual for F427 section 30.6.4, Bit 12 we see that it should be possible to set 9 data bits, but term data bits is also applicable to parity bit.
Bit 12M: Word length
This bit determines the word length. It is set or cleared by software.
0: 1 Start bit, 8 Data bits, n Stop bit
1: 1 Start bit, 9 Data bits, n Stop bit
Final answer is in 30.6.4, Bit 10
This bit selects the hardware parity control (generation and
detection). When the parity control is enabled, the computed parity is
inserted at the MSB position (9th bit if M=1; 8th bit if M=0) and
parity is checked on the received data. This bit is set and cleared by
software. Once it is set, PCE is active after the current byte (in
reception and in transmission).