STM32 DMA transfer error - c

I use STM32F407VTG6 controller and try to receive data from SPI using DMA. Then I want to process data on DMA Complete Transfer Interrupt. But when Complete Transfer Interrupt is occurred I see that TEIF (transfer error interrupt flag) is set. After this DMA can't be started. This is part of my code:
static void DmaInit()
{
DMA_InitTypeDef dma;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
// DMA for Rx
dma.DMA_Channel = DMA_Channel_3;
dma.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;
dma.DMA_Memory0BaseAddr = 0; // will be set later
dma.DMA_DIR = DMA_DIR_PeripheralToMemory;
dma.DMA_BufferSize = 1; // will be set later
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
dma.DMA_Mode = DMA_Mode_Normal;
dma.DMA_Priority = DMA_Priority_High;
dma.DMA_FIFOMode = DMA_FIFOMode_Disable;
dma.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
dma.DMA_MemoryBurst = DMA_MemoryBurst_Single;
dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_DeInit(DMA2_Stream2);
DMA_Init(DMA2_Stream2, &dma);
// Enable DMA Interrupt on complete transfer
NVIC_EnableIRQ(DMA2_Stream2_IRQn);
DMA_ITConfig(DMA2_Stream2, DMA_IT_TC, ENABLE);
}
// It run on external interrupt
static void DmaStart(uint32_t bufferSize, uint32_t* rxBuffer)
{
// Start DMA for reading
DMA2_Stream2->NDTR = bufferSize;
DMA2_Stream2->M0AR = (uint32_t)rxBuffer;
DMA_Cmd(DMA2_Stream2, ENABLE);
}
static void SpiInit()
{
SPI_InitTypeDef spi;
// Enable clock for SPI
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
// SPI settings
SPI_StructInit(&spi);
spi.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
spi.SPI_Mode = SPI_Mode_Master;
spi.SPI_DataSize = SPI_DataSize_8b;
spi.SPI_CPOL = SPI_CPOL_Low;
spi.SPI_CPHA = SPI_CPHA_2Edge;
spi.SPI_NSS = SPI_NSS_Soft;
spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
spi.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI1, &spi);
SPI_Cmd(SPI1, ENABLE);
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);
}

I just finished my SDIO+DMA this days, some notes maybe useful for you:
Clear Flags before enabling the stream
DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_FEIF2|DMA_FLAG_DMEIF2|DMA_FLAG_TEIF2|DMA_FLAG_HTIF2|DMA_FLAG_TCIF2);
Clear EN bit in the DMA_SxCR Register, Wait Until the EN bit is read as 0 before DMA_Init()
DMA_Cmd(DMA2_Stream2, DISABLE);
while (DMA2_Stream2->CR & DMA_SxCR_EN);
When use DMA_FIFOMode_Disable (Direct Mode), data width is determined by DMA_PeripheralDataSize (PSIZE), DMA_MemoryDataSize (MSIZE) is ignored
Memory address must be aligned to your selected data width (HalfWord)
Reference:
STM32F407XX Reference Manual - Chapter 10 DMA Controller
STM32F4XX Standard Peripheral Library

Related

SPI transmission errors. RX buffer full and data mismatch

I'm transmitting my data in SPI. uint8_t data[5] = {0xa,0xb,0xc,0xd,0xe}; When I see the output in logic analyzer, the data is mis matched. I dont know what might be the root of the problem. I will share my code and configuration here. Please have a look.
void SPI_Transmit (uint8_t *data, int size)
{
SPI1->CR1 |= (1<<6);
int i=0;
while (i<size)
{
while (!((SPI1->SR)&(1<<1))) {}; // wait for TXE bit to set -> This will indicate that the buffer is empty
SPI1->DR = data[i]; // load the data into the Data Register
i++;
}
// Clear the Overrun flag by reading DR and SR
while (!((SPI1->SR)&(1<<1))) {}; // wait for TXE bit to set -> This will indicate that the buffer is empty
while (((SPI1->SR)&(1<<7))) {}; // wait for BSY bit to Reset -> This will indicate that SPI is not busy in communication
while (((SPI1->SR)&(1<<0)))
{
uint8_t temp = SPI1->DR;
};
uint8_t temp1 = SPI1->SR;
SPI1->CR1 &= ~(1<<6);
}
Here I'm transmitting my data and waiting for my TX empty flag to set and Busy flag to reset. Also, after I transmittting my data, my RX buffer (RXFIFO) is full and RX not empty flag is set. So I have to read data register until RXNE is reset.
I understand SPI communicate through register shifting, for every data sent there will be some received data. But my communication is in Master transmit only mode. I'm only using MOSI not MISO. So I dont understand why there is data in my RX buffer even when I'm using only MOSI wire. I also tested transmitting data without any slave device, still I receive data in RX buffer. I dont understand where this RX data is coming from. The status registe shows RXNE=1 and FRLVL=11.
After programming my SPI transmit function according to my conditions, I transmit the data. When I see output in logic analyzer, the data is mismatch. The Baud Rate is 625.0KBits/s and sampling rate is 2MS/s.
Here is my SPI configuration
static void MX_SPI1_Init(void)
{
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 7;
hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
}
One of the most important thing to work with SPI is phasing. With two parameters CPOL and CPHA the phasing should be configured. In your problem in these two are named as CLKPolarity and CLKPhase in hspi1.Init respectively. These two parameters includes 4 states (0,0 - 0,1 - 1,0 - 1,1). It's better to try each state. For more information please check Here, section: Clock Polarity and Clock Phase.

STM32, master and slave devices not responding to each other

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
From your images it seems that CLK is kept low after sending data. In SPI the Master is the sole governor of the clock.
From STM32F411xC/E reference manual, p 578:
BUSY flag
This BSY flag is set and cleared by hardware (writing to this flag has no effect). The BSY flag indicates the state of the communication layer of the SPI.
When BSY is set, it indicates that the SPI is busy communicating. There is one exception in master mode / bidirectional receive mode (MSTR=1 and BDM=1 and BDOE=0) where the BSY flag is kept low during reception.
The BSY flag is useful to detect the end of a transfer if the software wants to disable the SPI and enter Halt mode (or disable the peripheral clock). This avoids corrupting the last transfer. For this, the procedure described below must be strictly respected.
The BSY flag is also useful to avoid write collisions in a multimaster system.
The BSY flag is set when a transfer starts, with the exception of master mode / bidirectional receive mode (MSTR=1 and BDM=1 and BDOE=0).
It is cleared:
when a transfer is finished (except in master mode if the communication is continuous)
when the SPI is disabledwhen a master mode fault occurs (MODF=1)
When communication is not continuous, the BSY flag is low between each communication.
When communication is continuous:
in master mode, the BSY flag is kept high during all the transfers
in slave mode, the BSY flag goes low for one SPI clock cycle between each transfer
Note:Do not use the BSY flag to handle each data transmission or reception. It is better to use the TXE and RXNE flags instead
So I think your waiting for busy flag in master after sending data can lock indefinitely. Try this (the code uses plain CMSIS, but it should be understandable):
GPIOB->BSRR |= GPIO_BSRR_BR6; //slave select
while(! (SPI1->SR & SPI_SR_TXE)); //wait for Tx buffer empty
SPI1->DR = 0x01; //send 0x01
while(! (SPI1->SR & SPI_SR_RXNE)); //wait for Rx buffer not empty (receive 0x0 sent by the slave during our sending 0x01 since it's 4-wire SPI)
uint8_t tmp = SPI1->DR; //we don't need that value, but need to read DR in order to reset RXNE flag
SPI1->DR = 0x0; //we need to trigger send in order to receive
while(! (SPI1->SR & SPI_SR_RXNE)); //wait for Rx buffer not empty (our response)
response = SPI1->DR;
while(SPI1->SR & SPI_SR_BSY); //now we can wait for SPI to end communications
GPIOB->BSRR |= GPIO_BSRR_BS6; //slave deselect
Thank You for the help. After long hours I managed to get it working, by resetting the SPI peripheral in th Slave device after each transaction:
void SPI_reset_flush(void)
{
//Reset the periph and registers
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1, ENABLE);
SPI_aux_tim_wait();
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1, DISABLE);
SPI_aux_tim_wait();
SPI_Cmd(SPI1, ENABLE);
}
12.04.2019
Actually, I think the mentioned solution is not the best. The problem was, I was not waiting for the SPI buffers to empty, this resulted in random data being send, and I lost synchronisation between devices. I since the rewrote the code, and stuck to the TX/RX procedures in a Reference Manuals.
Best Regards, Marek

STM32F4 SPI issue

I'am using STM32F407vg and i'am trying to write data in SPI data register, the following code shows the configuration function
void init_SPI1(void){
GPIO_InitTypeDef GPIO_InitStruct;
SPI_InitTypeDef SPI_InitStruct;
// enable clock for used IO pins
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* configure pins used by SPI1
* PA4 = NSS
* PA5 = SCK
* PA6 = MISO
* PA7 = MOSI
*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5|GPIO_Pin_4;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// connect SPI1 pins to SPI alternate function
GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
//Set chip select high
GPIOA->BSRRL |= GPIO_Pin_4; // set PE4 high
// enable peripheral clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
/* configure SPI1 in Mode 0
* CPOL = 0 --> clock is low when idle
* CPHA = 0 --> data is sampled at the first edge
*/
SPI_StructInit(&SPI_InitStruct); // set default config
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines
SPI_InitStruct.SPI_Mode = SPI_Mode_Master; // transmit in master mode, NSS pin has to be always high
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; // clock is low when idle
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // data sampled at first edge
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft ; // set the NSS management to internal and pull internal NSS high
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; // SPI frequency is APB2 frequency / 4
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first
SPI_Init(SPI1, &SPI_InitStruct);
SPI_Cmd(SPI1, ENABLE); // enable SPI1
}
and this is the function that send data
uint8_t SPI1_send(uint8_t data){
SPI1->DR = data; // write data to be transmitted to the SPI data register
while( !(SPI1->SR & SPI_I2S_FLAG_TXE) ); // wait until transmit complete
while( !(SPI1->SR & SPI_I2S_FLAG_RXNE) ); // wait until receive complete
while( SPI1->SR & SPI_I2S_FLAG_BSY ); // wait until SPI is not busy anymore
return SPI1->DR; // return received data from SPI data register
}
I think that i have set the good configuration (the choice of pins is not wrong in my opinion and also the configuration of the bus used ) the following pictures are extracted from the STM32F407 DataSheet
The problem is that the data in the DR registry is different than the data passed as argument .I don't know why this happen .Could anyone guide me to the right point
The SPI DR register is not a normal memory location where writing and reading access the same storage.
Instead, writing loads the output shift register, while reading reads the received input. Depending on device details, reading may also "claim" the input, clearing it from the register until another word is received.
For these reasons, trying to watch the SPI DR with a debugger is not only not going to give you the information you seek, it may even be damaging to the data you would otherwise receive.
After reading the SPI section from this book my problem is solved, i just connect SPI MOSI to SPI MISO pin (PA6 and PA7) then used the following function :
int spiReadWrite(SPI_TypeDef* SPIx, uint8_t *rbuf,
const uint8_t *tbuf, int cnt, enum spiSpeed speed)
{
int i;
SPIx->CR1 = (SPIx->CR1 & ~SPI_BaudRatePrescaler_256) |
speeds[speed];
for (i = 0; i < cnt; i++){
if (tbuf) {
SPI_I2S_SendData(SPIx, *tbuf++);
} else {
SPI_I2S_SendData(SPIx, 0xff);
}
while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET);
if (rbuf) {
*rbuf++ = SPI_I2S_ReceiveData(SPIx);
} else {
SPI_I2S_ReceiveData(SPIx);
}
}
return i;
}
by using a debugger i can see that the data sent (from tbuf) are succesfully received (in rbuf)
note that SCLK_freq = APB2_freq / (BaudRatePrescaler + 1)

ADC single conversion on STM32

I'm studying ADC programming on STM32 F103x and starting with the simplest case - single conversion.
The internal temperature sensor (connected to ADC1) value is measured and sending it to COM port by using USART. A target seems clear but when I try to download source code to flash, it doesn't send any data to COM port. USART function works well, I guess the problems come from ADC configuration part because I'm being hung in loop of waiting complete conversion:
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //Wail for conversion complete
Here is my source code so far.
/* Includes ------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdio.h>
uint16_t AD_value;
const uint16_t V25 = 1750; //when V25=1.41V
const uint16_t Avg_Slope = 5; //when avg_slc
uint16_t TemperatureC;
//Define output device
PUTCHAR_PROTOTYPE
{
USART_SendData(USART1, (uint8_t) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
{}
return ch;
}
void Usart1Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
/* COnfig PA9 for USART Tx as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* COnfig PA10 for USART Rx as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* USARTx configured as follow:
- BaudRate = 9600 baud
- Word Length = 8 Bits
- One Stop Bit
- No parity
- Hardware flow control disabled (RTS and CTS signals)
- Receive and transmit enabled
*/
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
/* USART configuration */
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
int main(void)
{
ADC_InitTypeDef ADC_InitStructure;
Usart1Init();
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //ADCCLK = PCLK22/6 = 72/6=12MHz
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //Enable ADC1 Clock
/* ADC1 configuration */
ADC_DeInit(ADC1); //Power-on default
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //Independent conversion mode (single)
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //Convert single channel only
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //Convert 1 time
ADC_InitStructure.ADC_ExternalTrigConv = DISABLE; //No external triggering
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //Right 12-bit data alignment
ADC_InitStructure.ADC_NbrOfChannel = 1; //single channel conversion
ADC_Init(ADC1, &ADC_InitStructure);
ADC_TempSensorVrefintCmd(ENABLE); //wake up temperature sensor
ADC_Cmd(ADC1, ENABLE); //Enable ADC1
ADC_ResetCalibration(ADC1); //Enable ADC1 reset calibration register
while(ADC_GetResetCalibrationStatus(ADC1)); //check the end of ADC1 reset calibration register
ADC_StartCalibration(ADC1); //Start ADC1 calibration
while(ADC_GetCalibrationStatus(ADC1)); //Check the end of ADC1 calibration
ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_1Cycles5); //Select 1.5 cycles conversion for channel 16
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //Start ADC1 software conversion
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //Wail for conversion complete
AD_value = ADC_GetConversionValue(ADC1); //Read ADC value
ADC_ClearFlag(ADC1, ADC_FLAG_EOC); //Clear EOC flag
printf("\r\n ADC value: %d \r\n", AD_value);
TemperatureC = (uint16_t)((V25-AD_value)/Avg_Slope+25);
printf("Temperature: %d%cC\r\n", TemperatureC, 176);
while (1)
{}
}
Any ideas are appreciated!
i'll try to explain what's going on with source code.
1- definition of disable is zero :
typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
2- so when you write "ADC_InitStructure.ADC_ExternalTrigConv = DISABLE;" you actually assign it to zero like this "ADC_InitStructure.ADC_ExternalTrigConv = 0;
3- this means your assigning the EXTSEL of ADC_CR2 register to zero.
4-if EXTSEL is zero, adc conversion depends on the timers to start.
5-if you want adc to be started by software, EXTSEL must be 0x000E0000;
6- and as you can guess the value of "ADC_ExternalTrigConv_None" is defined as 0x000E0000;
so while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); code will hung up here because it depens on the timers to start, it cannot end if it is not started.
Problem solved!
It's my fault to disable external trigger. Instead of using:
ADC_InitStructure.ADC_ExternalTrigConv = DISABLE;
It shoud be like this:
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
What a silly!
I will not invent a wheel here by saing that you are hanging in one of those three while() loops. Make some output before each of then then you will know where you are hanging.
If you have debugger (it is present on every ST development board, and possibly you are using it to download program) don't hesitate to use it :)

STM32F4 SPI Configuration SPI_Init causes assert_failed loop

I'm trying to configure SPI to work with a ST7565 GLCD library which is given here. For now, I'm trying to use SPI1 to achieve this. When the init function -which is given below- is called in main(), it causes the program to loop in assert_failed function.
void init_SPI1(void){
GPIO_InitTypeDef GPIO_InitStruct;
SPI_InitTypeDef SPI_InitStruct;
// enable clock for used IO pins
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* configure pins used by SPI1
* PA5 = SCK
* PA6 = MISO
* PA7 = MOSI
*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// connect SPI1 pins to SPI alternate function
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
// enable clock for used IO pins
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
/* Configure the chip select pin
in this case we will use PE7 */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOE, &GPIO_InitStruct);
GPIOE->BSRRL |= GPIO_Pin_7; // set PE7 high
// enable peripheral clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
/* configure SPI1 in Mode 0
* CPOL = 0 --> clock is low when idle
* CPHA = 0 --> data is sampled at the first edge
*/
SPI_InitStruct.SPI_Direction = SPI_Direction_1Line_Tx; // set to full duplex mode, seperate MOSI and MISO lines
SPI_InitStruct.SPI_Mode = SPI_Mode_Master; // transmit in master mode, NSS pin has to be always high
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; // clock is low when idle
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // data sampled at first edge
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; // set the NSS management to internal and pull internal NSS high
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; // SPI frequency is APB2 frequency / 4
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first
SPI_Init(SPI1, &SPI_InitStruct);
SPI_Cmd(SPI1, ENABLE); // enable SPI1
}
I've noticed that program goes in infinite loop inside assert_failed function when it reaches SPI_Init() line:
SPI_Init(SPI1, &SPI_InitStruct);
The assert_failed function ( Default in Firmware Library) is below:
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
I don't know what does it supposed to mean that it loops in assert_failed function. Is it a problem to do with the SPI configuration. I need guidance to understand the problem and generate a solution. Any help will be greately appreciated. Thanks in advance.
EDIT: I've checked inside of the SPI_Init function in stm32f4xx_spi.c
void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct)
{
uint16_t tmpreg = 0;
/* check the parameters */
assert_param(IS_SPI_ALL_PERIPH(SPIx));
/* Check the SPI parameters */
assert_param(IS_SPI_DIRECTION_MODE(SPI_InitStruct->SPI_Direction));
assert_param(IS_SPI_MODE(SPI_InitStruct->SPI_Mode));
assert_param(IS_SPI_DATASIZE(SPI_InitStruct->SPI_DataSize));
assert_param(IS_SPI_CPOL(SPI_InitStruct->SPI_CPOL));
assert_param(IS_SPI_CPHA(SPI_InitStruct->SPI_CPHA));
assert_param(IS_SPI_NSS(SPI_InitStruct->SPI_NSS));
assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_InitStruct->SPI_BaudRatePrescaler));
assert_param(IS_SPI_FIRST_BIT(SPI_InitStruct->SPI_FirstBit));
assert_param(IS_SPI_CRC_POLYNOMIAL(SPI_InitStruct->SPI_CRCPolynomial));
Since the library is locked, I cant get to type anything inside to debug in Live Watch. (I'm using IAR EWARM)
It loops in assert() because the assert failed, so the loop is there to stop further execution.
Just step up on your stack so that you can see which assert in the peripheral library it was that failed. The library does pretty extensive validation of its parameters, so probably something is wrong in one of your calls.
UPDATE It seems you never initialize the CRCPolynomial field, but it's asserted upon. I suggest adding a call to SPI_StructInit() to make sure your init struct is sanely initialized, before you start setting it up according to your application's wishes.

Resources