I try to achieve an USART communication. So I connect the RX of my STM32f1 with his TX.
Also I write a program for this communication. This code is composed of the following components:
RCC configuration
GPIO configuration
USART configuration
Send and receive of a string
Comparison between the sent string and the received string
Test if the communication succeeded => LED4 turn on else the LED3 turn on
The problem is in all cases the LED3 turns on. It means that the data transmission failed.
With my IDE (IAR's Embedded Workbench) I compile this program code:
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "stm32_eval.h"
/* Private typedef -----------------------------------------------------------*/
typedef enum { FAILED = 0, PASSED = !FAILED} TestStatus;
/* Private define ------------------------------------------------------------*/
#define USARTy USART1
#define USARTy_GPIO GPIOA /* PORT name*/
#define USARTy_CLK RCC_APB2Periph_USART1
#define USARTy_GPIO_CLK RCC_APB2Periph_GPIOA
#define USARTy_RxPin GPIO_Pin_10/* pin Rx name*/
#define USARTy_TxPin GPIO_Pin_9 /* pin Tx name*/
#define USARTz USART2
#define USARTz_GPIO GPIOA/* PORT name*/
#define USARTz_CLK RCC_APB1Periph_USART2
#define USARTz_GPIO_CLK RCC_APB2Periph_GPIOA
#define USARTz_RxPin GPIO_Pin_3/* pin Rx name*/
#define USARTz_TxPin GPIO_Pin_2/* pin Tx name*/
#define TxBufferSize (countof(TxBuffer))
/* Private macro -------------------------------------------------------------*/
#define countof(a) (sizeof(a) / sizeof(*(a)))
/* Private variables ---------------------------------------------------------*/
USART_InitTypeDef USART_InitStructure;
uint8_t TxBuffer[] = "Bufferrr";
uint8_t RxBuffer[8];
__IO uint8_t TxConteur = 0, RxConteur = 0;
volatile TestStatus TransferStatus = FAILED;
/* Private function prototypes -----------------------------------------------*/
void RCC_Configuration(void);
void GPIO_Configuration(void);
TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength);
__IO uint8_t index = 0;
GPIO_InitTypeDef GPIO_InitStructure;
int main(void)
{
STM_EVAL_LEDInit(LED1);
STM_EVAL_LEDInit(LED2);
STM_EVAL_LEDInit(LED3);
STM_EVAL_LEDInit(LED4);
/* System Clocks Configuration */
RCC_Configuration();
/* Configure the GPIO ports */
GPIO_Configuration();
USART_InitStructure.USART_BaudRate = 230400 /*115200*/;
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;
/* Configure USARTy */
USART_Init(USART1,&USART_InitStructure);
/* Enable the USARTy */
USART_Cmd(USART1,ENABLE);
while(TxConteur < TxBufferSize)
{
/* Send one byte from USARTy to USARTz */
USART_SendData(USARTy, TxBuffer[TxConteur++]);
/* Loop until USARTy DR register is empty */
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
{
}
/* Store the received byte in RxBuffer */
RxBuffer[RxConteur++] = USART_ReceiveData(USARTy) & 0xFF;
}
/* Check the received data with the send ones */
TransferStatus = Buffercmp(TxBuffer, RxBuffer, TxBufferSize);
/* TransferStatus = FAILED, if the data transmitted from USARTy and
received by USARTz are different */
if (TransferStatus == FAILED)
{
STM_EVAL_LEDOn(LED3);
}
else
{
STM_EVAL_LEDOn(LED4);
}
while (1)
{
}
}
void RCC_Configuration(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE);
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure1,GPIO_InitStructure2;
/* Configure USARTy Rx as input floating */
GPIO_InitStructure1.GPIO_Pin =GPIO_Pin_10;
GPIO_InitStructure1.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure1.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure1);
/* Configure USARTy Tx as alternate function push-pull */
GPIO_InitStructure2.GPIO_Pin =GPIO_Pin_9;
GPIO_InitStructure2.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure2.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure2);
/* Configure USARTz Tx as alternate function push-pull */
}
TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
{
while(BufferLength--)
{
if(*pBuffer1 != *pBuffer2)
{
return FAILED;
}
pBuffer1++;
pBuffer2++;
}
return PASSED;
}
Like explained in a comment by Hans Passant, the OP was testing the flag USART_FLAG_TC (Transmission Completed) instead of the flag USART_FLAG_RXNE (RX buffer Not Empty).
Related
I'm trying to enable the LED's on my MCP23S09 by writing to the GPIO register using SPI.
There are two chips on the board one is for the inputs and the other one is for the outputs, so the LED's.
I connected everything like I should, so I took CH2 low and connected the MOSI and SCK pin to my microcontroller.
I'm using a Nucleo STM32F411 in combination with the CubeMX software, So I'm trying to send data to the registers to enable functionality.
But unfortunately none of the LED's lit up on my IO Expander.
Next thing I tried was STM32duino, so I can write Arduino code for my board. But as far as I know this is just another layer on top of the HAL libraries.
To my suprise it worked just fine! It's the same piece of code, I just changed it a bit to work for Arduino.
But I still don't understand why it doesn't work when using the HAL libraries generated by CubeMX.
Arduino Code:
#include <SPI.h>
#define IODIR 0x00
#define IPOL 0x01
#define GPINTEN 0x02
#define DEFVAL 0x03
#define INTCON 0x04
#define IOCON 0x05
#define GPPU 0x06
#define INTF 0x07
#define INTCAP 0x08
#define GPIO 0x09
#define OLAT 0x0A
#define OPCODEW 0x40
#define OPCODER 0x41
// CS0 -> D2
const int slaveAPin = 2;
// CS1 -> D3
const int slaveBPin = 3;
// LED VAL
const uint8_t value = ~0x3F;
void setup() {
// put your setup code here, to run once:
// initialize SPI:
SPI.begin(); //Initialize the SPI_1 port.
SPI.setBitOrder(MSBFIRST); // Set the SPI_1 bit order
SPI.setDataMode(SPI_MODE0); //Set the SPI_1 data mode 0
SPI.setClockDivider(SPI_CLOCK_DIV64);
pinMode (slaveAPin, OUTPUT); // First chip for inputs
pinMode (slaveBPin, OUTPUT); // Second chip for outputs
digitalWrite (slaveAPin, HIGH);
digitalWrite (slaveBPin, HIGH);
}
void loop() {
// configuration led-io-expander
sendDataSPI(IOCON, 0x20);
// all pins = output
sendDataSPI(IODIR, 0x00);
// Enable LEDS
sendDataSPI(GPIO, value);
}
void sendDataSPI(uint8_t reg, uint8_t value){
digitalWrite (slaveBPin, LOW); // Take slave-select low
SPI.transfer(OPCODEW); // Send the MCP23S09 opcode, and write byte
SPI.transfer(reg); // Send the register we want to write
SPI.transfer(value); // Send the byte
digitalWrite (slaveBPin, HIGH); // Take slave-select high
}
STM32 HAL:
/**
******************************************************************************
* File Name : main.c
* Description : Main program body
******************************************************************************
** This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* COPYRIGHT(c) 2017 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f4xx_hal.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* USER CODE BEGIN Defines */
#define IODIR 0x00
#define IPOL 0x01
#define GPINTEN 0x02
#define DEFVAL 0x03
#define INTCON 0x04
#define IOCON 0x05
#define GPPU 0x06
#define INTF 0x07
#define INTCAP 0x08
#define GPIO 0x09
#define OLAT 0x0A
#define OPCODEW 0x40
#define OPCODER 0x41
#define SPI_TRANSFER_TIMEOUT 1000
/* USER CODE END Defines */
/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi1;
UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
static void MX_USART2_UART_Init(void);
void sendDataSPI(uint8_t reg, uint8_t value);
int fgetc(FILE *f);
int fputc(int c, FILE *f);
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
int main(void)
{
// LED VAL
uint8_t value = 0x3F;
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SPI1_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// configuration led-io-expander
sendDataSPI(IOCON, 0x20);
// all pins = output
sendDataSPI(IODIR, 0x00);
// Enable LEDS
sendDataSPI(GPIO, value);
}
/* USER CODE END 3 */
}
// REGISTER, VALUE
void sendDataSPI(uint8_t reg, uint8_t value){
HAL_GPIO_WritePin(CS1_GPIO_Port, CS1_Pin, GPIO_PIN_RESET); // Take slave-select low
HAL_SPI_Transmit(&hspi1,(uint8_t *)OPCODEW,sizeof(uint8_t),SPI_TRANSFER_TIMEOUT); // Send the MCP23S09 opcode, and write bit
HAL_SPI_Transmit(&hspi1,(uint8_t *)®,sizeof(uint8_t),SPI_TRANSFER_TIMEOUT); // Send the register we want to write
HAL_SPI_Transmit(&hspi1,(uint8_t *)&value,sizeof(uint8_t),SPI_TRANSFER_TIMEOUT); // Send the byte
HAL_GPIO_WritePin(CS1_GPIO_Port, CS1_Pin, GPIO_PIN_SET); // Take slave-select high
}
int fputc(int c, FILE *f) {
return (HAL_UART_Transmit(&huart2, (uint8_t *)&c,1,HAL_MAX_DELAY));
}
int fgetc(FILE *f) {
char ch;
HAL_UART_Receive(&huart2,(uint8_t*)&ch,1,HAL_MAX_DELAY);
return (ch);
}
/** System Clock Configuration
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
/**Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 16;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/* SPI1 init function */
static void MX_SPI1_Init(void)
{
/* SPI1 parameter configuration*/
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_64;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
/* USART2 init function */
static void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(CS0_GPIO_Port, CS0_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(CS1_GPIO_Port, CS1_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : B1_Pin */
GPIO_InitStruct.Pin = B1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : CS0_Pin */
GPIO_InitStruct.Pin = CS0_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(CS0_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : CS1_Pin */
GPIO_InitStruct.Pin = CS1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(CS1_GPIO_Port, &GPIO_InitStruct);
}
/* USER CODE END 4 */
You do not wait the SPI transfer to be completed before starting the next transmission in your sendDataSPI function. It should be modified like this:
void sendDataSPI(uint8_t reg, uint8_t value){
HAL_GPIO_WritePin(CS1_GPIO_Port, CS1_Pin, GPIO_PIN_RESET); // Take slave-select low
HAL_SPI_Transmit(&hspi1,(uint8_t *)OPCODEW,sizeof(uint8_t),SPI_TRANSFER_TIMEOUT); // Send the MCP23S09 opcode, and write bit
while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY);
HAL_SPI_Transmit(&hspi1,(uint8_t *)®,sizeof(uint8_t),SPI_TRANSFER_TIMEOUT); // Send the register we want to write
while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY);
HAL_SPI_Transmit(&hspi1,(uint8_t *)&value,sizeof(uint8_t),SPI_TRANSFER_TIMEOUT); // Send the byte
while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY);
HAL_GPIO_WritePin(CS1_GPIO_Port, CS1_Pin, GPIO_PIN_SET); // Take slave-select high
}
Also this line just sends rubbish and not 0x40.
HAL_SPI_Transmit(&hspi1,(uint8_t *)OPCODEW,sizeof(uint8_t),SPI_TRANSFER_TIMEOUT); // Send the MCP23S09 opcode, and write bit
Notice that your are casting OPCODEW to a uint8_t* so actually you will pass the 0x40 as a pointer (pointing to some random memory) and not as the data.
I can't seem to get my SPI line to work. It doesn't want to transmit at all although it does generate a clock signal on sck pin.
The Clock signal has a frequency of 62 kHz, the MOSI and MISO pins remain high indefinitely. I've built the code according to how the library defines it should be used, although I'm not sure if my transmit function is incorrect. I've also done error and state checks, the error checks come back saying there are no errors and the state says that the SPI bus is ready.
Here's my code:
//*****************************************************************************
//
//! \file main.c
//! \brief main application
//! \version 1.0.0.0
//! \date $Creat_time$
//! \author $Creat_author$
//! \copy
//!
//! Copyright (c) 2014 CooCox. All rights reserved.
//
//! \addtogroup project
//! #{
//! \addtogroup main
//! #{
//*****************************************************************************
#include "stm32f4xx.h"
#include "stm32f4xx_hal.h"
int main(void)
{
//Initialize Variables
//*****************************************************************************
uint32_t x;
uint32_t x1;
//Variables to check the state of the SPI bus.
HAL_SPI_StateTypeDef t;
HAL_SPI_StateTypeDef t1;
HAL_SPI_StateTypeDef t2;
HAL_SPI_StateTypeDef t3;
HAL_SPI_StateTypeDef t4;
HAL_SPI_StateTypeDef t5;
HAL_SPI_StateTypeDef t6;
HAL_SPI_StateTypeDef t7;
HAL_SPI_StateTypeDef t8;
HAL_SPI_StateTypeDef t9;
uint8_t message = 0xA4;
//*****************************************************************************
//(1)Declare a SPI_HandleTypeDef handle structure, for example: SPI_HandleTypeDef hspi;
//*****************************************************************************
SPI_HandleTypeDef SPIinit;
SPIinit.Instance = SPI1;
t1= HAL_SPI_GetState(&SPIinit);
//*****************************************************************************
//(2)Initialize the SPI low level resources by implementing the HAL_SPI_MspInit ()API:
//*****************************************************************************
HAL_SPI_MspInit(&SPIinit);
t2= HAL_SPI_GetState(&SPIinit);
//*****************************************************************************
// (3) Enable the SPIx interface clock
//*****************************************************************************
__HAL_RCC_SPI1_CLK_ENABLE();
t3 = HAL_SPI_GetState(&SPIinit);
//*****************************************************************************
// (4) SPI pins configuration
//(4.a) Enable the clock for the SPI GPIOs
//*****************************************************************************
__HAL_RCC_GPIOB_CLK_ENABLE();
//*****************************************************************************
//(4.b) Configure these SPI pins as alternate function push-pull
//*****************************************************************************
//Configure the SPI SCK,MISO & MOSI pins
GPIO_InitTypeDef NSS;
NSS.Pin = GPIO_PIN_4;
NSS.Mode = GPIO_MODE_AF_PP;
NSS.Pull = GPIO_PULLUP;
NSS.Speed = GPIO_SPEED_LOW;
NSS.Alternate = GPIO_AF5_SPI1;
//HAL_GPIO_Init(GPIOA, &NSS);
GPIO_InitTypeDef SCK;
SCK.Pin = GPIO_PIN_3;
SCK.Mode = GPIO_MODE_AF_PP;
SCK.Pull = GPIO_PULLUP;
SCK.Speed = GPIO_SPEED_LOW;
SCK.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOB, &SCK);
GPIO_InitTypeDef MISO;
MISO.Pin = GPIO_PIN_4;
MISO.Mode = GPIO_MODE_AF_PP;
MISO.Pull = GPIO_PULLUP;
MISO.Speed = GPIO_SPEED_LOW;
MISO.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOB, &MISO);
GPIO_InitTypeDef MOSI;
MOSI.Pin = GPIO_PIN_5;
MOSI.Mode = GPIO_MODE_AF_PP;
MOSI.Pull = GPIO_PULLUP;
MOSI.Speed = GPIO_SPEED_LOW;
MOSI.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOB, &MOSI);
//Configure the SPI NSS pin
//*****************************************************************************
//(5) Program the Mode, Direction , Data size, Baudrate Prescaler, NSS management, Clock polarity and phase, FirstBit and CRC configuration in the hspi Init structure
//*****************************************************************************
SPI_InitTypeDef SPItest;
SPItest.Mode = SPI_MODE_MASTER;
SPItest.Direction = SPI_DIRECTION_1LINE;
SPItest.DataSize = SPI_DATASIZE_8BIT;
SPItest.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
SPItest.CLKPhase = SPI_PHASE_1EDGE;
SPItest.CLKPolarity = SPI_POLARITY_LOW;
SPItest.FirstBit = SPI_FIRSTBIT_LSB;
SPItest.TIMode = SPI_TIMODE_DISABLE ;
SPItest.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
SPItest.NSS = SPI_NSS_SOFT;
t4= HAL_SPI_GetState(&SPIinit);
//*****************************************************************************
//(6) Initialize the SPI registers by calling the HAL_SPI_Init() API:
//*****************************************************************************
HAL_SPI_Init(&SPIinit);
t5= HAL_SPI_GetState(&SPIinit);
//*****************************************************************************
__HAL_SPI_ENABLE(&SPIinit);
while(1)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
//t6= HAL_SPI_GetState(&SPIinit);
//x1 = HAL_SPI_GetError(&SPIinit);
HAL_SPI_Transmit(&SPIinit, &message, 7, 0x01);
// t8= HAL_SPI_GetState(&SPIinit);
// x = HAL_SPI_GetError(&SPIinit);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
}
}
// SPI STATE CHECK
// HAL_SPI_STATE_RESET = 0x00, /*!< SPI not yet initialized or disabled */
// HAL_SPI_STATE_READY = 0x01, /*!< SPI initialized and ready for use */
// HAL_SPI_STATE_BUSY = 0x02, /*!< SPI process is ongoing */
// HAL_SPI_STATE_BUSY_TX = 0x12, /*!< Data Transmission process is ongoing */
// HAL_SPI_STATE_BUSY_RX = 0x22, /*!< Data Reception process is ongoing */
// HAL_SPI_STATE_BUSY_TX_RX = 0x32, /*!< Data Transmission and Reception process is ongoing */
// HAL_SPI_STATE_ERROR = 0x03 /*!< SPI error state */
// SPI ERROR CHECK
//#define HAL_SPI_ERROR_NONE ((uint32_t)0x00000000) /*!< No error */
//#define HAL_SPI_ERROR_MODF ((uint32_t)0x00000001) /*!< MODF error */
//#define HAL_SPI_ERROR_CRC ((uint32_t)0x00000002) /*!< CRC error */
//#define HAL_SPI_ERROR_OVR ((uint32_t)0x00000004) /*!< OVR error */
//#define HAL_SPI_ERROR_FRE ((uint32_t)0x00000008) /*!< FRE error */
//#define HAL_SPI_ERROR_DMA ((uint32_t)0x00000010) /*!< DMA transfer error */
//#define HAL_SPI_ERROR_FLAG ((uint32_t)0x00000010) /*!< Flag: RXNE,TXE, BSY */
I've tried both GPIOA and GPIOB alternate functions..Any help will really be appreciated
With your current code, it seems that you don't actually set up your SPI instance. You do not set up the SPI_InitTypeDef of your SPI_HandleTypeDef. Replace your SPItest by SPIinit.Init:
//SPI_InitTypeDef SPItest;
SPIinit.Init.Mode = SPI_MODE_MASTER;
SPIinit.Init.Direction = SPI_DIRECTION_1LINE;
SPIinit.Init.DataSize = SPI_DATASIZE_8BIT;
SPIinit.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
SPIinit.Init.CLKPhase = SPI_PHASE_1EDGE;
SPIinit.Init.CLKPolarity = SPI_POLARITY_LOW;
SPIinit.Init.FirstBit = SPI_FIRSTBIT_LSB;
SPIinit.Init.TIMode = SPI_TIMODE_DISABLE ;
SPIinit.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
SPIinit.Init.NSS = SPI_NSS_SOFT;
HAL_SPI_Init(&SPIinit);
I have smt32l1xx board and this code below is not working. Debugger shows pinA5 is set, but diode connected to this pin is still not lightening. I dont know why. Even i add delay after setting bit it is not working. diode is connected to PA5 and GND on board.
#include <stm32l1xx.h>
#define ENABLE 1
#define DISABLE 0
void TIM2_IRQHandler() //interrupt
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_5))
GPIO_ResetBits(GPIOA, GPIO_Pin_5); //LED OFF
else
GPIO_SetBits(GPIOA, GPIO_Pin_5); //LED ON <- im here and still nothing
}
}
int main(void)
{
/* gpio init struct */
GPIO_InitTypeDef gpio;
TIM_TimeBaseInitTypeDef tim;
NVIC_InitTypeDef nvic;
/* reset rcc */
RCC_DeInit();
RCC_APB2PeriphClockCmd(RCC_AHBENR_GPIOAEN, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
GPIO_StructInit(&gpio);
/* use pin 0 */
gpio.GPIO_Pin = GPIO_Pin_5;
/* mode: output */
gpio.GPIO_Mode = GPIO_Mode_OUT;
/* apply configuration */
GPIO_Init(GPIOA, &gpio);
TIM_TimeBaseStructInit(&tim); //timer
tim.TIM_CounterMode = TIM_CounterMode_Up;
tim.TIM_Prescaler = 64000 - 1;
tim.TIM_Period = 1000 - 1;
TIM_TimeBaseInit(TIM2, &tim);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2, ENABLE);
nvic.NVIC_IRQChannel = TIM2_IRQn; //interrupt
nvic.NVIC_IRQChannelPreemptionPriority = 0;
nvic.NVIC_IRQChannelSubPriority = 0;
nvic.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic);
while (1)
{
}
/* never reached */
return 0;
}
To make sure that your hardware is properly initialized, you should use STM32CubeMX.
It seems that the GPIOA clock is on the AHB bus, however you call RCC_APB2PeriphClockCmd which is for APB2. So try to use the equivalent for AHB something like RCC_AHBPeriphClockCmd
I am using an STM32F100RB at the moment and I am trying to read a value from a potentiometer and to display it through the PWM signal. The problem I have is where I am connecting them I think. The PWM signal is generated through this code:
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
uint32_t Prescaler, Period;
/* Enable GPIO clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* Enable TIM clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
/* Configure TIM1_CH1 as alternate function push-pull */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; // No point in overdriving
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Both these must ultimately fit in 16-bit, ie 1..65536 */
Prescaler = (SystemCoreClock / 20000); // System -> 20 KHz
Period = 2000; // 20 KHz -> 1 Hz
/* Extra caution required with TIM1/TIM8 full function timers, to initialize ALL fields */
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)(Prescaler - 1);
TIM_TimeBaseStructure.TIM_Period = (uint16_t)(Period - 1);
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // Where do those stairs go? They go up!
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // Not used
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // Not used
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_Pulse = (uint16_t)(Period / ADC1ConvertedValue[0]); // 50%
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
/* TIM1 enable counter */
TIM_Cmd(TIM1, ENABLE);
/* TIM1 Main Output Enable */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
while (1)
{
}
The PWM output works fine, and it displays what it should display. The problem comes with the ADC, where something seems not to work as it should (the code is from the manufacturer website), and this is the full code.
#include "stm32f10x.h"
//#include "stm32f10x_conf.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_adc.h"
#include "stm32f10x_dma.h"
#include "stm32f10x_flash.h"
#define ADC1_DR_Address ((uint32_t)0x4001244C)
#define BufferLenght 4
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
uint16_t ADC1ConvertedValue[BufferLenght];
ErrorStatus HSEStartUpStatus;
void RCC_Configuration(void);
void GPIO_Configuration(void);
RCC_Configuration();
GPIO_Configuration();
/* DMA1 channel1 configuration ---------------------------------------------*/
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC1ConvertedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = BufferLenght;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
/* Enable DMA1 channel1 */
DMA_Cmd(DMA1_Channel1, ENABLE);
/* ADC1 configuration ------------------------------------------------------*/
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = BufferLenght;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channel11, channel14, channel16 and channel17 configurations */
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_17, 2, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 3, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 4, ADC_SampleTime_1Cycles5);
/* Enable ADC1 DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Enable TempSensor and Vrefint channels: channel16 and Channel17 */
ADC_TempSensorVrefintCmd(ENABLE);
/* Enable ADC1 reset calibaration register */
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));
/* Start ADC1 calibaration */
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
/* Test on Channel 1 DMA1_FLAG_TC flag */
while(!DMA_GetFlagStatus(DMA1_FLAG_TC1));
/* Clear Channel 1 DMA1_FLAG_TC flag */
DMA_ClearFlag(DMA1_FLAG_TC1);
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
uint32_t Prescaler, Period;
/* Enable GPIO clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* Enable TIM clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
/* Configure TIM1_CH1 as alternate function push-pull */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; // No point in overdriving
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Both these must ultimately fit in 16-bit, ie 1..65536 */
Prescaler = (SystemCoreClock / 20000); // System -> 20 KHz
Period = 2000; // 20 KHz -> 1 Hz
/* Extra caution required with TIM1/TIM8 full function timers, to initialize ALL fields */
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)(Prescaler - 1);
TIM_TimeBaseStructure.TIM_Period = (uint16_t)(Period - 1);
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // Where do those stairs go? They go up!
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // Not used
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // Not used
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_Pulse = (uint16_t)(Period / ADC1ConvertedValue[0]); // 50%
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
/* TIM1 enable counter */
TIM_Cmd(TIM1, ENABLE);
/* TIM1 Main Output Enable */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
while (1)
{
}
}
/**
* #brief Configures the different system clocks.
* #param None
* #retval None
*/
void RCC_Configuration(void)
{
/* RCC system reset(for debug purpose) */
RCC_DeInit();
/* Enable HSE */
RCC_HSEConfig(RCC_HSE_ON);
/* Wait till HSE is ready */
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)
{
/* Enable Prefetch Buffer */
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/* Flash 2 wait state */
FLASH_SetLatency(FLASH_Latency_2);
/* HCLK = SYSCLK */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* PCLK2 = HCLK */
RCC_PCLK2Config(RCC_HCLK_Div1);
/* PCLK1 = HCLK/2 */
RCC_PCLK1Config(RCC_HCLK_Div2);
/* ADCCLK = PCLK2/4 */
RCC_ADCCLKConfig(RCC_PCLK2_Div4);
#ifndef STM32F10X_CL
/* PLLCLK = 8MHz * 7 = 56 MHz */
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7);
#else
/* Configure PLLs *********************************************************/
/* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
RCC_PREDIV2Config(RCC_PREDIV2_Div5);
RCC_PLL2Config(RCC_PLL2Mul_8);
/* Enable PLL2 */
RCC_PLL2Cmd(ENABLE);
/* Wait till PLL2 is ready */
while (RCC_GetFlagStatus(RCC_FLAG_PLL2RDY) == RESET)
{}
/* PLL configuration: PLLCLK = (PLL2 / 5) * 7 = 56 MHz */
RCC_PREDIV1Config(RCC_PREDIV1_Source_PLL2, RCC_PREDIV1_Div5);
RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_7);
#endif
/* Enable PLL */
RCC_PLLCmd(ENABLE);
/* Wait till PLL is ready */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
/* Select PLL as system clock source */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* Wait till PLL is used as system clock source */
while(RCC_GetSYSCLKSource() != 0x08)
{
}
}
/* Enable DMA1 clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* Enable peripheral clocks --------------------------------------------------*/
/* Enable ADC1 and GPIOC clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
}
/**
* #brief Configures the different GPIO ports.
* #param None
* #retval None
*/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure PC.01 and PC.04 (Channel11 and Channel14) as analog input -----*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
I am combining those two parts of code at the point where I should divide the value that TIM_Pulse is assigned:
TIM_OCInitStructure.TIM_Pulse = (uint16_t)(Period / ADC1ConvertedValue[0]);
I am a newcome in the embedded programming, and I just started playing with this board and the goal I want to achieve is to set the Pulse length according to the potentiometer value.
Thank you in advance,
Alex.
The modified code looks like this:
#include "stm32f10x_conf.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_adc.h"
#include "stm32f10x_tim.h"
double x = 0;
GPIO_InitTypeDef myGPIO;
ADC_InitTypeDef myADC;
void adc_config()
{
//ADC
myGPIO.GPIO_Pin = GPIO_Pin_6; //setat pe pin6
myGPIO.GPIO_Mode = GPIO_Mode_AIN; //setare ca analog
GPIO_Init(GPIOA, &myGPIO); //set to A6
RCC_ADCCLKConfig (RCC_PCLK2_Div6); //ceas pentru ADC (max 14MHz, 72/6=12MHz)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //ceas ADC
//configurare parametrii ADC
myADC.ADC_Mode = ADC_Mode_Independent;
myADC.ADC_ScanConvMode = DISABLE;
myADC.ADC_ContinuousConvMode = ENABLE;
myADC.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
myADC.ADC_DataAlign = ADC_DataAlign_Right;
myADC.ADC_NbrOfChannel = 1;
ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 1, ADC_SampleTime_55Cycles5); //PA6 as Input
ADC_Init(ADC1, &myADC);
//enable
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
ADC_Cmd(ADC1, ENABLE);
}
int getPot(void)
{
return ADC_GetConversionValue(ADC1);
}
//configurare pini I/O
void GPIO_config(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
//LED-pinC9
GPIO_StructInit(&myGPIO);
myGPIO.GPIO_Pin = GPIO_Pin_9;
myGPIO.GPIO_Mode = GPIO_Mode_Out_PP;
myGPIO.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOC, &myGPIO);
}
int main(void)
{
GPIO_config(); //configurare pini
adc_config(); //configurare ADC
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
uint32_t Prescaler, Period;
/*!< At this stage the microcontroller clock setting is already configured,
this is done through SystemInit() function which is called from startup
file (startup_stm32f10x_xx.s) before to branch to application main.
To reconfigure the default setting of SystemInit() function, refer to
system_stm32f10x.c file
*/
/* Enable GPIO clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* Enable TIM clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
/* Configure TIM1_CH1 as alternate function push-pull */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; // No point in overdriving
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Both these must ultimately fit in 16-bit, ie 1..65536 */
Prescaler = (SystemCoreClock / 200000); // System -> 20 KHz
Period = 2000; // 20 KHz -> 1 Hz
/* Extra caution required with TIM1/TIM8 full function timers, to initialize ALL fields */
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)(Prescaler - 1);
TIM_TimeBaseStructure.TIM_Period = (uint16_t)(Period - 1);
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // Where do those stairs go? They go up!
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // Not used
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // Not used
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
while(1)
{
x = getPot()*3.3/4096; //obtinere valoare analog si convertirea in volti, 12bit ADC
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_Pulse = (uint16_t)(Period / x); // 50%
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
/* TIM1 enable counter */
TIM_Cmd(TIM1, ENABLE);
/* TIM1 Main Output Enable */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
if(x > 2)
{
GPIO_WriteBit(GPIOC, GPIO_Pin_9, Bit_SET);//pornire Led
}
else {
GPIO_WriteBit(GPIOC, GPIO_Pin_9, Bit_RESET);//oprire Led
}
}
}
Thanks to #Olaf.
I have experienced a very strange problem in developing my application for the ST Microelectronics iNemo. My applications consists in:
Gyroscope reading with SPI
Accelerometer and Magnetometer (in the same device) reading with I2C
Attitude estimation algorithm
PD functions
Data receiving with USART, with interrupt without DMA
Sending of logging packet, with USART
The loop is triggered by a timer at 100Hz.
The program works well (I have tested it with some USART debug prints) until I start sending data with the USART: my initial guess was that, since this fact enables the receiving of interrupts, it causes problem with the I2C bus arbitrage mechanism. My guess is derived that when I have succeeded in debugging the problem (that is time dependent), with USART prints, I have detected that the last print is always before the accelerometer of magnetometer prints (the first that I call in my code).
Additionally, If I enable the verbose debug prints via USART that I have mentioned the problem occurs in fewer occasions, while if I disable it and I send only logging packet the problem occurs always and immediately. Anyone can give me an idea of what can be the cause of this problem? Thanks
EDIT: I attach my I2C code:
#define DMA_BUFFER_SIZE 196
#define FORCE_CRITICAL_SEC
/**
* #brief DMA initialization structure variable definition.
*/
DMA_InitTypeDef I2CDMA_InitStructure;
/**
* #brief Volatile variable definition for I2C direction.
*/
__IO uint32_t I2CDirection = I2C_DIRECTION_TX;
void iNemoI2CInit(I2C_TypeDef* I2Cx, uint32_t I2CxSpeed)
{
I2C_InitTypeDef I2C_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIO clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);
/* Configure I2C pins: SCL and SDA */
if(I2Cx==I2C2)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
}
else
{
GPIO_PinRemapConfig(GPIO_Remap_I2C1,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
}
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* I2C configuration */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = I2CxSpeed;
/* Apply I2C configuration after enabling it */
I2C_Init(I2Cx, &I2C_InitStructure);
/* I2C Peripheral Enable */
I2C_Cmd(I2Cx, ENABLE);
/* Enable DMA if required */
#if (defined(I2C1_USE_DMA_TX) || defined(I2C1_USE_DMA_RX))
if (I2Cx==I2C1)
iNemoI2CDMAInit(I2C1);
#endif
#if (defined(I2C2_USE_DMA_TX) || defined(I2C2_USE_DMA_RX))
if (I2Cx==I2C2)
iNemoI2CDMAInit(I2C2);
#endif
}
void iNemoI2CDMAInit(I2C_TypeDef* I2Cx)
{
/* Enable the DMA1 clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* I2C TX DMA Channel configuration */
I2CDMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)0; /* This parameter will be configured durig communication */
I2CDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; /* This parameter will be configured durig communication */
I2CDMA_InitStructure.DMA_BufferSize = 0xFFFF; /* This parameter will be configured durig communication */
I2CDMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
I2CDMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
I2CDMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte;
I2CDMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
I2CDMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
I2CDMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
I2CDMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
if(I2Cx==I2C2)
{
I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C2_DR_Address;
#ifdef I2C2_USE_DMA_TX
DMA_DeInit(I2C2_DMA_CHANNEL_TX);
DMA_Init(I2C2_DMA_CHANNEL_TX, &I2CDMA_InitStructure);
#endif
#ifdef I2C2_USE_DMA_RX
/* I2C2 RX DMA Channel configuration */
DMA_DeInit(I2C2_DMA_CHANNEL_RX);
DMA_Init(I2C2_DMA_CHANNEL_RX, &I2CDMA_InitStructure);
#endif
}
if(I2Cx==I2C1)
{
I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_Address;
#ifdef I2C1_USE_DMA_TX
DMA_DeInit(I2C1_DMA_CHANNEL_TX);
DMA_Init(I2C1_DMA_CHANNEL_TX, &I2CDMA_InitStructure);
#endif
#ifdef I2C1_USE_DMA_RX
/* I2C1 RX DMA Channel configuration */
DMA_DeInit(I2C1_DMA_CHANNEL_RX);
DMA_Init(I2C1_DMA_CHANNEL_RX, &I2CDMA_InitStructure);
#endif
}
void iNemoI2CDMAConfig(I2C_TypeDef* I2Cx, uint8_t* pBuffer, uint32_t lBufferSize, uint32_t lDirection)
{
/* Initialize the DMA with the new parameters */
if (lDirection == I2C_DIRECTION_TX)
{
/* Configure the DMA Tx Channel with the buffer address and the buffer size */
I2CDMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)pBuffer;
I2CDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
I2CDMA_InitStructure.DMA_BufferSize = (uint32_t)lBufferSize;
if(I2Cx==I2C2)
{
I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C2_DR_Address;
DMA_Cmd(I2C2_DMA_CHANNEL_TX, DISABLE);
DMA_Init(I2C2_DMA_CHANNEL_TX, &I2CDMA_InitStructure);
DMA_Cmd(I2C2_DMA_CHANNEL_TX, ENABLE);
}
else
{
I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_Address;
DMA_Cmd(I2C1_DMA_CHANNEL_TX, DISABLE);
DMA_Init(I2C1_DMA_CHANNEL_TX, &I2CDMA_InitStructure);
DMA_Cmd(I2C1_DMA_CHANNEL_TX, ENABLE);
}
}
else /* Reception */
{
/* Configure the DMA Rx Channel with the buffer address and the buffer size */
I2CDMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)pBuffer;
I2CDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
I2CDMA_InitStructure.DMA_BufferSize = (uint32_t)lBufferSize;
if(I2Cx==I2C2)
{
I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C2_DR_Address;
DMA_Cmd(I2C2_DMA_CHANNEL_RX, DISABLE);
DMA_Init(I2C2_DMA_CHANNEL_RX, &I2CDMA_InitStructure);
DMA_Cmd(I2C2_DMA_CHANNEL_RX, ENABLE);
}
else
{
I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_Address;
DMA_Cmd(I2C1_DMA_CHANNEL_RX, DISABLE);
DMA_Init(I2C1_DMA_CHANNEL_RX, &I2CDMA_InitStructure);
DMA_Cmd(I2C1_DMA_CHANNEL_RX, ENABLE);
}
}
}
void iNemoI2CBufferReadDma(I2C_TypeDef* I2Cx, uint8_t cAddr, uint8_t* pcBuffer, uint8_t cReadAddr, uint8_t cNumByteToRead)
{
__IO uint32_t temp = 0;
__IO uint32_t Timeout = 0;
/* Enable I2C errors interrupts */
I2Cx->CR2 |= I2C_IT_ERR;
/* Set the MSb of the register address in case of multiple readings */
if(cNumByteToRead>1)
cReadAddr |= 0x80;
#ifdef FORCE_CRITICAL_SEC
__disable_irq();
#endif
#ifdef USART_DEBUG2
USART1_Printf("FLAG BUSY\r\n");
#endif
Timeout = 0xFFFF;
/* While the bus is busy */
while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY)){
if (Timeout-- == 0)
return;
}
/* Send START condition */
I2C_GenerateSTART(I2Cx, ENABLE);
#ifdef USART_DEBUG2
USART1_Printf("MASTER MODE\r\n");
#endif
Timeout = 0xFFFF;
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT)){
if (Timeout-- == 0)
return;
}
/* Send LSM303DLH address for read */
I2C_Send7bitAddress(I2Cx, cAddr, I2C_Direction_Transmitter);
Timeout = 0xFFFF;
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){
if (Timeout-- == 0)
return;
}
/* Clear EV6 by setting again the PE bit */
I2C_Cmd(I2Cx, ENABLE);
/* Send the LSM303DLH_Magn's internal address to write to */
I2C_SendData(I2Cx, cReadAddr);
#ifdef USART_DEBUG2
USART1_Printf("BYTE TRANSMITTED\r\n");
#endif
Timeout = 0xFFFF;
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){
if (Timeout-- == 0)
return;
}
/* Configure I2Cx DMA channel */
iNemoI2CDMAConfig(I2Cx, pcBuffer, cNumByteToRead, I2C_DIRECTION_RX);
/* Set Last bit to have a NACK on the last received byte */
I2Cx->CR2 |= 0x1000;
/* Enable I2C DMA requests */
I2C_DMACmd(I2Cx, ENABLE);
Timeout = 0xFFFF;
/* Send START condition */
I2C_GenerateSTART(I2Cx, ENABLE);
Timeout = 0xFFFF;
/* Wait until SB flag is set: EV5 */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
{
if (Timeout-- == 0)
return;
}
Timeout = 0xFFFF;
/* Send LSM303DLH address for read */
I2C_Send7bitAddress(I2Cx, cAddr, I2C_Direction_Receiver);
Timeout = 0xFFFF;
/* Wait until ADDR is set: EV6 */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
{
if (Timeout-- == 0)
return;
}
/* Clear ADDR flag by reading SR2 register */
temp = I2Cx->SR2;
if(I2Cx == I2C2)
{
Timeout = 0xFFFF;
/* Wait until DMA end of transfer */
while (!DMA_GetFlagStatus(DMA1_FLAG_TC5)){
if (Timeout-- == 0)
return;
}
/* Disable DMA Channel */
DMA_Cmd(I2C2_DMA_CHANNEL_RX, DISABLE);
/* Clear the DMA Transfer Complete flag */
DMA_ClearFlag(DMA1_FLAG_TC5);
}
else
{
/* Wait until DMA end of transfer */
#ifdef USART_DEBUG2
USART1_Printf("END TRANSFER\r\n");
#endif
Timeout = 0xFFFF;
while (!DMA_GetFlagStatus(DMA1_FLAG_TC7)){
if (Timeout-- == 0)
return;
}
/* Disable DMA Channel */
DMA_Cmd(I2C1_DMA_CHANNEL_RX, DISABLE);
/* Clear the DMA Transfer Complete flag */
DMA_ClearFlag(DMA1_FLAG_TC7);
}
/* Disable Ack for the last byte */
I2C_AcknowledgeConfig(I2Cx, DISABLE);
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
#ifdef USART_DEBUG2
USART1_Printf("STOP BIT\r\n");
#endif
Timeout = 0xFFFF;
/* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
while ((I2Cx->CR1 & 0x0200) == 0x0200){
if (Timeout-- == 0)
return;
}
/* Enable Acknowledgement to be ready for another reception */
I2C_AcknowledgeConfig(I2Cx, ENABLE);
#ifdef FORCE_CRITICAL_SEC
__enable_irq();
#endif
}
void iNemoI2CBufferWriteDma(I2C_TypeDef* I2Cx, uint8_t cAddr, uint8_t* pcBuffer, uint8_t cWriteAddr, uint8_t cNumByteToWrite)
{
__IO uint32_t temp = 0;
__IO uint32_t Timeout = 0;
static uint8_t pcDmaBuffer[DMA_BUFFER_SIZE+1];
/* Set to 1 the MSb of the register address in case of multiple byte writing */
if(cNumByteToWrite>1)
cWriteAddr |= 0x80;
pcDmaBuffer[0]=cWriteAddr;
memcpy(&pcDmaBuffer[1],pcBuffer,cNumByteToWrite);
/* Enable Error IT */
I2Cx->CR2 |= I2C_IT_ERR;
Timeout = 0xFFFF;
/* Configure the DMA channel for I2Cx transmission */
iNemoI2CDMAConfig(I2Cx, pcDmaBuffer, cNumByteToWrite+1, I2C_DIRECTION_TX);
/* Enable DMA for I2C */
I2C_DMACmd(I2Cx, ENABLE);
/* Send START condition */
I2C_GenerateSTART(I2Cx, ENABLE);
/* Wait until SB flag is set: EV5 */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
{
if (Timeout-- == 0)
return;
}
Timeout = 0xFFFF;
/* Send LSM303DLH address for write */
I2C_Send7bitAddress(I2Cx, cAddr, I2C_Direction_Transmitter);
/* Wait until ADDR is set: EV6 */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if (Timeout-- == 0)
return;
}
/* Clear ADDR flag by reading SR2 register */
temp = I2Cx->SR2;
/* Disable the DMA1 channel */
if(I2Cx == I2C2)
{
/* Wait until DMA end of transfer */
while (!DMA_GetFlagStatus(DMA1_FLAG_TC4));
/* Disable DMA Channel */
DMA_Cmd(I2C2_DMA_CHANNEL_TX, DISABLE);
/* Clear the DMA Transfer complete flag */
DMA_ClearFlag(DMA1_FLAG_TC4);
}
else
{
/* Wait until DMA end of transfer */
while (!DMA_GetFlagStatus(DMA1_FLAG_TC6));
/* Disable DMA Channel */
DMA_Cmd(I2C1_DMA_CHANNEL_TX, DISABLE);
/* Clear the DMA Transfer complete flag */
DMA_ClearFlag(DMA1_FLAG_TC6);
}
/* EV8_2: Wait until BTF is set before programming the STOP */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
/* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
while ((I2Cx->CR1 & 0x0200) == 0x0200);
}
I see that for some while loops you have a timeout, but for some you don't:
while ((I2Cx->CR1 & 0x0200) == 0x0200);
Make all your loops timeout, and also make a note where the error condition occurs (it needs to be investigated - if you don't know the reason, it will come back to haunt you later).
Hardware can be a bit buggy at times, so it completely possible you're doing everything correctly, but it still doesn't work. Check errata (for STM32 I2C and your I2C slaves) for documented bugs.
A few years ago I came across an issue where I2C lines would stay low, and I had to reconfigure pins as GPIO, bit-bang some bits out, and then it I could switch back to I2C operation.