I have tried to implement TX only uart for ATTiny85 and receive the bits using arduino micro. (similiar question did not help since it is quite different to my situation)
My intend is to be able to print via attiny85 -> arduino -> console so I can debug the attiny85, since I don't have oscilloscope available.
attiny85 fuses are: "efuse:w:0xff:m -U hfuse:w:0xdf:m -U lfuse:w:0xf1:m" aka. 16MHz F_CPU
arduino also seems to have 16MHz F_CPU
Similiar to the mentioned question attiny85 sends bits via timer0 ISR one bit at time:
#ifndef F_CPU
#define F_CPU 16000000UL // 16 MHz
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define TX_PIN PB0
volatile uint16_t tx_shift_reg = 0;
ISR(TIMER0_COMPA_vect) {
uint16_t local_tx_shift_reg = tx_shift_reg;
if( local_tx_shift_reg & 0x01 ) {
PORTB |= _BV(TX_PIN);
} else {
PORTB &= ~_BV(TX_PIN);
}
local_tx_shift_reg >>= 1;
if(!local_tx_shift_reg) {
// Stop timer0.
GTCCR |= (1<<TSM) | (1<<PSR0);
}
tx_shift_reg = local_tx_shift_reg;
}
void UART_tx(char byte) {
uint16_t local_tx_shift_reg = tx_shift_reg;
local_tx_shift_reg = (0b1<<9) | ((uint16_t)byte<<1);
tx_shift_reg = local_tx_shift_reg;
TCNT0 = 0;
TCCR0B |= (1<<CS02)|(1<<CS00); // 1024 prescaler
GTCCR &= ~(1<<TSM);
}
void UART_tx_char(char c) {
UART_tx( c );
// wait until transmission is finished
while(tx_shift_reg);
}
void UART_init() {
cli()
// set TX pins as output
DDRB |= (1<<TX_PIN);
PORTB |= (1<<TX_PIN);
// set timer0 to CTC mode, keep it halted.
TCCR0A |= (1<<WGM01);
TCCR0B = 0;
// enable interrupt
TIMSK |= (1<<OCIE0A);
OCR0A = 128;
OCR0B = 128;
TCNT0 = 0;
GTCCR |= (1<<TSM);
sei();
}
void main(void)
{
UART_init();
while(1) {
for(char c = 1; c < 128; ++c) {
UART_tx_char(c);
_delay_ms(100);
}
}
}
Then arduino receives the bits:
/*
* ATtiny85 bit-bang uart monitor for ATmega32u4
*/
#define LED_PIN 13
#define RX_PIN 7
// rx_state == 0 // timer1 not running
// rx_state == 1 // receive in progress
// rx_state == 2 // data ready in rx_data_reg
volatile int rx_state = 0;
volatile int rx_bit_nro = 0;
volatile uint16_t rx_shift_reg = 0;
volatile uint16_t rx_data_reg = 0;
void rx_start_interupt() {
if(rx_state == 0) {
digitalWrite(LED_PIN, HIGH);
while(digitalRead(RX_PIN));
// Start timer1
rx_state++;
TCNT1 = 0;
TCCR1B = (1 << WGM12) | (1 <<CS12) | (1 << CS10);
}
}
ISR(TIMER1_COMPA_vect) {
uint16_t bit = digitalRead(RX_PIN) > 0;
rx_shift_reg >>= 1;
rx_shift_reg |= (bit << 7);
++rx_bit_nro;
if(rx_bit_nro == 9) {
// Stop timer.
TCCR1B = 0;
TCNT1 = 0;
rx_data_reg = rx_shift_reg;
rx_shift_reg = 0;
rx_bit_nro = 0;
rx_state++;
digitalWrite(LED_PIN, LOW);
}
}
void setup() {
noInterrupts();
// Program timer1 for UART bit bang receive.
TCCR1A = 0; // set entire TCCR1A register to 0 (stops it)
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
OCR1A = 128;
TIMSK1 |= (1 << OCIE1A);
interrupts();
pinMode(LED_PIN, OUTPUT);
pinMode(RX_PIN, INPUT);
// Attach RX start interupt.
pinMode(digitalPinToInterrupt(RX_PIN), INPUT);
attachInterrupt(digitalPinToInterrupt(RX_PIN), rx_start_interupt, FALLING);
Serial.begin(9600);
while(!Serial);
Serial.print("F_CPU:");
Serial.println(F_CPU,DEC);
Serial.println("Waiting for data from attiny85...");
}
void loop() {
if(rx_state == 2) {
uint16_t local_rx_data = rx_data_reg;
rx_state = 0;
Serial.println(local_rx_data,HEX);
}
}
I have tried pretty much everything to make it work, but received bytes come back garbace.
What am I missing?
Note: I'm using timer0 on attiny85 and timer1 on arduino.
Solved: switching ISR to TIMER1_COMPAB_vect and OCR1B = 64 actually works! Yay!
I recently ran into this issue of serial comms coming out as garbage on the other end. In my case, the ATtiny85 was sending bits to my laptop using an USB to TTL UART converter which had worked beautifully in other situations, but, I was just getting garbage in the Arduino IDE serial monitor.
I found a forum post which mentioned the possibility of calibrating OSCCAL.
I get a little bit fancier in my related blog post, but I tested the theory that I should calibrate OSCCAL using this code:
#include <SoftwareSerial.h>
SoftwareSerial comm(-1, 0);
static const int anchor = 128;
void
print_osccal(int v) {
comm.println(F("********************************"));
comm.print(F("OSCCAL = "));
comm.println(v);
comm.println(F("********************************"));
}
void
setup() {
delay(5000);
comm.begin(300);
OSCCAL = anchor;
print_osccal(anchor);
delay(5000);
}
void
loop() {
int x;
for (int i = 1; i < 128; ++i) {
x = anchor + i;
OSCCAL = x;
print_osccal(x);
delay(1000);
x = anchor - i;
OSCCAL = x;
print_osccal(x);
delay(1000);
}
}
It was a revelation seeing garbage all of a sudden transform to nicely formatted messages in the serial monitor (and, of course, back to garbage as the search is an infinite loop).
Now, the ATtiny85's internal oscillator can only support 1 MHz and 8 MHz. As I understand it, OSCCAL exists because this internal oscillator is 1) not very accurate and 2) is very sensitive the temperature.
If the ATtiny85 is set to run at 16MHz, it needs a reliable, external oscillator, and no amount of fiddling with OSCCAL might help. But, it did in my case allow me to discover the value(s) which made SoftwareSerial tick at 8 MHz and a range of baud rates from 300 to 38400.
This allowed me to get the right value for the bit banging UART to work with the 1MHz clock which is not supported by SoftwareSerial.
Related
I'm trying to create a 10 second delay using TIMER1(16 bit) in atmega328p, I don't know if the delay has been created or not because it takes longer duration than 10 seconds and expected output( which is to create pwm waves) is not obtained. Here I have created a 1second delay and looped it 10 times, TIMER0 is used for creating pwm waves.
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "interrupt.h"
#define SET_BIT(PORT,BIT) PORT |= (1<<BIT)
#define CLR_BIT(PORT,BIT) PORT &= ~(1<<BIT)
struct {
volatile unsigned int BIT: 1;
}
FLAG_TIMER;
void timer_configuration() //16 bit timer
{
TCCR1A = 0x00; // Normal mode of operation
TCNT1 = 0xC2F8;
TCCR1B |= ((1 << CS10) | (1 << CS12));
TCCR1B &= ~(1 << CS11); //101
sei(); // Global interrupt
}
void timer_on()
{
TIMSK1 |= (1 << TOIE1);
}
void pwm_configuration() //TIMER0 - 8 bit
{
TCCR0A |= ((1<<WGM00) | (1<<WGM01)); //setting it to fast PWM mode
TCCR0A |= (1<<COM0A1);
TCCR0A &= ~(1<<COM0A0);
TCNT0 = 0x00;
TCCR0B |= ((1<<CS00) | (1<<CS02)); //Prescaler setting 1024
TCCR0B &= ~(1<<CS01);
sei();
}
ISR(TIMER1_OVF_vect)
{
static unsigned int counter;
counter++;
if(counter >= 10)
{
FLAG_TIMER.BIT=1;
counter = 0;
TCNT1 = 0xC2F8;
TIMSK &= ~(1<< TOIE1);
}
else
{
FLAG_TIMER.BIT=0;
}
}
int main(void)
{
SET_BIT(DDRD,PD6); //CRO
timer_configuration();
pwm_configuration();
while(1)
{
timer_on();
if(FLAG_TIMER.BIT == 1)
{
OCR0A = 128; //50% dutycycle
}
}
You set the counter to 49912 on initialisation and increment your count when it overflows, but it will then start from 0, so if 15624 counts = 1 second, then your counter will increment to 10 after 15624 + 9 x 216 counts or about 38.75 seconds.
Move the TCNT1 = 0xC2F8; line in the ISR:
ISR(TIMER1_OVF_vect)
{
static unsigned int counter;
TCNT1 = 0xC2F8;
counter++;
if(counter >= 10)
{
FLAG_TIMER.BIT=1;
counter = 0;
TIMSK &= ~(1<< TOIE1);
}
else
{
FLAG_TIMER.BIT=0;
}
}
I am not familiar with ATmega, but I cannot believe that is an appropriate way to use the timer. Normally you'd up-count to a compare value with auto reset to zero, or down-count from an auto reload value to zero and let the hardware reload the counter.
I'm trying to blink a led using ISR for 3seconds, here atmega328p is used. I'm trying to create a 1second delay in isr using TIMER1(16 BIT) and then loop that for 3seconds. LED is connected to PD7, I don't know why it is not blinking, can anyone point out the mistake. I'm using simulIDE, here is the circuit,timer_circuit
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define SET_BIT(PORT,BIT) PORT |= (1<<BIT)
#define CLR_BIT(PORT,BIT) PORT &= ~(1<<BIT)
unsigned int count = 0;
void timer()
{
TCCR1A = 0x00; // Normal mode of operation
TCNT1 = 0xC2F8; // decimal value is 49912
TCCR1B |= ((1 << CS10) | (1 << CS12));
TCCR1B &= ~(1 << CS11); //1024 prescaler
sei(); // Global interrupt
}
int main(void)
{
SET_BIT(DDRD,PD7);
timer();
while(1)
{
TIMSK1 |= TOIE1;
if(count>=3)
{
SET_BIT(PORTD,PD7);
count=0;
}
}
;
return 0;
}
ISR(TIMER1_OVF_vect)
{
count++;
}
This code never turn off the LED ... once the bit is set your code never clear it ... try to toggle the bit instead of set it
#define toggle_BIT(PORT,BIT) PORT ^= (1<<BIT) //this will flip the bit
...
if(count>=3)
{
toggle_BIT(PORTD,PD7);
count=0;
TCNT1 = 0xC2F8; // reset counter
}
update
use volatile access modifier before count variable to tell the compiler that you will Chang it from ISR to make sure that count variable will not delete in optimization
when you set TCCR1B you have to set other bits to zero to operate in normal mode
Recalculate value TCNT1 for 8 MHz which is internal default frequency
full code
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define toggle_BIT(PORT,BIT) PORT ^= (1<<BIT) //this will flip the bit
#define SET_BIT(PORT,BIT) PORT |= (1<<BIT)
#define CLR_BIT(PORT,BIT) PORT &= ~(1<<BIT)
volatile unsigned int count = 0;
void timer()
{
TCCR1A = 0x00; // Normal mode of operation
TCNT1 = 64754; // over flow after 1 sec calculated at 8 MHZ
TCCR1B = ((1 << CS10) | (1 << CS12)); //1024 prescaler
TIMSK1 |= 1<<TOIE1; // Enable timer1 overflow interrupt
sei(); // Global interrupt
}
int main(void)
{
SET_BIT(DDRD,PD7);
timer();
while(1)
{
if(count>=3)
{
toggle_BIT(PORTD,PD7);
count=0;
}
}
return 0;
}
ISR(TIMER1_OVF_vect)
{
count++;
TCNT1 = 64754; // reset to over flow after 1 sec calculated at 8 MHZ
}
I've run into an issue using an ATmega32u4, where I am successfully able to use timer 1 overflows, but when I try to repurpose the code for timer 3, it doesn't function.
The following code turns an LED (on pin b7) on and off when timer 1 (16 bit) overflows. It works.
#include <avr/io.h>
#include <avr/interrupt.h>
int main (void) {
DDRB |= (1<<7);; //PortB Output
PORTB = 0x00; //PortB All LEDs off
TCCR1B |= (1<<CS10) | (1<<CS12); //Set Prescaler to 1024
TIMSK1 |= (1<<TOIE1); //Enable Timer Overflowinterrupt
sei(); //Enable Interrupts
while(1);
return 0;
}
ISR(TIMER1_OVF_vect)
{
PORTB ^= (1<<7); //toggle LED
}
This next code is intended to perform the same functionality using timer 3, but doesn't work.
#include <avr/io.h>
#include <avr/interrupt.h>
int main (void) {
DDRB |= (1<<7);; //PortB Output
PORTB = 0x00;
TCCR3B |= (1<<CS30) | (1<<CS32); //Set prescaler to 1024
TIMSK3 |= (1<<TOIE3); //Enable Timer Overflowinterrupt
sei(); //Enable Interrupts
while(1);
return 0;
}
ISR(TIMER3_OVF_vect)
{
PORTB ^= (1<<7);
}
This final code block was used to test that timer 3's count value was increasing (no interrupts involved), which it is. (I'm using a different LED in this test)
#include <avr/io.h>
int main()
{
// Prescaler of 1024
TCCR3B |= (1<<CS32)|(1<<CS30);
// Initialize Counter
TCNT3 = 0;
// Initialize LED
DDRE |= (1 << 6); // LED0
// Infinite Loop
while (1)
{
// Flash every 0.016 secs
// COUNTER = 0.016 / (PRE SCALER / CPU FREQ)
// 250
if( TCNT3 >= 250 )
{
// Toggle LED
PORTE ^= (1 << 6); // If output use PORT, If input use PIN
TCNT3 = 0;
}
}
return 0;
}
From this, I'm assuming that I'm doing something wrong when calling the interrupt, I'm just not sure what
I am not sure if you are using LilyPad or Leonardo.
I am assuming from the code above that it's LilyPad. Change the TCCR3B to 256 and see if it corrects the problem for you.
TCCR3B = 0x0C; // prescaler = 256
I used to write my codes in ICCAVR and I had no problem there, but not for some reason I should migrate to AtmelStudio.
in the following code, the LED is flashing in the interrupt, but when I only set a flag in the interrupt and want to flash the LED in polling (using the flag) it wouldn't work:
#include<avr/io.h>
#include<avr/interrupt.h>
#define LED PA1
ISR (TIMER1_OVF_vect) // Timer1 ISR
{
//PORTA ^= (1 << LED);
TCNT1 = 63974; // for 1 sec at 16 MHz
PORTA ^= (1 << LED);
}
int main()
{
DDRA = (0x01 << LED); //Configure the PORTD4 as output
TCNT1 = 63974; // for 1 sec at 16 MHz
TCCR1A = 0x00;
TCCR1B = (1<<CS10) | (1<<CS12);; // Timer mode with 1024 prescler
TIMSK = (1 << TOIE1) ; // Enable timer1 overflow interrupt(TOIE1)
sei(); // Enable global interrupts by setting global interrupt enable bit in SREG
while(1)
{
}
}
while this change would make it not to flash:
#include<avr/io.h>
#include<avr/interrupt.h>
#define LED PA1
unsigned int counter=0;
unsigned char flag=0;
ISR (TIMER1_OVF_vect) // Timer1 ISR
{
//PORTA ^= (1 << LED);
TCNT1 = 63974; // for 1 sec at 16 MHz
counter++;
if(counter>=10)
{
flag=1;
counter=0;
}
}
int main()
{
DDRA = (0x01 << LED); //Configure the PORTD4 as output
TCNT1 = 63974; // for 1 sec at 16 MHz
TCCR1A = 0x00;
TCCR1B = (1<<CS10) | (1<<CS12);; // Timer mode with 1024 prescler
TIMSK = (1 << TOIE1) ; // Enable timer1 overflow interrupt(TOIE1)
sei(); // Enable global interrupts by setting global interrupt enable bit in SREG
while(1)
{
if(flag)
{
flag=0;
PORTA ^= (1 << LED);
}
}
}
could anyone please help me?
Compiler saw that flag set to 0 at start of program and can't know that the variable can be changed by interrupt handler (the code never called directly in program).
So it optimized out flag check in while loop.
Use volatile qualifier for variables that accessed from different code streams (main code and interrupt handler, different threads in multi-threaded environment).
volatile unsigned char flag = 0;
I want to use ADXL345 in timer interrupt with Arduino mega.
But it can't not work.
Here is my code :
#include <Wire.h>
#define Register_ID 0
#define Register_2D 0x2D
#define Register_X0 0x32
#define Register_X1 0x33
#define Register_Y0 0x34
#define Register_Y1 0x35
#define Register_Z0 0x36
#define Register_Z1 0x37
int ADXAddress = 0xA7>>1;
int reading = 0;
int val = 0;
int X0,X1,X_out;
int Y0,Y1,Y_out;
int Z1,Z0,Z_out;
double Xg,Yg,Zg;
unsigned long t1, t2;
void setup()
{
Serial.begin(9600);
Wire.begin(); //初始化I2C
delay(100);
Wire.beginTransmission(ADXAddress);
Wire.write(Register_2D);
Wire.write(8);
Wire.endTransmission();
delay(500);
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 2500; // compare match register //250 = 1ms//500=2ms
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= (1 << CS10) + (1 << CS11); // 64 prescaler
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
interrupts(); // enable all interrupts
}
void loop()
{
Serial.println(Z_out);
delay(500);
}
ISR(TIMER1_COMPA_vect){
Wire.beginTransmission(ADXAddress);
Wire.write(Register_Z0);
Wire.write(Register_Z1);
Wire.endTransmission();
Wire.requestFrom(ADXAddress,2);
if(Wire.available()<=2);
{
Z0 = Wire.read();
Z1 = Wire.read();
Z1 = Z1<<8;
Z_out = Z0+Z1;
}
}
ISR() function executes every 1 millisecond, but the codes in ISR() only take 650 microseconds.
I don't know why it couldn't work.
If I do all things in the loop(), it can work normally.
Can any one help me?
Thanks in advance,
You shouldn'y handle I2C communications in the ISR. Try using the timer interrupt to change the value of a flag. Check that flag in the main loop and read the value.
You cannot use the Wire library inside an ISR, as interrupts have been disabled. The Wire library uses interrupts.