STM32 SPI Data Packing - stm32

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.

Related

Transmitting I2S mic data over UART in STM32

I have interfaced I2S mic (ICS-43434) with STM32f401RET6 board.
I have wired it correctly, now just trying to test the mic by passing the data through UART to my pc. Hoping someone can point me in the correct direction.
I have tried passing straight to the UART transmit. However I think I may need some datahandling - I am receiving from the UART, but sometimes just 0 or other times just gibberish which is not from the Mic as it still transmits even when i disconnect the mic.
I2S mic is receiving data in 24 bits in 32 bit frame, the last 8 bits are junk. The protocol is Big Endian, I am thinking that the HAL library handles this, however I am not completely sure.
uint16_t data;
while (1)
{
/*USER CODE END WHILE */
HAL_StatusTypeDef result= HAL_I2S_Receive(&hi2s1,&data,2,100);
HAL_UART_Transmit(&huart3,&data,2,100);
/*USER CODE BEGIN 3 */
}
/*USER CODE END 3 */
What did I miss?

How to transmit a 32 bits word with SPI on a stm32 to a GPS receiver chip (MAX2769C)

I am trying to configure a GPS receiver chip (MAX2769C) with an stm32f446re MCU using SPI in half duplex master mode. The chip is expecting a 32 bit word (4 bits address and 28 bits data). This is on page 21 of the datasheet.
My first question is how can I transmit a 32 bits word when the maximum bits format that cubemx allows is 16 bits transfer.
My second problem is that, I have to generate a clock of exactly 16,384 MHZ to feed the MAX2769C chip (this is not the data clock SCK of the SPI). So I selected MCO1 in cubemx and played around with clock configuration until I got 16.384 MHZ. How is this going to affect the SPI speed?
I have tried using hal_spi_transmit using an unint8_t array of 4 bytes but this doesn't work.
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET);
HAL_Delay(10);
//Set IF centre frequency to 3.9 MHz
//SPI read data
//1. Put CS low - Activate
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET);
//2. Write data (0A2919A3) to slave
spiTX1Data[0] = 0x0A; // Transmit register address 0000
spiTX1Data[1] =0x29; // Set FCEN to 001101 & FBW to 00 in configuration 1
spiTX1Data[2] =0x19;
spiTX1Data[3] =0xA3;
HAL_SPI_Transmit(&hspi2, spiTX3Data, 4, 10);
//3. Read
HAL_SPI_Receive(&hspi2, &spiTX1Data[3], 4, 10);
//Bring CS high - Deactivate
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET);
It's my first time asking a question on this platform. Thank you in advance!

STM32 Temperature sensor power off

I am using internal ADC temp sensor , in a low power device without the sensor in stop mode ,the uController consumes around 4 uA but when the temp sensor is on the consumption goes up to 8-9 uA
the problem is i can not turn the sensor OFF / i just measured the off current by setting it off from start by stmcube
i am searching for a code that can turn off the temp sensor
up until now i have tested these:
1-
HAL_ADC_Init(&hadc);
hadc.Lock=HAL_UNLOCKED;
__HAL_UNLOCK(&hadc);
HAL_ADCEx_DisableVREFINTTempSensor();
2-
ADC1->CR&=0X00000000;
ADC->CCR&=~(1<<23);
i prefer to work with HAL , it dose not seems to cut the Sensor power
Your ADC1->CR &= 0x00000000; line looks wrong to me, depending on the controller you're using.
There is usually a bit to disable the ADC which needs to be set, rather than writing all 0s. Try ADC1->CR = (0x01 << 1); instead. If you have the ST Micro written defines for your processor ADC1->CR = ADC_CR_ADDIS; should be the same but more readable. After disabling the ADC you will be able to turn off the TSEN bit of ADC->CCR.

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).

STM32F0 SPI loopback - No data on MISO

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)