I have little bit problem when reading Rx Buffer in STM32 SPI. I can watch my signal when transmit or receive in my scope. But I never can get any data in my Rx Buffer. I just use coocox software for this project.
For this project, I use STM32F103 and LoRa module (SX1278). I use Full duplex communication for my SPI Configuration. There is 2 cycle to read register status in my LoRa module. First cycle is to write address and second cycle is for read/write register. My problem is reading register in my LoRa module.
This is my simple code to read register.
void SPI2_IRQHandler(void)
{
RxSPIBuff = &Buffer_Rx[0];
if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_RXNE) == SET)
{
/* Store the I2S2 received data in the relative data table */
//Buffer_Rx[RxIdx++] = SPI_I2S_ReceiveData(SPI2);
//if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_FLAG_RXNE)==SET)
USART_SendData(USART1, SPI_I2S_ReceiveData(SPI2));
}
}
void InitSPI_Lora(void)
{
SPI_InitTypeDef SPI_InitStruct;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// RCC Peripheral Configuration
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// GPIO Configuration
GPIO_InitStructure.GPIO_Pin = MOSI_LoRa | SCLK_LoRa;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SPI_LoRa, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = NSS_LoRa;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(PeriphNSS_LoRa, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = MISO_LoRa;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SPI_LoRa, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = Reset_LoRa;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(PeriphRst_LoRa, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = DIO0_LoRa;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(PeriphDI0_LoRa, &GPIO_InitStructure);
// SPI Configuration
SPI_InitStruct.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_32; // 7us every 8 bit data
SPI_InitStruct.SPI_CPHA=SPI_CPHA_1Edge;
SPI_InitStruct.SPI_CPOL=SPI_CPOL_Low;
SPI_InitStruct.SPI_DataSize=SPI_DataSize_8b;
SPI_InitStruct.SPI_Direction=SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_FirstBit=SPI_FirstBit_MSB;
SPI_InitStruct.SPI_Mode=SPI_Mode_Master;
SPI_InitStruct.SPI_NSS=SPI_NSS_Soft;
// NVIC Configuration
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
/* SPI1 IRQ Channel configuration */
NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
SPI_I2S_DeInit(SPI2);
/* Enable the I2S1 RxNE interrupt */
SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, ENABLE);
SPI_Init(SPI2, &SPI_InitStruct);
SPI_Cmd(SPI2, ENABLE);
}
void SendSPI_Lora(unsigned short val, unsigned char status)
{
SPI_I2S_SendData(SPI2, val);
while(SPI_I2S_GetITStatus(SPI2, SPI_I2S_FLAG_TXE)==SET);
SPI_I2S_ClearFlag(SPI2, SPI_I2S_FLAG_TXE);
}
void AccessSPI(unsigned char Cmd, unsigned short *ptrBuff, unsigned char Operation)
{
unsigned short m, temp;
NSS_LO_LoRa;
SendSPI_Lora(Cmd, kWriteSPI); // Send Command
if (Operation==kWriteSPI)
{
temp=*ptrBuff;
SendSPI_Lora(temp, Operation);
}
else
{
RxIdx=0;
SendSPI_Lora(0, Operation);
ptrBuff = RxSPIBuff;
}
Delay(2);
NSS_HI_LoRa;
}
// Main Sequence
void test(void)
{
unsigned char statusLoRa,buff,irqFlags,newData,newOpMode;
unsigned char size = 0;
AccessSPI(R_REGISTER|RegVersion, &newOpMode, kReadSPI);
}
Pict 1. Write signal in MOSI pin
Pict 2. Read Signal in MISO pin
I think my problem is about delay to receive data after transmit data with SPI. But i cannot solve this problem because i should transmit data to receive. Is there any solution for this?
I'm not sure about this one, but I think MISO should also be configured as alternate mode. At least that's what works for me.
You have configured RXNE interrupt, but use TXE as interrupt also.
Use SPI_I2S_GetFlagStatus instead of SPI_I2S_GetITStatus
while(SPI_I2S_GetITStatus(SPI2, SPI_I2S_FLAG_TXE)==SET); is an error. Reference manual for STM32F103, page 710:
The TXE flag (Tx buffer empty) is set when the data are transferred from the Tx buffer to the shift register. It indicates that the internal Tx buffer is ready to be loaded with the next data.
So it should be while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
With RXNE interrupt you will be sending to USART also after sending the first byte (the register addess)
Here is a CMSIS code for similar transmission ("First cycle is to write address and second cycle is for read/write register.", but without using interrupts, and using STM32F4 with SPI configured as follows:
//af5, afrl
GPIOB->AFR[0] |= ( GPIO_AFRL_AFSEL3_2 | GPIO_AFRL_AFSEL3_0 |
GPIO_AFRL_AFSEL5_2 | GPIO_AFRL_AFSEL5_0 );
GPIOA->AFR[0] |= ( GPIO_AFRL_AFSEL6_2 | GPIO_AFRL_AFSEL6_0 );
//B3 SCK
//A6 MISO
//B5 MOSI
//B6 SS
GPIOA->MODER |= ( GPIO_MODER_MODE6_1 );
GPIOB->MODER |= ( GPIO_MODER_MODE3_1 |
GPIO_MODER_MODE5_1 |
GPIO_MODER_MODE6_0 ); //alternate, 6 output
GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD6_Msk ); // no pull
GPIOB->PUPDR |= GPIO_PUPDR_PUPD3_1;
Are you using a Nano board? If so into which connector did you plug your MISO? I've spent a week once because I have plugged it into Arduino connector that was connected to some other peripheral instead of Morpho connector.
Related
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)
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 :)
Recently I've been trying to get the I2C bus working on the STM32F030F4P6 MCU, but with little luck.
I'm using an STM32F0 module and have found plenty of resources for the STM32F1 module I2C initialization, but nothing specific about the STM32F0 initialization/transfer process.
Here's my initialization code:
void i2c_init(uint8_t ownAddress)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
// Enable GPIOA clocks
RCC_APB2PeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
// Configure I2C1 clock and GPIO
GPIO_StructInit(&GPIO_InitStructure);
/* I2C1 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
/* I2C1 SDA and SCL configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* I2C1 Reset */
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);
/* Configure I2C1 */
I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;
I2C_StructInit(&I2C_InitStructure);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
//I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = ownAddress;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
//I2C_InitStructure.I2C_ClockSpeed = ClockSpeed;
I2C_Init(I2C1, &I2C_InitStructure);
I2C_Cmd(I2C1, ENABLE);
}
In order to test to see if my setup was correct I designed some I2C transmission code that would transfer data in a never ending loop. Here's the code for that:
while(1)
{
I2C_SlaveAddressConfig(I2C1, RegName);
I2C_GenerateSTART(I2C1, ENABLE);
I2C_NumberOfBytesConfig(I2C1, 8);
I2C_SendData(I2C1,0b00000000);
I2C_GenerateSTOP(I2C1, ENABLE);
}
Where:
RegName = 0x75
SDA = GPIO_PIN_10 on GPIOA
SCL = GPIO_PIN_9 on GPIOA
I2C = I2C1
ownAdrress = 0x68
When I scope the I2C lines after I start this code I get a floating voltage around 160mV. When I step through the code every one of the I2C function calls happen and complete, so that's why I was thinking that it had something more so to do with my initialization of the pins themselves.
My problem is very similar to this thread, but was never answered:
https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a%2f%2fmy%2est%2ecom%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex_mx_stm32%2fSTM32F0%20I2C%20code%20doesn%27t%20work&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=1342
Edit 1: Here's my latest code; still not working (Edit 2: Updated to what I currently have; moved things into more correct locations):
void i2c_init(uint8_t ownAddress)
{
/* TypeDefs for GPIOA and I2C1 */
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
/* Enable GPIOA clocks and I2C1 clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
/* Configure I2C1 clock and GPIO */
GPIO_StructInit(&GPIO_InitStructure);
/* I2C1 SDA and SCL configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //UP
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
/* GPIO AF Configuration -> GPIO_AF_1: USART2, CEC, Tim3, USART1, USART2,EVENTOUT, I2C1, I2C2, TIM15 */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* I2C1 Reset */
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);
//I2C_DeInit(I2C1);
/* Configure I2C1 */
I2C_StructInit(&I2C_InitStructure);
I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_OwnAddress1 = ownAddress;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C1, &I2C_InitStructure);
I2C_Cmd(I2C1, ENABLE);
//I2C_AcknowledgeConfig(I2C1, ENABLE);
}
As you can see I added the two lines GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1); and GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1); where I found that GPIO_AF_1 had the alternate function of I2C1 from the STM32F0 Standard Peripheral bibliotheek.
Any other ideas? I've been playing around with the clocks to see if that changed anything and have been adding snippets of other people's code just to see if that has any effect on the output of my device.
Edit 3: I have tried pulling both the SDA and SCL lines up to VCC with a 1kohm resistor as instructed by this guide: https://electronics.stackexchange.com/questions/57121/i2c-pullup-resistor-calculations
->(3.3V-0.4)/3mA ~= 1kohm
Edit 4: After going through my code line by line I tried outputting various flag bit registers. Specifically these registers: isr = I2C1->ISR;, cr1 = I2C1->CR1;, and cr2 = I2C1->CR2;
The flag I get after initiating the I2C transfer handling with I2C_TransferHandling(I2C1, 0x02, 1, I2C_AutoEnd_Mode, I2C_Generate_Start_Write); was 0x8001 which can be deciphered down to two errors:
#define I2C_ISR_BUSY ((uint32_t)0x00008000) /*!< Bus busy */
and
#define I2C_ISR_TXE ((uint32_t)0x00000001) /*!< Transmit data register empty */
I've found some work arounds at this link here (remove the space after https: to go to the link -> stack overflow won't let me post more than 1 link for some reason): https: //my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2Fcortex_mx_stm32%2FSTM32L151RB%20I2C%20Busy%20flag%20always%20set&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=690 that I'm looking to implement and will report back as soon as I try them out.
I have I2C working as master and slave on the F0. The main issue I can see with your code is that in master mode you absolutely must set the I2C_Timing initialisation structure member. See RM0091 for sample values that correspond to the frequency you want to generate on SCL. In slave mode the clock is recovered from the master so the timing member doesn't appear to be used.
As the others have said, external pullups to Vcc on SCL and SDA are not optional and must be present once per bus not per peripheral as you incorrectly stated in a comment. You were right to use the calculator to choose suitable values because the internal pullups in the STM32 at about 30-50K are far too weak for use as I2C pullups.
The problem is that you don't configure proper AF (Alternate Function) source for I2C pins. After reset registers that configure AF are all 0, and I2C's function is 1, so your I2C peripheral is in fact disconnected from the GPIOs.
Technically it makes no difference when you configure that, but it's best to do that before GPIO configuration to minimize any unwanted transitions on the pins.
Edit: You MUST have the pullups on the I2C pins - without them you have "low" level there, and I2C peripheral detects that as bus error, which obviously prevents it from working properly. Either connect external resistors, or at least enable internal pullups instead of "no pullups/no pulldowns" configuration.
Moreover - it's just not possible for an "open drain" pin to work properly without pullup.
The Core of Cortex M0 is different then Core of Cortex M3, STM32f030f4 has AHB and APB1 (bridged) only. The C code of STM32f1xx never be run under STM32f0xx.
Use STM32F0xx_Snippets_Package for solve your key problems.
I just noticed this too:
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);
So you have disabled the clock after you enabled it. I don't see where you have re-enabled it later.
I notice that you are mapping the pins to AF_1 and that is for the UART function.
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);
You need to map them to AF_4 to use the I2C function.
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_4);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_4);
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.
I am using STM32F103ZE
I am not getting SPI data correctly.
Master is transmitting correctly.
But always read as zero where a non zero value has been sent.
Master config: (MSP430)
The master configuration is correct. (I tested it.)
Master Mode, MSB First, 8-bit SPI,
Inactive state is high, SS grounded, 1 MHz clock, no dividers
Slave Config (STM32F103ZE)
Using SPI2.
SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Rx
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB
SPI_InitStructure.SPI_CRCPolynomial = 7
Anybody have an ANSWER,
Thanks
Hari
I know, the question is quite old. Still, since I have faced the same problem the last days, I'll try to give an answer for future readers.
The following code works on the STM32F407, which is used on the STM32 discovery board. What I can see from the datasheet, the SPI peripheral is the same as on the STM32F103, so
I expect the code to run on the other microcontroller without modifications.
#include "stm32f4xx.h"
[... configure the pins SCK, MISO, MOSI and NSS ...]
// Configure the SPI as: Slave, 8 bit data, clock high when idle, capture on
// 1st edge, baud rate prescaler 2, MSB first.
SPI1->CR1 = SPI_CR1_CPOL;
// No interrupts, no DMA and Motorola frame format.
SPI1->CR2 = 0;
// Enable the peripheral.
SPI1->CR1 |= SPI_CR1_SPE;
// Wait until some data has been sent to the slave and print it.
while ((SPI1->SR & SPI_SR_RXNE) == 0);
printf("Received: %d\n", SPI1->DR);
Two things are different in this initialization procedure from the code posted in the question:
Do not select bidirectional mode for ordinary SPI with the 3 lines SCK, MISO and MOSI.
Both MISO and MOSI are unidirectional lines.
I use hardware slave select management, i.e. the bit SSM is not set. This way, the
SPI peripheral can automatically detect when the device has been asserted (the pin
NSS goes low) and will
store the MOSI bits in a shift register. When enough bits have been read (8 or
16 depending on the selected data format),
the flag RXNE is set in the status register and the transmitted value can be read
from the register DR.
Hope that helps.
I had exactly the same problem of getting 0x00 value from data register.
In my case the problem was that MISO line was set as floating input. It works after changing it to OType_PP. Here is my configuration code for STM32F429:
void SPI1_Config(void){
GPIO_InitTypeDef GPIO_InitStruct;
SPI_InitTypeDef SPI_InitStruct;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
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_100MHz;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStruct);
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_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_100MHz;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOE, &GPIO_InitStruct);
GPIOE->BSRRL |= GPIO_Pin_7;
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set;
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI1, &SPI_InitStruct);
SPI_Cmd(SPI1, ENABLE);}
And sending function:
uint8_t SPI1_Send(uint8_t data){
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, data);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
return SPI_I2S_ReceiveData(SPI1);}