Arduino interrupt output compare register not working as expected - arduino

I am trying to use interrupts to toggle a pin with Arduino Uno. This is what I have so far:
const int outputPin = 12;
void setup() {
pinMode(outputPin, OUTPUT);
// initialize Timer0
noInterrupts(); // disable all interrupts
TCCR0A = 0;
TCCR0B = 0;
TCNT0 = 0;
OCR0A = 255;
TCCR0B |= (1 << WGM12); // CTC mode
TCCR0B |= (1 << CS12);
TCCR0B |= (1 << CS10); // 1024 prescaler
TIMSK0 |= (1 << OCIE1A); // enable timer compare interrupt
interrupts(); // enable all interrupts
}
ISR(TIMER0_COMPA_vect){
digitalWrite(outputPin,digitalRead(outputPin)^1); //Toggle pin
}
I am using an oscilloscope to read the voltage on the pin and when I change the value of OCR0A there is no change. I am not sure why nothing is changing. I would like to also add that there are no errors.
Thank you for your help!

First, You mix TIMER0 ports and TIMER1 bits constants, use WGM0x, CS0x and so on. You try to set CTC mode like TIMER1. For TIMER0 set bit WGM01 of TCCR0A port:
TCCR0A = 1 << WGM01;
TCCR0B = 1 << CS02 | 1 << CS00;
OCR0A = <Max counter value>;
TIMSK0 |= 1 << OCIE0A;

Related

ATMEGA328P Arduino Uno: Adjusting the brightness of LED with AVR Programming

int led_pin = 9;
int duty_cycle = 63; //in %
int freq_OC = 16000; //in Hz
int freq_clk = 16000000; //in Hz
int prescaler = 1;
void setup() {
//setting the port B pin (D9) as output for OC1A to override the normal port functionality
DDRB = DDRB|(1 << led_pin);
//clearing the counter/timer registers
TCCR1A = 0;
TCCR1B = 0;
//setting the prescaler 1
TCCR1B = TCCR1B|(1 << CS10);
//setting the mode 14 fast PWM
TCCR1B = TCCR1B|((1 << WGM13)|(1 << WGM12));
TCCR1A = TCCR1A|(1 << WGM11);
//setting the fast PWM in non-inverting mode
TCCR1A = TCCR1A|(1 << COM1A1);
ICR1 = (freq_clk/(freq_OC*prescaler)) - 1;
OCR1A = ICR1/(100/duty_cycle);
}
void loop() {
}
Why doesn't this code work when pin D9 is initialised as an output pin OC1A as written above? But it works when...
DDRB = DDRB|(1 << PB1);
Is there any reason for this? As far as the datasheet for ATMEGA328P is concerned, it quotes "If one or both of the COM1X1:0 bits are written to one, the OC1X overrides the normal port functionality of the I/O pin it is connected to". So does that mean the PB1 (or D9) pin no longer functions as an I/O pin and therefore I cannot initialise it with a variable name?
DDRB is an 8-bit register, it has no 9th bit in it.
You have led_pin variable set to 9, therefore operation DDRB = DDRB|(1 << led_pin) has no effect.
There is no D9 pin on the ATmega328P. But looks like you're talking about Arduino board. You can google "Arduino UNO Pinout". E.g. this
You can see D9 pin of the board is connected to PB1 pin of the MCU. Therefore you have to use DDRB |= (1 << 1) (use value 1, not 9)

Using All Interrupt Vector Of A Timer

Purpose
I'm doing some timer experiment on atmega328.
I'm attempting to use every interrupt (except OVF).
Trying to make timer1 act likes 3 individual timers.
This might comes in handy when ran out of timer.
According to manual,there are 4 interrupt vectors related to timer1.
Timer1 Interrupt Vectors
My idea is making TCNT1 keep counting from 0 to 65535.
Then set the desired compare value in OCR1A,OCR1B and ICR1 registers.
When interrupts, manually add value to registers, so next interrupt will be trigger in same duration.
I wrote some codes to verify and the result seems to be ideal.
I'm considering that is this a proper way to use a timer?
or this may cause some bugs,error or efficiency issue?
Thanks!
Codes
int A_Ticks = 15624; //64us*(15624+1) = 1000ms
int B_Ticks = 23436; //1500ms
int ICR_Ticks = 31248; //2000ms
void setup()
{
Serial.begin(115200);
TCCR1A = 0x00;
TCCR1B = 0x00;
TCCR1B|= _BV(WGM13); //enable TIMER1_CAPT_vect
TCCR1B|= _BV(WGM12); //enable CTC
TCCR1B |= _BV(CS12); //prescaler = CPU clock/1024
TCCR1B &= ~_BV(CS11); //per tick = 64us
TCCR1B |= _BV(CS10);
OCR1A = A_Ticks;
OCR1B = B_Ticks;
ICR1 = ICR_Ticks;
char oldSREG = SREG;
noInterrupts();
TIMSK1 |= _BV(OCIE1A); // enable timer interrupt
TIMSK1 |= _BV(OCIE1B);
TIMSK1 |= _BV(ICIE1);
TIMSK1 |= _BV(TOIE1);
TCNT1=0;
SREG = oldSREG;
}
void loop()
{
delay(100);
}
ISR (TIMER1_COMPA_vect)
{
Serial.print(millis());
Serial.println(":COMPA");
OCR1A+=A_Ticks; //add value manually
}
ISR (TIMER1_COMPB_vect)
{
Serial.print(millis());
Serial.println(":COMPB");
OCR1B+=B_Ticks; //add value manually
}
ISR (TIMER1_OVF_vect)
{
Serial.print(millis());
Serial.println(":OVF_vect");
}
ISR (TIMER1_CAPT_vect)
{
//When interrupt into TIMER1_CAPT_vect
//TCNT will be clear to 0 due to CTC is on
//manually set it to value of ICR1 to make TCNT keep counting
TCNT1=ICR1;
ICR1+=ICR_Ticks; //add value manually
Serial.print(millis());
Serial.println(":CAPT_vect");
}
Result
999:COMPA
1499:COMPB
1999:CAPT_vect
1999:COMPA
2999:COMPA
2999:COMPB
3999:CAPT_vect
3999:COMPA
4194:OVF_vect
4499:COMPB
4999:COMPA
5999:CAPT_vect
5999:COMPA
5999:COMPB
6999:COMPA
7498:COMPB
7999:CAPT_vect
7999:COMPA
8388:OVF_vect

UART Receiving keyboard input doesn't work

I am having trouble with reading data sent from my laptop to the microcontroller via UART. The transmitting part works fine - I can send data to my laptop without problems, but echoing data, or reading keyboard input data from the laptop doesn't work. I have tried to implement reading both with polling and with Rx interrupt routines, but without success. The microcontroller I am using is ATMEGA2560, and I am conntected to my laptop via FTD1232 USB to TTL serial converter.
I am using Putty as a serial comm terminal, and the Arduino IDE for programming.
I am assuming that the problem is not in the hardware based on the following - I have tried initializing different USARTs and tried to use different COM ports, as well as another USB to TTL converter, various wires, but the result is the same. I have also connected another power source to supply enough voltage to all devices.
I am trying to get at least a response by turning a LED on when Rx interrupt occurs (when I type something in the terminal).
~
#define F_CPU 16000000UL //16MHz
#define BAUD 115200UL //bps
#define BAUD_PRESCALER (((F_CPU/(BAUD*8UL)))-1) //Table 101, page 212
volatile uint8_t temp;
void UART_init(){
//Set baud rate
UBRR0H = (uint8_t)(BAUD_PRESCALER >> 8); //Higher portion of the baud rate
UBRR0L = (uint8_t)BAUD_PRESCALER; //Lower portion of the baud rate
//Enable Receiver and Transmitter
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
//Set frame format: 8-bit format, 1 stop bit, no parity
UCSR0C |= (3 << UCSZ00);
UCSR0C &= ~(1 << USBS0); //clear for 1 stop bit
//Set Double Speed Asynchronous mode
UCSR0A |= (1 << U2X0);
UCSR0B |= (1 << RXCIE0); //Enables interrupt rxc
}
uint8_t UART_getchar(){
//Wait for RXC flag
while(!(UCSR0A & (1 << RXC0))){};
return UDR0;
}
//Arduino setup()
void setup(){
pinMode(8, OUTPUT);
UART_init();
sei();
}
//Arduino loop()
void loop(){
delay(500);
UART_putchar('a');
}
ISR(USART0_RX_vect){
temp = UDR0;
digitalWrite(8, HIGH);
}
It is a lenghty post, but I tried to be specific and also post the whole code. The datasheet I am using for the ATMEGA2560 can be found here.
My Putty settings:
COM Port Settings
I've just tested it on my Mega board and it's working fine without interrupts enabled (simple loopback):
#define BAUD 115200UL
#define BAUD_PRESCALER (((F_CPU/(BAUD*8UL)))-1)
volatile uint8_t temp;
void UART_init(){
//Set baud rate
UBRR0H = (uint8_t)(BAUD_PRESCALER >> 8); //Higher portion of the baud rate
UBRR0L = (uint8_t)BAUD_PRESCALER; //Lower portion of the baud rate
//Enable Receiver and Transmitter
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
//Set frame format: 8-bit format, 1 stop bit, no parity
UCSR0C |= (3 << UCSZ00);
UCSR0C &= ~(1 << USBS0); //clear for 1 stop bit
//Set Double Speed Asynchronous mode
UCSR0A |= (1 << U2X0);
// UCSR0B |= (1 << RXCIE0); //Enables interrupt rxc
}
uint8_t UART_getchar(){
//Wait for RXC flag
while(!(UCSR0A & (1 << RXC0))){};
return UDR0;
}
void UART_putchar(uint8_t data){
//Do nothing until UDR is ready
while(!(UCSR0A &(1 << UDRE0))){};
UDR0 = data;
}
void UART_putstring(uint8_t *data){
while(*data != 0x00){
UART_putchar(*data);
data++;
}
}
//Arduino setup()
void setup(){
pinMode(8, OUTPUT);
UART_init();
sei();
}
//Arduino loop()
void loop(){
UART_putchar(UART_getchar());
}
/*ISR(USART0_RX_vect){
temp = UDR0;
digitalWrite(8, HIGH);
}*/
RX interrupt must be disabled, otherwise Serial interrupt vector is taking place and polled get char can't work as characters are readed by ISR

Using AVR on Arduino, trying to get pin7 to flash on and off

I'm trying to get this to toggle pin 7 on and off but I'm having some issues. What's the correct way to do this? I'm fairly certain my issue is in the toggleLED function between the two "state" lines.
#include <avr/io.h>
int state = 1;
char ticks = 0;
void toggleLED(void);
int main(void) {
DDRB = (1 << PD7); // set pin 7 to output
TIMSK0 = 0; // no interrupts
TCCR0B = 5; // divide clock by 1024
PORTB = (1<<PD7);
while(1) {
while((TIFR0 & 0x01) == 0) {} // loop until flag is set
TIFR0 = 1; // clear the flag
ticks++;
if(ticks == 1) {
ticks = 0;
toggleLED();
}
}
}
void toggleLED(void) {
if(state == 1) {
PORTB = 1;
state = 0;
} else {
PORTB = 0;
state = 1;
}
}
Your main function sets PB7. Your toggleLED function toggles PB0. Pin 7 is probably something else, we would need to know which hardware this running on to tell what pin 7 is.
How about this?
#include <avr/io.h>
ISR (TIMER0_COMPA_vect)
{
PIND = (1 << PIND7); // toggle D7
}
int main(void)
{
DDRD = (1 << PORTD7); // set pin D7 to output
TCCR0A = 0;
TCCR0B = (1 << CS00) | (1 << CS02); // prescaler of 1024
TIMSK0 = (1 << OCIE0A); // Timer/Counter0 Output Compare Match A Interrupt Enable
OCR0A = 249; // count up to 250
sei (); // want interrupts now
while (true) ; // all done!
}
That toggles pin 7 at a rate of 62.5 Hz. (ie. the frequency is 31.25 Hz, which is visible).
Theory:
16e6 / 1024 / 250 = 62.5 Hz
Or let the hardware do it for you:
#include <avr/io.h>
int main(void)
{
DDRD = (1 << PORTD6); // set pin 6 to output
TCCR0A = (1 << COM0A0); // toggle OC0A on compare match
TCCR0B = (1 << CS00) | (1 << CS02); // prescaler of 1024
OCR0A = 249; // count up to 250
}
Note that this is now on pin D6 (pin 12 on the chip) because it is using a hardware timer output.

Controlling MSP430 PWM with a Laptop

I have written a code which takes two digit number from laptop and changes the PWM dutycycle to that number. It is part of a bigger requirement where I need to control motor speed over UART.
#include "io430g2553.h"
#include <stdint.h>
void PWM(uint8_t duty_cycle);
void PWM_Config();
int main( void )
{
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
WDTCTL = WDTPW + WDTHOLD;
BCSCTL1 = CALBC1_1MHZ; // Run at 1 MHz
DCOCTL = CALDCO_1MHZ; // Run at 1 MHz
PWM_Config();
PWM(5);
__delay_cycles(5000000);
PWM(15);
__delay_cycles(5000000);
PWM(25);
__delay_cycles(5000000);
PWM(50);
__delay_cycles(5000000);
PWM(25);
__delay_cycles(5000000);
PWM(15);
__delay_cycles(5000000);
PWM(5);
while(1)
{}
}
void PWM_Config()
{
P1OUT &= 0x00; // Clearing P1OUT
P1SEL |= BIT6 ;
P1SEL2 &= ~BIT6 ;
P1DIR |= BIT6; // Configuring P1.6 as Output
}
void PWM(uint8_t duty_cycle)
{
TA0CTL =0;
TA0CTL |= TACLR;
TA0CCR1 |= (duty_cycle*100);
TA0CCR0 |= 10000;
TA0CTL |= TASSEL_2 + MC_1 + ID_0;// Register TA0CTL -> SMCLK/8, Up mode
TA0CCTL1 |= OUTMOD_7 ;//Set/Reset Mode
TA0CCTL0 &= ~CCIE; // Interrupt Disabled}
The problem with the void PWM(uint8_t duty_cycle) function is that first time it generates the correct PWM at P1.6, next if it is given a value it changes PWM to that DC, but I can not go back to lower DC.
the fisrt 2 PWM functions in the code changes to correct duty cycle PWM(5),PWM(15) then the rest of PWM values do not produce desired dutycycle.
I am not able to troubleshoot where am I wrong, can any1 help?
Thanks
Seems like a stupid mistake on my part..
TA0CCR1 |= (duty_cycle*100);
instead of
TA0CCR1 = (duty_cycle*100);

Resources