I recently purchased a NUCLEO-F446RE board (an STM32F4 product) and one minor issue has been bugging me. All the code I've written executes and works just fine, but they only work after pressing the reset button on the NUCLEO board.
IDE: Keil v5
For example, I wrote code for a blinking LED:
#include "stm32f446xx.h"
int main(void) {
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
GPIOA->MODER |= GPIO_MODER_MODE5_0;
GPIOA->ODR |= GPIO_ODR_OD5;
volatile int i;
while(1) {
for(i=0; i<100000; i++)
GPIOA->ODR |= GPIO_ODR_OD5;
for(i=0; i<100000; i++)
GPIOA->ODR &= ~GPIO_ODR_OD5;
}
}
After I run and download the code onto the board, nothing will happen. Once I press reset, the LED will blink as expected.
I'm fairly certain it's something not included in my code because when I run an example program it executes immediately.
For example, a blinking LED provided by KIEL:
#include <stdio.h>
#include "Board_LED.h" // ::Board Support:LED
#include "Board_Buttons.h" // ::Board Support:Buttons
#include "stm32f4xx.h" // Device header
extern int stdout_init (void);
volatile uint32_t msTicks; /* counts 1ms timeTicks */
/*----------------------------------------------------------------------------
* SysTick_Handler:
*----------------------------------------------------------------------------*/
void SysTick_Handler(void) {
msTicks++;
}
/*----------------------------------------------------------------------------
* Delay: delays a number of Systicks
*----------------------------------------------------------------------------*/
void Delay (uint32_t dlyTicks) {
uint32_t curTicks;
curTicks = msTicks;
while ((msTicks - curTicks) < dlyTicks) { __NOP(); }
}
/*----------------------------------------------------------------------------
* SystemCoreClockConfigure: configure SystemCoreClock using HSI
(HSE is not populated on Nucleo board)
*----------------------------------------------------------------------------*/
void SystemCoreClockConfigure(void) {
RCC->CR |= ((uint32_t)RCC_CR_HSION); /* Enable HSI */
while ((RCC->CR & RCC_CR_HSIRDY) == 0); /* Wait for HSI Ready */
RCC->CFGR = RCC_CFGR_SW_HSI; /* HSI is system clock */
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI); /* Wait for HSI used as system clock */
FLASH->ACR = (FLASH_ACR_PRFTEN | /* Enable Prefetch Buffer */
FLASH_ACR_ICEN | /* Instruction cache enable */
FLASH_ACR_DCEN | /* Data cache enable */
FLASH_ACR_LATENCY_5WS ); /* Flash 5 wait state */
RCC->CFGR |= (RCC_CFGR_HPRE_DIV1 | /* HCLK = SYSCLK */
RCC_CFGR_PPRE1_DIV2 | /* APB1 = HCLK/2 */
RCC_CFGR_PPRE2_DIV1 ); /* APB2 = HCLK/1 */
RCC->CR &= ~RCC_CR_PLLON; /* Disable PLL */
/* PLL configuration: VCO = HSI/M * N, Sysclk = VCO/P */
RCC->PLLCFGR = ( 16ul | /* PLL_M = 16 */
(200ul << 6) | /* PLL_N = 200 */
( 0ul << 16) | /* PLL_P = 2 */
(RCC_PLLCFGR_PLLSRC_HSI) | /* PLL_SRC = HSI */
( 7ul << 24) | /* PLL_Q = 7 */
( 2ul << 28) ); /* PLL_R = 2 */
RCC->CR |= RCC_CR_PLLON; /* Enable PLL */
while((RCC->CR & RCC_CR_PLLRDY) == 0) __NOP(); /* Wait till PLL is ready */
RCC->CFGR &= ~RCC_CFGR_SW; /* Select PLL as system clock source */
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); /* Wait till PLL is system clock src */
}
/*----------------------------------------------------------------------------
* main: blink LED and check button state
*----------------------------------------------------------------------------*/
int main (void) {
int32_t max_num = LED_GetCount();
int32_t num = 0;
SystemCoreClockConfigure(); /* configure HSI as System Clock */
SystemCoreClockUpdate();
LED_Initialize();
Buttons_Initialize();
stdout_init(); /* Initializ Serial interface */
SysTick_Config(SystemCoreClock / 1000); /* SysTick 1 msec interrupts */
for (;;) {
LED_On(num); /* Turn specified LED on */
Delay(500); /* Wait 500ms */
while (Buttons_GetState() & (1 << 0)); /* Wait while holding USER button */
LED_Off(num); /* Turn specified LED off */
Delay(500); /* Wait 500ms */
while (Buttons_GetState() & (1 << 0)); /* Wait while holding USER button */
num++; /* Change LED number */
if (num >= max_num) {
num = 0; /* Restart with first LED */
}
printf ("Hello World\n\r");
}
}
The example code doesn't appear to have anything special that will make it run immediately.
Any help is greatly appreciated.
My guess is that it's in the project flash tools settings, maybe "run to main" or "Load Application at Startup" (not your code). To check, copy/paste your code over the top of one of the samples.
In Kiel Following Steps Follow:
Go to "Flash" options.
In flash, go to "Configure Flash Tools".
Go to the last bar/option "Utilities"
In utilities chose "Settings" options.
Finally,tick "Run and Reset" Options.
upload the code, it working without a click reset button.
I got the same problem. In Keil you need to go to "Flash -> Configure Flash Tools -> Utilities" and turn on "Run and reset" option
Regards:)
Related
I was trying DMA in stm32f103rc. I followed this tutorial https://letanphuc.net/2014/06/how-to-use-stm32-dma/ and wrote my own code using CMSIS CORE. Here i m taking two arrays one 'sourceArr' where i am storing a random value and copying that array to 'destArr' with the help of DMA.
DMA RELATED FUNCTIONS DEFINES AND VARIABLES
volatile uint32_t status = 0;
uint32_t sourceArr[ARRAYSIZE];
uint32_t destArr[ARRAYSIZE];
#define DMA1_CLOCK_EN() (RCC->AHBENR = RCC_AHBENR_DMA1EN)
#define DMA1_CHANNEL1_EN() (DMA1_Channel1->CCR |= DMA_CCR1_EN) //((uint16_t)0x0001)
void DMA1_Channel1_IRQHandler(void)
{
if (DMA1->ISR & DMA_ISR_TCIF1)
{
status = 1;
Blink_Led(5000);
DMA1->IFCR |= DMA_IFCR_CTCIF1;
}
}
void NVIC_Init()
{
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
NVIC_SetPriority(DMA1_Channel1_IRQn, 0);
}
void DMA_Init(void)
{
DMA1_Channel1->CCR |= DMA_CCR1_MEM2MEM; /*Memory to memory transfer enable ((uint16_t)0x4000)*/
DMA1_Channel1->CCR &= ~DMA_CCR1_CIRC; /* circular mode* ((uint16_t)0x0020) */
/* Priroty set as medium PL[1:0] = 01 */
DMA1_Channel1->CCR |= DMA_CCR1_PL_0; //((uint16_t)0x1000)
/* source and destination data size set as 32bit */
DMA1_Channel1->CCR |= DMA_CCR1_MSIZE_1; //((uint16_t)0x0800)
DMA1_Channel1->CCR |= DMA_CCR1_PSIZE_1; //((uint16_t)0x0200)
/* Auto increment of memory enabled for source and destination */
DMA1_Channel1->CCR |= DMA_CCR1_PINC; //((uint16_t)0x0040)
DMA1_Channel1->CCR |= DMA_CCR1_MINC; //((uint16_t)0x0080)
/* Data transfer direction set as read from peripheral*/
DMA1_Channel1->CCR &= ~DMA_CCR1_DIR; //((uint16_t)0x0010)
/* source and destination start addresses */
DMA1_Channel1->CPAR = (uint32_t)&sourceArr;
DMA1_Channel1->CMAR = (uint32_t)&destArr;
/* Enable DMA1 Channel Transfer Complete interrupt */
DMA1_Channel1->CCR |= DMA_CCR1_TCIE; //((uint16_t)0x0002)
}
void DMA_DeInit(void)
{
DMA1_Channel1->CCR &= (uint16_t)~DMA_CCR1_EN; /* Disable the selected DMAy Channelx */
DMA1_Channel1->CCR = 0; /* Reset DMAy Channelx control register */
DMA1_Channel1->CNDTR = 0; /* Reset DMAy Channelx remaining bytes register */
DMA1_Channel1->CPAR = 0; /* Reset DMAy Channelx peripheral address register */
DMA1_Channel1->CMAR = 0; /* Reset DMAy Channelx memory address register */
DMA1->IFCR |= DMA_IFCR_CGIF1 | DMA_IFCR_CTCIF1 | DMA_IFCR_CHTIF1 | DMA_IFCR_CTEIF1; /* Reset interrupt pending bits for DMA1 Channel1 */
}
MAIN
int main(void)
{
int i;
for (i=0;i<ARRAYSIZE;i++)
sourceArr[i] = i;
Led_Init();
Blink_Led(1000);
DMA1_CLOCK_EN(); //enable clock for DMA
DMA_DeInit();
DMA_Init();
NVIC_Init();
Blink_Led(1000);
status = 0;
__enable_irq();
DMA1_CHANNEL1_EN(); //Enable DMA1 Channel 1 transfer
while(status==0);
Blink_Led(1000);
for (i=0; i<ARRAYSIZE;i++)
{
destArr[i]=sourceArr[i];
}
Blink_Led(1000);
while (1)
{
}
}
if everything works fine then there will be 5 Blinks. 4 in the main function and 1 in IRQ.
But i am only getting two blinks.
Any suggestions will be really helpful.
Thanks in Advance
You should set the number of data to transfer
DMA1_Channel1->CNDTR = ARRAYSIZE;
before enabling the channel with DMA1_CHANNEL1_EN().
Thanks for your help everyone. I have got the correct answer. It was my mistake as i forgot to set number of data to be transferred. The working source code is
#include "stm32f10x.h"
#define ARRAYSIZE 100
#define LED_PORT_EN() ( RCC->APB2ENR |= RCC_APB2ENR_IOPDEN )
#define LED_PORT GPIOD
#define LED_MODE_BIT1 8
#define LED_MODE_BIT2 9
#define LED_CNF_BIT1 10
#define LED_CNF_BIT2 11
#define CNF_SET_PORTD(BIT1,BIT2) ( LED_PORT->CRL &= ~((1<<BIT1) | (1<<BIT2)) ) //General purpose output push-pull
#define MODE_SET_PORTD(BIT1,BIT2) ( LED_PORT->CRL |= (1<<BIT1) | (1<<BIT2) ) //Output mode, max speed 50 MHz.
#define SET_GPIO_BIT_PORTD(BIT) ( LED_PORT->BSRR = (1 << BIT) ) //For setting the Bit
#define RESET_GPIO_BIT_PORTD(BIT) ( LED_PORT->BSRR = ( (1 << BIT) << 16 ) ) //For Resseting Bit
volatile uint32_t status = 0;
uint32_t sourceArr[ARRAYSIZE];
uint32_t destArr[ARRAYSIZE];
#define DMA1_CLOCK_EN() (RCC->AHBENR |= RCC_AHBENR_DMA1EN)
#define DMA1_CHANNEL1_EN() (DMA1_Channel1->CCR |= DMA_CCR1_EN) //((uint16_t)0x0001)
void Delay(int ms);
void Led_Init(void);
void Blink_Led(int ms);
void DMA_DeInit(void);
void DMA_Init(void);
void NVIC_Init(void);
void DMA1_Channel1_IRQHandler(void);
int main(void)
{
int i;
for (i=0;i<ARRAYSIZE;i++)
sourceArr[i] = i;
Led_Init();
Blink_Led(1000);
DMA1_CLOCK_EN(); //enable clock for DMA
DMA_DeInit();
DMA_Init();
NVIC_Init();
Blink_Led(1000);
status = 0;
__enable_irq();
DMA1_CHANNEL1_EN(); //Enable DMA1 Channel 1 transfer
while(status==0);
Blink_Led(1000);
for (i=0; i<ARRAYSIZE;i++)
{
destArr[i]=sourceArr[i];
}
Blink_Led(1000);
while (1)
{
}
}
void DMA1_Channel1_IRQHandler(void)
{
if (DMA1->ISR & DMA_ISR_TCIF1)
{
status = 1;
Blink_Led(5000);
DMA1->IFCR |= DMA_IFCR_CTCIF1;
}
}
void NVIC_Init()
{
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
NVIC_SetPriority(DMA1_Channel1_IRQn, 0);
}
void DMA_Init(void)
{
DMA1_Channel1->CCR |= DMA_CCR1_MEM2MEM; /*Memory to memory transfer enable ((uint16_t)0x4000)*/
DMA1_Channel1->CCR &= ~DMA_CCR1_CIRC; /* circular mode* ((uint16_t)0x0020) */
/* Priroty set as medium PL[1:0] = 01 */
DMA1_Channel1->CCR |= DMA_CCR1_PL_0; //((uint16_t)0x1000)
/* source and destination data size set as 32bit */
DMA1_Channel1->CCR |= DMA_CCR1_MSIZE_1; //((uint16_t)0x0800)
DMA1_Channel1->CCR |= DMA_CCR1_PSIZE_1; //((uint16_t)0x0200)
/* Auto increment of memory enabled for source and destination */
DMA1_Channel1->CCR |= DMA_CCR1_PINC; //((uint16_t)0x0040)
DMA1_Channel1->CCR |= DMA_CCR1_MINC; //((uint16_t)0x0080)
/* Data transfer direction set as read from peripheral*/
DMA1_Channel1->CCR &= ~DMA_CCR1_DIR; //((uint16_t)0x0010)
/*size of data to be transfered*/
DMA1_Channel1->CNDTR = ARRAYSIZE;
/* source and destination start addresses */
DMA1_Channel1->CPAR = (uint32_t)sourceArr;
DMA1_Channel1->CMAR = (uint32_t)destArr;
/* Enable DMA1 Channel Transfer Complete interrupt */
DMA1_Channel1->CCR |= DMA_CCR1_TCIE; //((uint16_t)0x0002)
}
void DMA_DeInit(void)
{
DMA1_Channel1->CCR &= (uint16_t)~DMA_CCR1_EN; /* Disable the selected DMAy Channelx */
DMA1_Channel1->CCR = 0; /* Reset DMAy Channelx control register */
DMA1_Channel1->CNDTR = 0; /* Reset DMAy Channelx remaining bytes register */
DMA1_Channel1->CPAR = 0; /* Reset DMAy Channelx peripheral address register */
DMA1_Channel1->CMAR = 0; /* Reset DMAy Channelx memory address register */
DMA1->IFCR |= DMA_IFCR_CGIF1 | DMA_IFCR_CTCIF1 | DMA_IFCR_CHTIF1 | DMA_IFCR_CTEIF1; /* Reset interrupt pending bits for DMA1 Channel1 */
}
/** #breif: For wait and doing nothing i.e for delay
* #param: delaya time
* #retVal: None
*/
void Delay(int ms)
{
int i,j;
for (i = 0; i < ms; ++i) {
for (j = 0; j < 5000; ++j);
}
}
/** #breif: Initalize GPIO For Led
* #param: None
* #retVal: None
*/
void Led_Init()
{
LED_PORT_EN(); //Enable RCC for Led Port
CNF_SET_PORTD(LED_CNF_BIT1,LED_CNF_BIT2); //SET CNF General purpose output push-pull
MODE_SET_PORTD(LED_MODE_BIT1,LED_MODE_BIT2); //SET MODE Output mode, max speed 50 MHz.
}
/** #breif: Blink Led Placed in PORT D Pin 2
* #param: Delay for each state(ON/OFF)
* #retVal: None
*/
void Blink_Led(int ms)
{
RESET_GPIO_BIT_PORTD(2); //Make Led High
Delay(ms); //wait
SET_GPIO_BIT_PORTD(2); //Make Led Low
Delay(ms); //wait
}
Thanks every one.
It's actually a basic code for controlling buzzer with leds. I did with HAL libraries.But the institution I was working with wanted to do this at the register level too. But I couldn't it. It's not too complicated however i don't understand where the problem is.
My code in below.
#include "stm32f10x.h"
void SystemCoreClockConfigure(void)
{
RCC->CR |= ((uint32_t)RCC_CR_HSION); // Enable HSI
while ((RCC->CR & RCC_CR_HSIRDY) == 0); // Wait for HSI Ready
RCC->CFGR = RCC_CFGR_SW_HSI; // HSI is system clock
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI); // Wait for HSI used as system clock
FLASH->ACR = FLASH_ACR_PRFTBE; // Enable Prefetch Buffer
FLASH->ACR |= FLASH_ACR_LATENCY; // Flash 1 wait state
RCC->CFGR |= RCC_CFGR_HPRE_DIV1; // HCLK = SYSCLK
RCC->CFGR |= RCC_CFGR_PPRE1_DIV2; // APB1 = HCLK/2
RCC->CFGR |= RCC_CFGR_PPRE2_DIV1; // APB2 = HCLK
RCC->CR &= ~RCC_CR_PLLON; // Disable PLL
// PLL configuration: = HSI/2 * 12 = 48 MHz
RCC->CFGR &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL);
RCC->CFGR |= (RCC_CFGR_PLLSRC_HSI_Div2 | RCC_CFGR_PLLMULL12);
RCC->CR |= RCC_CR_PLLON; // Enable PLL
while((RCC->CR & RCC_CR_PLLRDY) == 0) __NOP(); // Wait till PLL is ready
RCC->CFGR &= ~RCC_CFGR_SW; // Select PLL as system clock source
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // Wait till PLL is system clock src
}
This is the first oscillator activation part.I know that there is no problem until the main function.
In main:
int main(void)
{
SystemCoreClockUpdate();
SysTick_Config(SystemCoreClock / 1000);
RCC->APB2ENR |= (1UL << 2); /* Enable GPIOA clock */
RCC->APB2ENR |= (1UL << 4); /* Enable GPIOC clock */
// Configure the GPIO Buttons
GPIOA->CRL = 0x00000044; //1SET // GPIOA -> 0,1
GPIOC->CRL = 0x00004400; //3SET // GPIOC -> 3,2
while (1)
{
if(GPIOA->IDR == 0x0000003) // PA1 ON (Led4) //
{
GPIOC->CRH = 0x00000002; // BUZZER SET
GPIOC->BSRR = 0x00000100; // BUZZER ON
}
}
}
I'm using keil and I know that if i only set and on buzzer after
GPIOC->CRL = 0x00004400; //3SET // GPIOC -> 3,2
it's working.But with the reading input to button with GPIO->IDR(Input Data Reg.) It's not toggle or whatever i don't know.I've been stuck here for a week and it's really annoying. Heelp me !?
the code inside your while loop is completely wrong!
while(1)
{
if((GPIOA->IDR & 0x02) == 0x02) // 0x02 = 0b10 = PA1 (LED4)
{
GPIOC->BSRR = 0x100; // ON
}
else
{
GPIOC->BSRR = (0x100 << 16); // OFF
}
}
and also set the GPIOC->CRH register only once before the while loop.
I'm running some tests on STM32L152 by trying to control a DC motor speed by selecting 3 different speeds using a push button, as following:
ideal mode, motor is off.
push button pressed, motor runs at speed-1
push button pressed again, motor runs at speed-2
push button pressed again, motor stops.
I've already tried to run the motor directly by setting CCR1 (TIM4), and it works perfectly. so I believe the only issue is with the push button part. here's the code:
#include <stdio.h>
#include "stm32l1xx.h" // Keil::Device:Startup
// initialization of GPIOB, GPIOA & PWM/TIM4
void GPIO_Init()
{
// initialization of GPIOB
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOBRST; /* Reset GPIOB clock */
RCC->AHBENR |= RCC_AHBENR_GPIOBEN; /* Enable GPIOB clock*/
GPIOB->MODER &= ~(0x03 << (2 * 6)); /* Clear bit 12 & 13 Output mode*/
GPIOB->MODER |= 0x01 << (2 * 6); /* set as Output mode*/
GPIOB->OSPEEDR &= ~(0x03 << (2 * 6)); /* 40 MHz speed */
GPIOB->OSPEEDR |= 0x03 << (2 * 6); /* 40 MHz speed*/
GPIOB->PUPDR &= ~(1 << 6); /* NO PULL-UP PULL-DOWN*/
GPIOB->OTYPER &= ~(1 << 6); /* PUSH-PULL*/
GPIOB->AFR[0] |= 0x2 << (4 * 6);
// initialization of GPIOA
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOARST; /* Reset GPIOA clock*/
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; /* Enable GPIOA clock*/
GPIOA->MODER &= ~(0x03); /* Clear & set as input*/
GPIOA->OSPEEDR &= ~(0x03); /* 2 MHz speed */
GPIOA->OSPEEDR |= 0x01; /* 2 MHz speed */
GPIOA->PUPDR &= ~(0x03); /* No PULL-UP/DOWN */
GPIOA->OTYPER &= ~(0x1); /* PUSH-PULL */
//initialization of PWM & TIM4
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
TIM4->PSC = 100;
TIM4->ARR = 414; // F=2.097MHz , Fck= 2097000/(100+1)= 20.762KHz, Tpwm = 0.02, ARR= (Fck x Tpwm)-1
TIM4->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; // 111: PWM mode 1
TIM4->CCMR1 |= TIM_CCMR1_OC1PE;
TIM4->CR1 |= TIM_CR1_ARPE;
TIM4->CCER |= TIM_CCER_CC1E;
TIM4->EGR |= TIM_EGR_UG;
TIM4->SR &= ~TIM_SR_UIF;
TIM4->DIER |= TIM_DIER_UIE;
TIM4->CR1 |= TIM_CR1_CEN;
}
// Delay conf
void setSysTick(void)
{
// ---------- SysTick timer (1ms) -------- //
if (SysTick_Config(SystemCoreClock / 1000))
{
// Capture error
while (1)
{
};
}
}
volatile uint32_t msTicks; //counts 1ms timeTicks
void SysTick_Handler(void)
{
msTicks++;
}
static void Delay(__IO uint32_t dlyTicks)
{
uint32_t curTicks = msTicks;
while ((msTicks - curTicks) < dlyTicks);
}
int returnVal = 0;
int updatedpress = 0;
int buttonpress() // function to check & add, if the pushbutton is pressed
{
if (GPIOA->IDR & GPIO_IDR_IDR_0) //condition: if PA0 is set
{
Delay(500); // avoid debouncing
if (GPIOA->IDR & GPIO_IDR_IDR_0) //confirm condition: if PA0 is set
{
returnVal = 1 + updatedpress;
while (GPIOA->IDR & GPIO_IDR_IDR_0)
{
}
}
}
return returnVal;
}
int main(void)
{
GPIO_Init();
setSysTick();
while (1)
{
int buttonpress();
updatedpress = returnVal;
if (updatedpress == 1)
TIM4->CCR1 = 30;
else if (updatedpress == 2)
TIM4->CCR1 = 37;
else if (updatedpress == 3)
TIM4->CCR1 = 46;
else if (updatedpress > 3)
returnVal = 0;
}
}
When I run the code, nothing works physiclly. I tried to run the debugger and I found that it exits the buttonpress function immedtialy after reaching
if(GPIOA->IDR & GPIO_IDR_IDR_0)
Any idea why it doesn't work as it should?
The GPIO peripherals are held in reset, you should clear the reset bits:
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOBRST
RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOBRST
/* ... */
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOARST;
RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOARST;
Ok it worked, and here are the corrections made:
1/ PB6 (which is connected to the DC motor) was mistakenly set as output. changed to Alternate Function.
2/ If-Conditions used for comparing the number of button-press and select motor speed is shifted to a separate function called runmotor
3/ The read instruction if(GPIOA->IDR & 0x0001) is moved into the while loop within the main function to ensure a continuous check of the pushbutton condition.
4/ Reset of GPIOs are cleared, as advised by #berendi
here's the updated code:
#include <stdio.h>
#include "stm32l1xx.h" // Keil::Device:Startup
// initialization of GPIOB, GPIOA & PWM/TIM4
void GPIO_Init(){
// initialization of GPIOB
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOBRST; /* Reset GPIOB clock*/
RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOBRST; /* Clear Reset */
RCC->AHBENR |= RCC_AHBENR_GPIOBEN; /* Enable GPIOB clock*/
GPIOB->MODER &= ~(0x03 << (2*6)); /* Clear bit 12 & 13 */
GPIOB->MODER |= 0x02 << (2*6); /* set as Alternate function*/
GPIOB->OSPEEDR &= ~(0x03<< (2*6)); /* 40 MHz speed*/
GPIOB->OSPEEDR |= 0x03<< (2*6); /* 40 MHz speed */
GPIOB->PUPDR &= ~(1<<6); /* NO PULL-UP PULL-DOWN*/
GPIOB->OTYPER &= ~(1<<6); /* PUSH-PULL*/
GPIOB->AFR[0] |= 0x2 << (4*6);
// initialization of GPIOA
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOARST; /* Reset GPIOA clock */
RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOARST; /* Clear Reset */
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; /* Enable GPIOA clock */
GPIOA->MODER &= ~(0x03); /* Clear & set as input */
GPIOA->OSPEEDR &= ~(0x03); /* 2 MHz speed */
GPIOA->OSPEEDR |= 0x01; /* 2 MHz speed */
GPIOA->PUPDR &= ~(0x03); /* reset PULL-DOWN */
GPIOA->OTYPER &= ~(0x1); /* PUSH-PULL */
//initialization of PWM & TIM4
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
TIM4->PSC = 100;
TIM4->ARR = 414; // F=2.097MHz , Fck= 2097000/(100+1)= 20.762KHz, Tpwm = 0.02, ARR= (Fck x Tpwm)-1
TIM4->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; // 111: PWM mode 1
TIM4->CCMR1 |= TIM_CCMR1_OC1PE;
TIM4->CR1 |= TIM_CR1_ARPE;
TIM4->CCER |= TIM_CCER_CC1E;
TIM4->EGR |= TIM_EGR_UG;
TIM4->SR &= ~TIM_SR_UIF;
TIM4->DIER |= TIM_DIER_UIE;
TIM4->CR1 |= TIM_CR1_CEN;
}
void setSysTick(void){
// ---------- SysTick timer (1ms) -------- //
if (SysTick_Config(SystemCoreClock / 1000)) {
// Capture error
while (1){};
}
}
volatile uint32_t msTicks; //counts 1ms timeTicks
void SysTick_Handler(void) {
msTicks++;
}
static void Delay(__IO uint32_t dlyTicks){
uint32_t curTicks = msTicks;
while ((msTicks - curTicks) < dlyTicks);
}
int buttonpress=0;
static void runmotor(void)
{
if (buttonpress ==1){
TIM4->CCR1 = 30;
return;
}
if (buttonpress ==2){
TIM4->CCR1 = 37;
return;
}
if (buttonpress ==3){
TIM4->CCR1 = 46;
return;
}
if (buttonpress > 3){
TIM4->CCR1 = 0;
buttonpress = 0;
return;
}
}
int main(void){
GPIO_Init();
setSysTick();
while (1){
if(GPIOA->IDR & 0x0001)
{
Delay(5);
if(GPIOA->IDR & 0x0001)
buttonpress = buttonpress + 1;
runmotor();
}
}
}
I wrote up a function to connect via UART and print a string for debugging purposes. But my logic does not add up somehow... I see the line "Random Number" printed in the console but blazingly fast... no matter what I add for a _delay_ms value, it is not usable. Did I miss out on anything?
Why is my delay function not having any influence on the output on the serial terminal?
void initUSART(void) {
#define BAUDRATE ((F_CPU) / (BAUD * 8UL)-1) // Set Baud Rate Value for UBRR
// Set register
UBRR0H = (BAUDRATE >> 8);
UBRR0L = BAUDRATE;
UCSR0A |= (1 << U2X0);
// Enable USART transmitter and receiver
UCSR0B = (1 << TXEN0) | (1 << RXEN0);
// Set 8 data bits and 1 stop bit
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
}
void transmitByte(uint8_t data) {
// Wait for empty transmit buffer
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = data;
}
void printString(const char myString[]) {
uint8_t i = 0;
while (myString[i]) {
transmitByte(myString[i]);
i++;
}
}
int main(void)
{
setup();
randomSeed(adcRead(0));
while (1)
{
printString("Random Number:\n");
_delay_ms(100000);
}
return (0);
}
When I use \r\nat the end of the string, the output gets really strange:
When I try this test code everything works as expected, the LED blinks every second. I really don't see where the difference is, as it is the same function.
/* Blinker Demo */
// ------- Preamble -------- //
#include <avr/io.h> /* Defines pins, ports, etc */
#include <util/delay.h> /* Functions to waste time */
int main(void) {
// -------- Inits --------- //
DDRB |= 0b00000001; /* Data Direction Register B:
writing a one to the bit
enables output. */
// ------ Event loop ------ //
while (1) {
PORTB = 0b00000001; /* Turn on first LED bit/pin in PORTB */
_delay_ms(1000); /* wait */
PORTB = 0b00000000; /* Turn off all B pins, including LED */
_delay_ms(1000); /* wait */
} /* End event loop */
return 0; /* This line is never reached */
}
Hi I write code below for initial External Interrupt for LPC2138 in KEIL 4.7 Compiler and when run code in proteus software , code dosent Work. I double check VIC and EXTINT registers seems correct. thanks
Project Picture on Proteus
one Switch on EXTINT2 (P0.15) and one LED on P1.25
#include <LPC213x.h>
void delay(int count);
void init_ext_interrupt(void);
__irq void Ext_ISR(void);
int main (void)
{
init_ext_interrupt(); // initialize the external interrupt
while (1)
{
}
}
void init_ext_interrupt(void) //Initialize Interrupt
{
EXTMODE = (1<<2); //Edge sensitive mode on EINT2
EXTPOLAR &= ~(1<<2); //Falling Edge Sensitive
PINSEL0 = 0x80000000; //Select Pin function P0.15 as EINT2
/* initialize the interrupt vector */
VICIntSelect &= ~(1<<16); // EINT2 selected as IRQ 16
VICVectAddr5 = (unsigned)Ext_ISR; // address of the ISR
VICVectCntl5 = (1<<5) | 16;
VICIntEnable = (1<<16); // EINT2 interrupt enabled
EXTINT &= ~(1<<2); //Set interrupt
}
__irq void Ext_ISR(void) // Interrupt Service Routine-ISR
{
IO1DIR |= (1<<25);
IO1SET |= (1<<25); // Turn ON LED
delay(100000);
IO1CLR |= (1<<25); // Turn OFF LED
EXTINT |= (1<<2); //clear interrupt
VICVectAddr = 0; // End of interrupt execution
}
void delay(int count)
{
int j=0,i=0;
for(j=0;j<count;j++)
{
for(i=0;i<35;i++);
}
}
You should correct the line:
(VICVectCntl5 = (1<<5) | 16;)
to:
(VICVectCntl5 = 0x20 | 16;)
as datasheet said.