Trying to initialize PWM on PB4 on the TM4C123 Microcontroller - c

As the tittle states I am trying to initialize PWM for PB4 on the TM4C123 microcontroller using Keil as the IDE. So far I have been able to initialize PB6 and PB7 but i'm not sure why PB4 isn't working. Do you guys know whats I'm doing wrong? Thanks in advance for your help. I have posted my working code for initalizing port B6 and the one that isnt working for port B4.
// PWM clock rate = processor clock rate/SYSCTL_RCC_PWMDIV
// = BusClock/16
// = 80 MHz/16 = 5 MHz
// Output on PB7/M0PWM1
void PWM0B4_Init(uint16_t period, uint16_t duty)
{
volatile unsigned long delay;
SYSCTL_RCGCPWM_R |= 0x01; // 1) activate PWM0
SYSCTL_RCGCGPIO_R |= 0x02; // 2) activate port B
// delay = SYSCTL_RCGCGPIO_R; // allow time to finish activating
while((SYSCTL_PRGPIO_R&0x02) == 0){};
GPIO_PORTB_AFSEL_R |= 0x10; // enable alt funct on PB4
GPIO_PORTB_PCTL_R &= ~0x000F000; // configure PB4 as M0PWM2
GPIO_PORTB_PCTL_R |= 0x0004000;
GPIO_PORTB_AMSEL_R &= ~0x10; // disable analog functionality on PB4
GPIO_PORTB_DEN_R |= 0x10; // enable digital I/O on PB4 ** double check **
SYSCTL_RCC_R = 0x00100000 | // 3) use PWM divider
(SYSCTL_RCC_R & (~0x000C0000)); // configure for /16 divider
PWM0_1_CTL_R = 0; // 4) re-loading down-counting mode
PWM0_1_GENB_R = (PWM_1_GENB_ACTCMPBD_ONE|PWM_1_GENB_ACTLOAD_ZERO);
// PB4 goes low on LOAD
// PB4 goes high on CMPB down
PWM0_1_LOAD_R = period - 1; // 5) cycles needed to count down to 0
PWM0_1_CMPB_R = duty - 1; // 6) count value when output rises
PWM0_1_CTL_R |= 0x00000001; // 7) start PWM0
PWM0_ENABLE_R |= 0x00000004; // enable PB4/M0PWM2 **** check
}
// change duty cycle of PB4
// duty is number of PWM clock cycles output is high (2<=duty<=period-1)
void PWM0B4_Duty(uint16_t duty)
{
PWM0_1_CMPB_R = duty - 1; // 6) count value when output rises
}
void PWM0B6_Init(uint16_t period, uint16_t duty)
{
SYSCTL_RCGCPWM_R |=0x01; // 1) activate PWM0
SYSCTL_RCGCGPIO_R|=0x02; // 2) activate portB
while ((SYSCTL_PRGPIO_R&0x02) == 0) {};
GPIO_PORTB_AFSEL_R |= 0x40; // enable alt funct on PB6
GPIO_PORTB_PCTL_R &= ~0x0F000000; // configure PB6 as PWM0
GPIO_PORTB_PCTL_R |= 0x04000000;
GPIO_PORTB_AMSEL_R &= ~0x40; // disable analog functionality on PB6
GPIO_PORTB_DEN_R |= 0x40; // enable digital I/O on PB6
SYSCTL_RCC_R = 0x00100000 | // 3) use PWM divider
(SYSCTL_RCC_R & (~0x000C0000)); // configure for /16 divider to C
PWM0_0_CTL_R = 0; // 4) re-loading down-counting mode
PWM0_0_GENA_R = 0xC8; // low on LOAD, high on CMPA down
// PB6 goes low on LOAD
// PB6 goes high on CMPA down
PWM0_0_LOAD_R = period - 1; // 5) cycles needed to count down to 0
PWM0_0_CMPA_R = duty - 1; // 6) count value when output rises
PWM0_0_CTL_R |= 0x00000001; // 7) start PWM0
PWM0_ENABLE_R |= 0x00000001; // enable PB6/M0PWM0
}
// change duty cycle of PB6
// duty is number of PWM clock cycles output is high (2<=duty<=period-1)
void PWM0B6_Duty(uint16_t duty)
{
PWM0_0_CMPA_R = duty - 1; // 6) count value when output rises
}

Related

Controlling Timer0 in ATmega328p

I'm trying to create a blocking delay for the ATmega328p for my arduino uno R3. but I'm running into problems with my function.
I am not sure if it has something to do with my clock source. I set it as 8 MHz at the top of my script, but the problem persists.
#define F_CPU 8000000UL
Here's a snip of my delay function, it's configured for a 10 ms delay at 8 MHz and uses a delayTime counter to create a longer delay
/*
* Function to instantiate timer operations
*/
void makeDelay(int delayTime){
// Call the timer for delayTime successively
// resulting in delay of (configured delay) * timerDelay
while(delayTime > 0){
/* Set the TCNT reg for 10ms # 8 MHz */
TCNT0 = 0xB2;
// Define the mode and prescaler values
TCCR0A = 0x00; // Normal mode
TCCR0B = 0x05; // prescaler = 1024
// loop until overflow
while( (TIFR0 & (1 << TOV0) == 0) );
// Stop the timer
TCCR0B = 0;
// clear the overflow
TIFR0 = 0x01;
// decrement the counter
delayTime--;
}
}
Any advice would be appreciated.
In your program this waiting condition is wrong:
(TIFR0 & (1 << TOV0) == 0)
Operator == has higher precedence than &. (1 << TOV0) == 0 is evaluated first and it is always false. Thus TIFR0 & 0 is always false too.
Rewrite the condition as
((TIFR0 & (1 << TOV0)) == 0)
or
((TIFR0 & _BV(TOV0)) == 0)
You can use following formula to calculate TCCNT0 register value for milliseconds:
Nticks = 256 - ms*F_CPU/1000/prescaler
As Timer0 is used by Arduino runtime library, you should disable it at first.
Entire sketch may be like this:
#define MS2TICKS(ms) (256 - (ms)*(F_CPU/1000)/1024)
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
TCCR0B = 0; // Stop timer
TIMSK0 = 0; // Disable timer interrupts
TCCR0A = 0; // Normal mode
TIFR0 = ~0; // Clear all interrupt flags
}
void my_delay()
{
TCNT0 = MS2TICKS(10);
TCCR0B = 0x05; // Enable timer with prescaler 1024
while ((TIFR0 & _BV(TOV0)) == 0);
TCCR0B = 0; // Stop Timer0
TIFR0 = _BV(TOV0); // Clear overflow flag
}
void loop()
{
digitalWrite(LED_BUILTIN, HIGH);
my_delay();
digitalWrite(LED_BUILTIN, LOW);
my_delay();
}
It generates 10 ms pulses with 10 ms pauses on LED output.

Can I enable a button toggle interrupt to pause my timer? MSP432 -- Code Composer Studio

Hello! I am working on a project where I have to enable a timer that counts up every tenth of a second and outputs my times in binary. Independently, the timer itself works perfectly. However, I want to add a function to use my internal board switches (P1.4 and P1.1) to stop and start my timer, respectively. In any case, I am working on a MSP432P401R board. Thank you beforehand! My code:
#include "msp.h"
int sec = 0, tensec = 0, min = 0; //time stuff
int A = 1;
void Initiate(){
//internal switches -- negative logic, lazy to do outside stuff
//1.1 -- start related stuff
//1.4 -- stop relted stuff
P1->DIR &= ~0x12;
P1->REN |= 0x12;
P1->OUT |= 0x12;
//asking for start LED
P1->DIR |= BIT0;
P1->OUT &= ~BIT0;
//lights for status -- onboard
P2->DIR |= 0x07;
P2->OUT &= ~0x07;
//minute lights
P5->DIR |= 0x03;
P5->OUT &= ~0x03;
//seconds lights -- 6 LEDs
P4->DIR |= 0x3F;
P4->OUT &= ~0x3F;
//tens of sec
P6->DIR |= BIT0;
P6->OUT &= ~BIT0;
}
int main(void) {
WDT_A->CTL = WDT_A_CTL_PW | WDT_A_CTL_HOLD; // Stop WDT
// Configure GPIO
Initiate();
// Enable & configure the SysTick Timer Module
SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
// SysTick->LOAD = 0x60000 - 1; // Period = 0x60000
SysTick->LOAD = 300000; // Period = tenth of a second
SysTick->VAL = 0x01; // Clear value by writing any value
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; // Enable interrupt
// Enable global interrupt
__enable_irq();
SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk; // Sleep on exit from ISR
__DSB(); // Ensure SLEEPONEXIT takes effect immediately
while (1)
__sleep();
} // End of main
// Interrupt service routine (ISR) invoked when SysTick down counter reaches 0.
void SysTick_Handler(void)
{
A = P1->IN & BIT1;
if((!A)){ //pressing the switch will make it pause
}else{
P6->OUT ^= BIT0; // Toggle tens of sec light
tensec++;
if(tensec == 10){
sec++;
P4->OUT &=~0x3F; //refresh seconds
P4->OUT |= sec;
tensec = 0; //restart it
if(sec == 60){
sec = 0; //restart secs
min++;
P5->OUT &= ~0x3F; //refresh
P5->OUT |= min;
}
}
}
}

ADC on MSP430 stuck on either timer delay or cunable to take ADC unless I remove all timer and push button interrupt

I have used MSP430 to write a custom blinking code with adjustable frequency. I use an ADC to adjust the frequency but I have been having issues with the ADC portion of the code being stuck while I use it with timer 0 interrupts and a Port 1 interrupt. But if I remove them from the program the ADDC works fine. Could anyone help me point out my error or help me understand the mechanism with which I could have the ADC running again? Attached below is a portion of my code:
float updatealphaFreq(){
int af_update = 0;
if(p_count>0)
{
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
BCSCTL1= CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
ADC12CTL0 = SHT0_2 + ADC12ON; // Set sampling time, turn on ADC12
ADC12CTL1 = SHP + SHS0; // Use sampling timer
ADC12IE = 0x01; // Enable interrupt
ADC12CTL0 |= ENC; // Conversion enabled
P6DIR &= ~0x01; // P6.0, i/p
P6SEL |= 0x01; // P6.0-ADC option select
P1DIR |= 0x01; // P1.0 output-LED
//lcdInit();// Initialize LCD
//lcdSetText("Select Frequency ", 0, 0);
//lcdClear();
while(1){
//__enable_interrupt();
ADC12CTL0 |= ADC12SC ;
//delayMS(1000);
//lcdSetText("Value of a_freq: ", 0, 0);
float i = 0;
af_update = ADC12MEM0/100;
i = af_update *0.325;
//lcdSetInt(i*100, 0,1);
//delay_ms(10000);
//lcdSetText(" ", 0, 1);
}
ADC12CTL0 &=~ENC;
ADC12CTL0 &=~(REFON + ADC12ON);
ADC12CTL0 =0;
}
p_count = 0;
while((P1IN & BIT3)!=BIT3);
return af_update;
}
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
switch (P1IFG & BUTTON) {
case BUTTON:
P1IFG = P1IFG & ~BUTTON;
// flip the LED output
P1OUT ^= LED1;
P1OUT ^= LED2;
break;
default:
break;
}
return;
}
//Timer ISR
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A_CCR0_ISR(void)
{
OFCount++; //Increment Over-Flow Counter
}

Atmega328p only one ISR handled

I'm trying to run two functions 'similtaniously' via interrupts:
1) Measure ADC via timing of timer 0 (100Hz) and show results on pin 0-5
2) Blink a led via timer 1 (10Hz) on pin 6.
Problem seems to be that the ISR of timer 1 blocks the function, so nothing else is executed. Here is the code:
(Please don't be offended by any styling mistakes, the code is under development)
#define F_CPU 16000000UL // 16MHz Clock speed
#include <avr/io.h>
#include <avr/interrupt.h>
void ADC_init(void);
void SetTimer0(void);
void SetTimer1(void);
int main(void)
{
DDRB |= (1<<DDB0) + (1<<DDB1) + (1<<DDB2) + (1<<DDB3) + (1<<DDB4) + (1<<DDB5) + (1<<DDB6);
PORTB = 0b00000000;
DDRB &= ~(1<<DDB7);
ADC_init();
SetTimer0();
SetTimer1();
while(1){
}
}
void ADC_init(void)
{
cli();
// Select Vref=AVcc
// and set left adjust result
// select pin ADC0 (PC0)
ADMUX |= (1<<REFS0)|(1<<ADLAR);
//and enable ADC
//enable ADC interupt
//enable autotriggering
//set prescaller to 128
ADCSRA |= (1<<ADEN) | (1<<ADATE) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
//set ADC trigger source - Timer0 compare match A
ADCSRB |= (1<<ADTS1)|(1<<ADTS0);
// StartADC
ADCSRA |= (1<<ADSC);
sei();
}
//initialize timer0 match A on 100hz
void SetTimer0(void)
{
cli();
TCCR0A = 0; // set entire TCCR0A register to 0
TCCR0B = 0; // same for TCCR0B
TCNT0 = 0; // initialize counter value to 0
// set compare match register for 100Hz increments
OCR0A = 155; // = 16000000 / (1024 * 100.16025641025641)-1
// toggle PD6/OC0A pin on compare match
TCCR0A |=(1<<COM0A0)|(1<<WGM01);
//Set CTC mode
TCCR0B |= (1 << WGM01);
// Set CS02, CS01 and CS00 bits for 1024 prescaler
TCCR0B |= (1 << CS02) | (0 << CS01) | (1 << CS00);
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
sei();
}
//initialize timer1 10hz
void SetTimer1(void){
cli();
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
// set compare match register for 10 Hz increments
OCR1A = 24999; // = 16000000 / (64 * 10) - 1 (must be <65536)
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS12, CS11 and CS10 bits for 64 prescaler
TCCR1B |= (0 << CS12) | (1 << CS11) | (1 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei();
}
// ADC done interrupt
ISR(ADC_vect)
{
// Clear timer compare match flag
TIFR0=(1<<OCF0A);
// save ADC measurement
uint16_t val = ADC;
// show ADC results
if (val < 100)
{ PORTB = 0b00000000; }
else if (val < 300)
{ PORTB = 0b00000001; }
else if (val < 550)
{ PORTB = 0b00000011; }
else if (val < 850)
{ PORTB = 0b00000111; }
else if (val < 1020)
{ PORTB = 0b00001111; }
else
{ PORTB = 0b00011111; }
}
ISR(TIMER1_COMPA_vect)
{
//PORTB ^= PINB5;
static uint16_t on = 0;
if (on == 1){
PORTB = 0b00100000;
on = 0;
}
else {
PORTB = 0b00000000;
on = 1;
}
}
When the SetTimer1() function is disabled the DCA runs as expected. So individually are are both ISR's working fine, but together not. Could someone help me solve this problem?
You have output compare interrupt enabled fro Timer0:
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
but no ISR handler for that interrupt.
The default __bad_interrupt handler just performs jump to zero interrupt vector, i.e. restarts the program.
That means if you have an interrupt enabled there should be an ISR for that interrupt.

AVR Butterfly - Timer reuse after internal oscillator calibration

I am calibrating the AVR Butterfly internal oscillator for being able to use USART, based on the sample code provided by AVR (see code below). As I also wanted to use two timer-controlled servo motors, I am wondering whether it is possible to reuse 16-bit timer 1 after the calibration process - I tried resetting the TCCR1A/B but it did not work out (code also below). I hope you can help me out with this.
void OSCCAL_Calibrate(void){
unsigned char calibrate = 0;
int temp;
unsigned char tempL;
CLKPR = (1<<CLKPCE); // set Clock Prescaler Change Enable
// set prescaler = 8, Inter RC 8Mhz / 8 = 1Mhz
CLKPR = (1<<CLKPS1) | (1<<CLKPS0);
TIMSK2 = 0; //disable OCIE2A and TOIE2
ASSR = (1<<AS2); //select asynchronous operation of timer2 (32,768kHz)
OCR2A = 200; // set timer2 compare value
TIMSK0 = 0; // delete any interrupt sources
TCCR1B = (1<<CS10); // start timer1 with no prescaling
TCCR2A = (1<<CS20); // start timer2 with no prescaling
while((ASSR & 0x01) | (ASSR & 0x04)); //wait for TCN2UB and TCR2UB to be cleared
delayMs(1000); // wait for external crystal to stabilise
while(!calibrate)
{
cli(); // disable global interrupt
TIFR1 = 0xFF; // delete TIFR1 flags
TIFR2 = 0xFF; // delete TIFR2 flags
TCNT1H = 0; // clear timer1 counter
TCNT1L = 0;
TCNT2 = 0; // clear timer2 counter
while ( !(TIFR2 & (1<<OCF2A)) ); // wait for timer2 compareflag
TCCR1B = 0; // stop timer1
sei(); // enable global interrupt
if ( (TIFR1 & (1<<TOV1)) )
{
temp = 0xFFFF; // if timer1 overflows, set the temp to 0xFFFF
}else
{ // read out the timer1 counter value
tempL = TCNT1L;
temp = TCNT1H;
temp = (temp << 8);
temp += tempL;
}
if (temp > 6250)
OSCCAL--; // the internRC oscillator runs to fast, decrease the OSCCAL
else if (temp < 6120)
OSCCAL++; // the internRC oscillator runs to slow, increase the OSCCAL
else
calibrate = 1; // the interRC is correct
TCCR1B = (1<<CS10); // start timer1
}
}
void motorInit(){
// reset timer 1
TCCR1A = 0;
TCCR1B = 0;
// initialize Servo Pins
DDRB |= (1<<PB5) | (1<<PB6);
ICR1H = ICR_VALUE >> 8;
ICR1L = ICR_VALUE & (TOP_VALUE);
// reset OCRs
setServoSpeed(0, 0);
setServoSpeed(1, 0);
// Set Timer mode (PWM Phase & Freq. correct, clear on compare match)
// and prescaler (8)
TCCR1A = ((1<<COM1A1) | (1<<COM1B1));
TCCR1B = ((1<<WGM13) | (0<<CS12) | (1<<CS11) | (0<<CS10));
}
Maybe you can check code which I used for a project while ago, but you should take care that I decreased the system frequency to 7.3768 MHz for 56700 baudrate, which maybe you need to adjust.
void OSCCAL_Calibrate(void)
{
uint8_t LoopCount = (0x7F / 2);
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
// Make sure all clock division is turned off (8MHz RC clock)
CLKPR = (1 << CLKPCE);
CLKPR = 0x00;
// Inital OSCCAL of half its maximum
OSCCAL = (0x7F / 2);
// Disable timer interrupts
TIMSK1 = 0;
TIMSK2 = 0;
// Set timer 2 to asyncronous mode (32.768KHz crystal)
ASSR = (1 << AS2);
// Ensure timer 1 control register A is cleared
TCCR1A = 0;
// Start both counters with no prescaling
TCCR1B = (1 << CS10);
TCCR2A = (1 << CS20);
// Wait until timer 2's external 32.768KHz crystal is stable
while (ASSR & ((1 << TCN2UB) | (1 << TCR2UB) | (1 << OCR2UB)));
// Clear the timer values
TCNT1 = 0;
TCNT2 = 0;
while (LoopCount--)
{
// Wait until timer 2 overflows
while (!(TIFR2 & (1 << TOV2)));
// Stop timer 1 so it can be read
TCCR1B = 0x00;
// Check timer value against ideal constant
if (TCNT1 > OSCCAL_TARGETCOUNT) // Clock is running too fast
OSCCAL--;
else if (TCNT1 < OSCCAL_TARGETCOUNT) // Clock is running too slow
OSCCAL++;
// Clear timer 2 overflow flag
TIFR2 |= (1 << TOV2);
Check this out!

Resources