Atmega32A with 16MHZ crystal oscillator runs slowly - c

I have decided to program Atmega32A in Arduino to enjoy its numerous I/O pins. To achieve that, I specified the board definition in the boards.txt file and also defined the pin mappings in the pins_arduino.h. However, the microcontroller runs slowly as if the external crystal oscillator does not take effect. The board definitions and pin mappings are shown below:
Atmega32A definition in boards.txt file:
mega32-16.name=ATmega32-External 16mhz
mega32-16.build.mcu=atmega32
mega32-16.build.f_cpu=16000000L
mega32-16.build.core=arduino:arduino
mega32-16.build.variant=mega32
mega32-16.upload.tool=avrdude
mega32-16.upload.protocol=arduino
mega32-16.upload.maximum_size=32000
mega32-16.bootloader.low_fuses=0xEF
mega32-16.bootloader.high_fuses=0x89
#mega32-16.bootloader.extended_fuses=0xFD
**pins_arduino.h **
/*
Author: Eric Conner
Email: Eric#EricConnerApps.com
Date: 06-10-2013
Project: ATmega32 for Arduino IDE
Version: v1.2
*/
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include <avr/pgmspace.h>
#define NOT_ON_TIMER 0
#define TIMER0A 1
#define TIMER0B 2
#define TIMER1A 3
#define TIMER1B 4
#define TIMER2 5
#undef TCCR2A
#define NOT_A_PORT 0
#define NOT_ON_TIMER 0
/*
ATMEL ATmega32
+---\\---+
(XCK/T0) D0 PB0 01| |40 PA0 AI7 D31 (ADC0)
(T1) D1 PB1 02| |39 PA1 AI6 D30 (ADC1)
(INT2/AIN0) D2 PB2 03| |38 PA2 AI5 D29 (ADC2)
(OC0/AIN1) D3 PB3 04| |37 PA3 AI4 D28 (ADC3)
(SS) D4 PB4 05| |36 PA4 AI3 D27 (ADC4)
(MOSI) D5 PB5 06| |35 PA5 AI2 D26 (ADC5)
(MISO) D6 PB6 07| |34 PA6 AI1 D25 (ADC6)
(SCK) D7 PB7 08| |33 PA7 AI0 D24 (ADC7)
RESET 09| |32 AREF
VCC 10| |31 GND
GND 11| |30 AVCC
XTAL2 12| |29 PC7 D23 (TOSC2)
XTAL1 13| |28 PC6 D22 (TOSC1)
(RXD) D8 PD0 14| |27 PC5 D21 (TDI)
(TXD) D9 PD1 15| |26 PC4 D20 (TDO)
(INT0) D10 PD2 16| |25 PC3 D19 (TMS)
(INT1) D11 PD3 17| |24 PC2 D18 (TCK)
(OC1B) D12 PD4 18| |23 PC1 D17 (SDA)
(OC1A) D13 PD5 19| |22 PC0 D16 (SCL)
(ICP1) D14 PD6 20| |21 PD7 D15 (OC2)
+--------+
*/
const static uint8_t SDA = 17; //correct
const static uint8_t SCL = 16; //correct
const static uint8_t SS = 4;
const static uint8_t MOSI = 5;
const static uint8_t MISO = 6;
const static uint8_t SCK = 7;
#define NUM_DIGITAL_PINS 32
#define NUM_ANALOG_INPUTS 8
#define analogInputToDigitalPin(p) ((p < 8) ? (p) + 24 : -1)
#define digitalPinHasPWM(p) ((p) == 4 || (p) == 5 || (p) == 7)
#ifdef ARDUINO_MAIN
const uint16_t PROGMEM port_to_mode_PGM[] = {
NOT_A_PORT,
(uint16_t) &DDRA,
(uint16_t) &DDRB,
(uint16_t) &DDRC,
(uint16_t) &DDRD,
NOT_A_PORT,
NOT_A_PORT,
};
const uint16_t PROGMEM port_to_output_PGM[] = {
NOT_A_PORT,
(uint16_t) &PORTA,
(uint16_t) &PORTB,
(uint16_t) &PORTC,
(uint16_t) &PORTD,
NOT_A_PORT,
NOT_A_PORT,
};
const uint16_t PROGMEM port_to_input_PGM[] = {
NOT_A_PORT,
(uint16_t) &PINA,
(uint16_t) &PINB,
(uint16_t) &PINC,
(uint16_t) &PIND,
NOT_A_PORT,
NOT_A_PORT,
};
const uint8_t PROGMEM digital_pin_to_port_PGM[32] = {
PB, // PB0 ** D0
PB, // PB1 ** D1
PB, // PB2 ** D2
PB, // PB3 ** D3
PB, // PB4 ** D4
PB, // PB5 ** D5
PB, // PB6 ** D6
PB, // PB7 ** D7
PD, // PD0 ** D8
PD, // PD1 ** D9
PD, // PD2 ** D10
PD, // PD3 ** D11
PD, // PD4 ** D12
PD, // PD5 ** D13
PD, // PD6 ** D14
PD, // PD7 ** D15
PC, // PC0 ** D16
PC, // PC1 ** D17
PC, // PC2 ** D18
PC, // PC3 ** D19
PC, // PC4 ** D20
PC, // PC5 ** D21
PC, // PC6 ** D22
PC, // PC7 ** D23
PA, // PA7 ** A0 D24
PA, // PA6 ** A1 D25
PA, // PA5 ** A2 D26
PA, // PA4 ** A3 D27
PA, // PA3 ** A4 D28
PA, // PA2 ** A5 D29
PA, // PA1 ** A6 D30
PA, // PA0 ** A7 D31
};
const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[32] = {
_BV(0), // PB0 ** D0
_BV(1), // PB1 ** D1
_BV(2), // PB2 ** D2
_BV(3), // PB3 ** D3
_BV(4), // PB4 ** D4
_BV(5), // PB5 ** D5
_BV(6), // PB6 ** D6
_BV(7), // PB7 ** D7
_BV(0), // PD0 ** D8
_BV(1), // PD1 ** D9
_BV(2), // PD2 ** D10
_BV(3), // PD3 ** D11
_BV(4), // PD4 ** D12
_BV(5), // PD5 ** D13
_BV(6), // PD6 ** D14
_BV(7), // PD7 ** D15
_BV(0), // PC0 ** D16
_BV(1), // PC1 ** D17
_BV(2), // PC2 ** D18
_BV(3), // PC3 ** D19
_BV(4), // PC4 ** D20
_BV(5), // PC5 ** D21
_BV(6), // PC6 ** D22
_BV(7), // PC7 ** D23
_BV(7), // PA7 ** A0 D24
_BV(6), // PA6 ** A1 D25
_BV(5), // PA5 ** A2 D26
_BV(4), // PA4 ** A3 D27
_BV(3), // PA3 ** A4 D28
_BV(2), // PA2 ** A5 D29
_BV(1), // PA1 ** A6 D30
_BV(0), // PA0 ** A7 D31
};
const uint8_t PROGMEM digital_pin_to_timer_PGM[32] = {
NOT_ON_TIMER, // PB0 ** D0
NOT_ON_TIMER, // PB1 ** D1
NOT_ON_TIMER, // PB2 ** D2
TIMER0A, // PB3 ** D3
NOT_ON_TIMER, // PB4 ** D4
NOT_ON_TIMER, // PB5 ** D5
NOT_ON_TIMER, // PB6 ** D6
NOT_ON_TIMER, // PB7 ** D7
NOT_ON_TIMER, // PD0 ** D8
NOT_ON_TIMER, // PD1 ** D9
NOT_ON_TIMER, // PD2 ** D10
NOT_ON_TIMER, // PD3 ** D11
TIMER1B, // PD4 ** D12
TIMER1A, // PD5 ** D13
NOT_ON_TIMER, // PD6 ** D14
TIMER2, // PD7 ** D15
NOT_ON_TIMER, // PC0 ** D16
NOT_ON_TIMER, // PC1 ** D17
NOT_ON_TIMER, // PC2 ** D18
NOT_ON_TIMER, // PC3 ** D19
NOT_ON_TIMER, // PC4 ** D20
NOT_ON_TIMER, // PC5 ** D21
NOT_ON_TIMER, // PC6 ** D22
NOT_ON_TIMER, // PC7 ** D23
NOT_ON_TIMER, // PA7 ** A0 D24
NOT_ON_TIMER, // PA6 ** A1 D25
NOT_ON_TIMER, // PA5 ** A2 D26
NOT_ON_TIMER, // PA4 ** A3 D27
NOT_ON_TIMER, // PA3 ** A4 D28
NOT_ON_TIMER, // PA2 ** A5 D29
NOT_ON_TIMER, // PA1 ** A6 D30
NOT_ON_TIMER, // PA0 ** A7 D31
};
#endif
#endif
My problem here is, calling delay(100) function causes delay of more than 1000 milli seconds instead of 100 milli seconds. What do I do to get correct clock frequency according to 16MHZ oscillator?
I tried to change the crystall oscillator but nothing changes.

AFAIK, there's only few things that might impact incorrect delay:
F_CPU, which is present in your config and I believe already passed to your compiler - I would check this.
Clock fuse settings - check CKDIV8, etc.
Clock related registers - check CLKPR, CLKPCE, etc. Note, this step might be not required if fuses are programmed for a correct speed.
Wrong value of an oscillator.

Thanks a lot to everyone who helped me in one way or the other. I was able to get the microcontroller working with 16MHZ external oscillator by taking the following steps:
Installed AVRDUDE
Connected USBtinyISP to the microcontroller through ISP interface.
Run the following command in the command prompt to set low and high fuses of the microcontroller: avrdude -c usbtiny -p m32 -U lfuse:w:0xbf:m -U hfuse:w:0xce:m

Related

CC430 UART Reading Problem -Receive Interrupt Flag is Always '0'

I'm trying to establish UART communication. I can send data from CC430F6137 to other MCU .However I couldn't handle receive operation. I'm sure that other MCU sends the data through UART Tx pin , but I couldn't get this datas from CC430 Rx pin.
My code is that :
#include <stdio.h>
#include <msp430.h>
#include "cc430x613x.h"
char buffer_0[5] ;
char terminal_read();
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
UART_open();
UCA0IE |= UCRXIE ;
while(1)
{
terminal_read();
// __delay_cycles(1e5);
}
return 0;
}
char terminal_read()
{
char c ;
while (!(UCA0IFG & UCRXIFG));
c = UCA0RXBUF ;
printf("%c" , &c);
return UCA0RXBUF;
}
void terminal_write(char *info)
{
unsigned int i;
unsigned int len = strlen(info) ;
for(i=0;i<len;i++)
{
UCA0TXBUF=info[i];
__delay_cycles(10000);
}
}
void UART_open()
{
P1SEL |= BIT5 + BIT6;
//UART Settings
UCA0CTL1 |= UCSWRST;
UCA0CTL1 |= UCSSEL0 ; // ACLK
UCA0BR0=3; //UCA0BR0 = 3 ; //32Khz / 9600 –>> 3
UCA0BR1=0; //UCA0BR1=0; // BAUD 9600; ( UCABR1 * 256 ) + UCABR0 = UCABRx see "slau259e.pdf"
UCA0MCTL=UCBRS0 + UCBRS1 ; // see "slau259e.pdf" page 602 //
//UCA0MCTL =| BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 |
// |------- UCBRFx --------------|----UCBRSx----------|UCOS16|
// for 9600 baudrate at 32kHz UCBRFx = 0 , UCBRSx = 3 , UCOS16 = 0
// | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
// 0b00000110 = 0x06 = 6
UCA0CTL1 &=~ UCSWRST;//
// UCA0CTL1 |= UCDORM;
}
void UART_close()
{
P1SEL &= ~(BIT5 + BIT6);
P1DIR |= BIT5 + BIT6;
P1OUT &= ~(BIT5 + BIT6);
UCA0CTL1 |= UCSWRST;
UCA0CTL1 &=~ UCDORM;
}
char* String_int(int data)
{
char* ret_data;
ret_data = ltoa(data , buffer_0 , 10 );
return ret_data;
}
What's wrong with my code? I always read the UCRXIFG as '0'. So 'terminal_read' function always stuck on this line.
Since you are polling for the interrupt flag in the terminal_read() function, then you don't need to enable interrupt with UCA0IE |= UCRXIE; because that will cause the CPU to go to the interrupt vector, which your code doesn't provide. Instead, remove the UCA0IE |= UCRXIE; and continue polling.
Also, the printf() will go to the terminal of the Debug window only if you have the JTAG debugger attached, otherwise it could get stuck. I agree with Peter that it could get stuck here if you don't have the debugger attached. Try removing that and replace with an LED blinker so you know the terminal_read() isn't getting stuck.

Blink leds while switches are pressed in Tiva C

I'm trying to make the PF0 and PF4 leds blink while the switches are pressed. But it simply does not turn on any leds.
I was told I needed to use two ports, I don't see why, since this can be done with only one port — in this case the port D — but it was suggested that I use the port K as well (?).
The board is a Tiva C TM4c1294nctpd
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
#include <inc/tm4c1294ncpdt.h>
uint32_t SW1,SW2; //
int main(void) {
while(1){
SYSCTL_RCGCGPIO_R=0X1100; // Enable port D
GPIO_PORTD_DIR_R=0X03; //enable the GPIO pin PN0,
GPIO_PORTD_DEN_R=0X03;
GPIO_PORTK_AHB_DIR_R=0;
GPIO_PORTK_AHB_DEN_R=0X03;
GPIO_PORTK_AHB_PUR_R=0X01;
SW1 = GPIO_PORTD_DATA_R&0x10; // read PF4 into SW1
SW2 = GPIO_PORTD_DATA_R&0x01; // read PF0 into SW2
if (!SW1 && !SW2) { // both pressed
GPIO_PORTD_DATA_R = 0x04;
} else if (!SW1) { // SW1 pressed
GPIO_PORTD_DATA_R = 0x02;
} else if (!SW2) { // SW2 pressed
GPIO_PORTD_DATA_R = 0x08;
} else { // neither
GPIO_PORTD_DATA_R = 0x00;
}
}
}
You have only enabled D0 and D1, but appear to be using D0, D1, D2, D3 and D4.
You have set D0 and D1 as output, but appear to be be using D1, D2, D3 as outputs.
You have set D0 as an output, but attempt to read it as an input.
The configuration of PORTK is entirely irrelevant if you are not using it.
The RCGCGPIO enables the clock for PORTN and PORTJ which you are not using at all.
I am not familiar with the part and have only briefly read the data sheet, but the the PORTD clock, direction and digital enable configuration should be as follows if the input/output code is itself correct.
SYSCTL_RCGCGPIO_R = 0x0008; // Enable port D clock
GPIO_PORTD_DIR_R = 0x0E; // D4, D0 input, D1 to D3 output.
GPIO_PORTD_DEN_R = 0x1F; // Enable D0 to D4
These initialisation settings need be done once only - before the loop, not inside it.
int main(void)
{
SYSCTL_RCGCGPIO_R = 0x0008; // Enable port D
GPIO_PORTD_DIR_R = 0x0E; // D4, D0 input, D1 to D3 output.
GPIO_PORTD_DEN_R = 0x1F; // Enable D0 to D4
for(;;)
{
uint32_t SW1 = GPIO_PORTD_DATA_R & 0x10; // read PD4 into SW1
uint32_t SW2 = GPIO_PORTD_DATA_R & 0x01; // read PD0 into SW2
if (!SW1 && !SW2) // both pressed
{
GPIO_PORTD_DATA_R = 0x04;
}
else if (!SW1) // SW1 pressed
{
GPIO_PORTD_DATA_R = 0x02;
}
else if (!SW2) // SW2 pressed
{
GPIO_PORTD_DATA_R = 0x08;
}
else // neither
{
GPIO_PORTD_DATA_R = 0x00;
}
}
}
After thought:
The comments in the presumably copy & pasted code suggest the board might be an EK-TM4C1294XL. In that case the the LEDs are called D1, D2, D3, D4 (D for diode, not _PORTD), but are on GPIOs PN1, PN0, PF4 and PF0 respectively, and the switches are on PJ0 and PJ1.
In that case perhaps the following will be more successful:
int main(void)
{
SYSCTL_RCGCGPIO_R |= (1<<5 | 1<<8 | 1<<12); // Enable port F, J and N clocks
GPIO_PORTN_DIR_R |= 0x03; // PN1 = LED0, PN0 = LED1 (Outputs)
GPIO_PORTN_DEN_R |= 0x03; // Enable PN0 and PN1
GPIO_PORTF_DIR_R |= 0x11; // PF4 = LED3, PF0 = LED4 (Outputs)
GPIO_PORTF_DEN_R |= 0x11; // Enable PF0 and PF4
GPIO_PORTJ_DIR_R &= ~0x03; // PJ0 = SW1, PJ1 = SW2 (Inputs)
GPIO_PORTJ_DEN_R &= ~0x03; // Enable PJ0 and PJ4
for(;;)
{
uint32_t SW1 = GPIO_PORTJ_DATA_R & 0x01; // read PJ0 into SW1
uint32_t SW2 = GPIO_PORTJ_DATA_R & 0x02; // read PJ1 into SW2
if (!SW1 && !SW2) // both pressed
{
GPIO_PORTF_DATA_R = 0x01; // LED4
}
else if (!SW1) // SW1 pressed
{
GPIO_PORTF_DATA_R = 0x10; // LED3
}
else if (!SW2) // SW2 pressed
{
GPIO_PORTN_DATA_R = 0x01; // LED2
}
else // neither
{
GPIO_PORTN_DATA_R = 0x02; // LED1
}
}
}
This remains broken because the code only ever switches LED's on - an it does not respect other hardware that may be connected to other pins on ports F and N; you need to add code to read-modify-write the respective pins fo reach LED you set, you need to clear the other three. I'll leave that to you - it goes beyond the original question.

ATmega4808 32 Pin - Pin PA0 doesn't get set HIGH

I'm using an ATmega4808 32 Pin. I have 2 LEDs connected to the pins PA0 and PA1. I want to set both high. Unfortunatly only the PA1 LED is on.
I figured out the PA0 Pin could be set to EXTCLK by default. If this is the problem i can't find the solution to change the port to GPIO.
int main(int argc, char** argv) {
PORTA.DIRSET = PIN0_bm; // Config PA0 as output
PORTA.DIRSET = PIN1_bm; // Config PA1 as output
PORTA.OUTSET = PIN0_bm; // Set Pin PA0 to HIGH
PORTA.OUTSET = PIN1_bm; // Set Pin PA1 to HIGH
while(1){
}
return (EXIT_SUCCESS);
}
The configuration of PIN0 is lost by writing again to registers PORTA.DIRSET and PORTA.OUTSET.
Try using | (bitwise OR) to not discard PIN0 config:
PORTA.DIRSET = PIN0_bm; // Config PA0 as output
PORTA.DIRSET |= PIN1_bm; // Config PA1 as output
PORTA.OUTSET = PIN0_bm; // Set Pin PA0 to HIGH
PORTA.OUTSET |= PIN1_bm; // Set Pin PA1 to HIGH
Or, to set them at the same time:
PORTA.DIRSET = PIN0_bm | PIN1_bm; // Config PA0 and PA1 as output
PORTA.OUTSET = PIN0_bm | PIN1_bm; // Set Pin PA0 and PA1 to HIGH

STM32 GPIO register level input

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.

Simple DC motor Speed Control with Push Button

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();
}
}
}

Resources