Attiny 84 Communicating with RTC Through SPI Troubles - spi

I am currently trying to use an ATtiny84 to communicate with an RTC (DS1305) through SPI to make an buzzer vibrate every variable amount of time. I've been trying to set alarm0 on the DS1305. However, the 84 does not "technically" have SPI. It has USI which can be programmed to be like SPI. I was wondering if any of you could review my code/ board connections and let me know if you see any problems. The current problem is that I cannot get any communication going through SPI and I am having trouble finding what the issue could be.
Current board connections:
ATtiny84 | DS1305
MOSI ------ DI
MISO ------ DO
USCLK ---- CLK
Datasheets:
Attiny84
DS1305
/*
* Atmel_Jolt_Code.c
*
* Created: 11/28/2018 10:44:30 PM
* Author : Nick Hulsey
*/
#include <avr/io.h>
#define F_CPU 16000000UL
#include <avr/interrupt.h>
#include <util/delay.h>
//variables for SPI
#define SPI_DDR_PORT DDRA
#define CE_PIN DDA3 //I ADDED *****
#define DO_DD_PIN DDA5 // SHOULD WE
#define DI_DD_PIN DDA6 // THEM FLIP
#define USCK_DD_PIN DDA4
#define SPI_MODE0 0x00
#define SPI_MODE1 0x04
#define MOTOR_PIN DDA7 //I ADDED *****
void SPI_begin();
void setDataMode(uint8_t spiDataMode);
uint8_t transfer(uint8_t spiData);
void flipLatch(uint8_t on);
int main(void)
{
SPI_begin();
setDataMode(SPI_MODE1);
DDRA |= (1 << MOTOR_PIN);
//**startup**
uint8_t status_register = 0x10;
uint8_t control_register = 0x8F;
uint8_t control_byte = 0x05;
uint8_t alarm_registers[] = {0x8A, 0x89, 0x88, 0x87};
//set control
flipLatch(1);
transfer(control_register);
transfer(0);
flipLatch(0);
flipLatch(1);
transfer(control_register);
transfer(control_byte);
flipLatch(0);
//set alarm:
for (int i = 0; i < 4; i++){
flipLatch(1);
transfer(alarm_registers[i]);
transfer(0x80); //0b10000000
flipLatch(0);
}
//THIS MIGHT NEED WORK
//GIMSK |= (1 << PCIE1);//set external interrupt (A1)
PCMSK0 |= (1 << PCINT1);
sei();
while (1) //our main loop
{
//reading the flag from the status register
uint8_t status = transfer(status_register);
if(status == 0x01){//if alarm 0 has been flagged
PORTA ^= (1 << MOTOR_PIN);
_delay_ms(100);
}
}
}
//if A1 has changed state at all this function will fire
ISR(PCINT1_vect){
PORTA ^= (1 << MOTOR_PIN);//invert motor power
_delay_ms(100);
}
void SPI_begin(){
USICR &= ~((1 << USISIE) | (1 << USIOIE) | (1 << USIWM0));//Turn off these bits
USICR |= (1 << USIWM0) | (1 << USICS1) | (1 << USICLK);//Turn on these bits
//REVIEW THIS PAGE 128
//external,positive edge software clock
//What does this mean
SPI_DDR_PORT |= 1 << USCK_DD_PIN; // set the USCK pin as output
SPI_DDR_PORT |= 1 << DO_DD_PIN; // set the DO pin as output
SPI_DDR_PORT |= 1 << CE_PIN;// ******** I ADDED
SPI_DDR_PORT &= ~(1 << DI_DD_PIN); // set the DI pin as input
}
void setDataMode(uint8_t spiDataMode)
{
if (spiDataMode == SPI_MODE1)
USICR |= (1 << USICS0);
else
USICR &= (1 << USICS0);
}
//returns values returned from the IC
uint8_t transfer(uint8_t spiData)
{
USIDR = spiData;
USISR = (1 << USIOIF); // clear counter and counter overflow interrupt flag
//ATOMIC_BLOCK(ATOMIC_RESTORESTATE) // ensure a consistent clock period
//{
while ( !(USISR & (1 << USIOIF)) ) USICR |= (1 << USITC);
//}
return USIDR;
}
void flipLatch(uint8_t on){
if (on == 1)
PORTA |= (1 << CE_PIN);
else
PORTA &= ~(1 << CE_PIN);
}

Related

Reading a non-null terminated input at serial?

I am working with mbed, the LPC1768. The serial input to the mbed is a unsigned character array which is not null-terminated. I don't get anything with getc(), how to get the input?
the null character is 0 so if you need get it u can using a Buffer Counter or a ovf variable to detect received a character!!
Config your UART0,1 by this Setting:
comment UART0 or UART1 if not use it!
so u can select UARTs with #define in: option->C/C++->Define:__UART0 or __UART1
void SER_Init (void) {
#ifdef __UART0 /* UART0 */
LPC_SC->PCONP |= ((1 << 3) | (1 << 15)); /* enable power to UART0 & IOCON */
LPC_PINCON->PINSEL0 |= (1 << 4); /* Pin P0.2 used as TXD0 */
LPC_PINCON->PINSEL0 |= (1 << 6); /* Pin P0.3 used as RXD0 */
#else /* UART1 */
LPC_SC->PCONP |= ((1 << 4) | (1 << 15)); /* enable power to UART1 & IOCON */
LPC_PINCON->PINSEL4 |= (2 << 0); /* Pin P2.0 used as TXD1 */
LPC_PINCON->PINSEL4 |= (2 << 2); /* Pin P2.1 used as RXD1 */
#endif
UART->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */
UART->DLL = 9; /* 115200 Baud Rate # 25.0 MHZ PCLK*/
UART->FDR = 0x21; /* FR 1,507, DIVADDVAL=1, MULVAL=2 */
UART->DLM = 0; /* High divisor latch = 0 */
UART->LCR = 0x03; /* DLAB = 0 */
}
------> and use this func. for Get Character:
/*----------------------------------------------------------------------------
Read character from Serial Port (blocking read)
*----------------------------------------------------------------------------*/
int SER_GetChar (void) {
while (!(UART0->LSR & 0x01));
return (UART0->RBR);
}

Why am I only getting 0xFF when reading from the LIS3DSH accelerometer on the STM32F407G-Disc1 MCU?

So I'm learning embedded development, and I recently learned the basics of SPI. As a project, I wanted to communicate with the LIS3DSH accelerometer on my STM32F407G-DISC1 board using only the CMSIS headers.
I pasted the entire code below, but I'll explain it first because no one wants to read all that code.
As a reference, these are the pins needed (according to the MCU's datasheet) to communicate via SPI:
PA5 - SPI1_SCK
PA7 - SPI1_MOSI
PA6 - SPI1_MISO
PE3 - CS_I2C/SPI
Here's the steps I took in my code:
Enabled the clock for GPIOA and GPIOE using the AHB1ENR register.
For GPIOA, I set the three pins as alternate function, output is push-pull, speed is low, no pull-up/pull-down, and configured the alternate function as SPI.
For GPIOE, set it as GPIO mode, push-pull, low speed, pull-up, and then set it high (as in wrote to the BSSR register).
Enabled the clock for SPI using the APB2ENR register.
Configured SPI1: first disabled it, enabled 2-line unidirectional mode, set baud rate to fPCL/16 since the APB2 peripheral clock is 84MHz and the max clock of the accelerometer is 10MHz. Then set clock phase and polarity to 1. 8-bit data frame, MSB first, enabled software slave management, and also enabled master configuration. Finally, enabled SPI1.
After all this, I transmit 0x63 to the 0x20 register of the accelerometer. This sets the output rate to 100Hz and enables both the x and y axis. I have no idea if this is actually working. I'm assuming it is because the TX buffer is empty when I check the SPI status register.
Then to test whether I can recieve, I attempt to get the data from the WHO_AM_I register of the accelerometer. But I only see garbage data when I debug it (0xFF).
I've googled around to see why this may be, and a lot of people suggested that the clock polarity and phase may be incorrect. However, I've checked it multiple times, and I'm fairly certain I configured it properly.
I've tried setting interrupts. During the interrupt, even though RXNE (RX buffer not empty) is true, it still reads only 0xFF. I'm stumped as to why this is happening.
The code is below. The starting point is accelerometer_init(). The reading of the data from the WHO_AM_I register is in turn_on_accelerometer().
#include <stdint.h>
#include <stdbool.h>
#include "stm32f4xx.h"
#include "accelerometer.h"
static void gpio_clock_enable(void);
static void gpio_a_init(void);
static void gpio_e_init(void);
static void accelerometer_clock_enable(void);
static void configure_accelerometer(void);
static void pull_slave_high(void);
static void pull_slave_low(void);
static void turn_on_accelerometer(void);
static void wait_till_transmit_complete(void);
static void transmit_only(uint8_t address, uint8_t data);
static void receive_dummy_data(void);
void accelerometer_init(void) {
gpio_clock_enable();
gpio_a_init();
gpio_e_init();
accelerometer_clock_enable();
configure_accelerometer();
turn_on_accelerometer();
}
void gpio_clock_enable(void) {
RCC_TypeDef *rcc = RCC;
rcc->AHB1ENR |= (1 << 0) | (1 << 4);
}
void gpio_a_init(void) {
GPIO_TypeDef *gpio_a = GPIOA;
// Reset mode and set as alternate function
gpio_a->MODER &= ~(0x3 << 10) & ~(0x3 << 12) & ~(0x3 << 14);
gpio_a->MODER |= (0x2 << 10) | (0x2 << 12) | (0x2 << 14);
// Set output to PP
gpio_a->OTYPER &= ~(1 << 5) & ~(1 << 6) & ~(1 << 7);
// Set speed to low
gpio_a->OSPEEDR &= ~(0x3 << 10) & ~(0x3 << 12) & ~(0x3 << 14);
// Set to no pull-up / pull-down
gpio_a->PUPDR &= ~(0x3 << 10) & ~(0x3 << 12) & ~(0x3 << 14);
// Reset alternate function and set to SPI
gpio_a->AFR[0] &= ~(0xF << 20) & ~(0xF << 24) & ~(0xF << 28);
gpio_a->AFR[0] |= (0x5 << 20) | (0x5 << 24) | (0x5 << 28);
}
void gpio_e_init(void) {
GPIO_TypeDef *gpio_e = GPIOE;
// Set as general purpose output mode
gpio_e->MODER &= ~(0x3 << 6);
gpio_e->MODER |= (1 << 6);
// Set as push pull
gpio_e->OTYPER &= ~(1 << 3);
// Set as low speed
gpio_e->OSPEEDR &= ~(0x3 << 6);
// Set to pull up
gpio_e->PUPDR &= ~(0x3 << 6);
gpio_e->PUPDR |= (1 << 6);
// Set it high
pull_slave_high();
}
void accelerometer_clock_enable(void) {
RCC_TypeDef *rcc = RCC;
rcc->APB2ENR |= (1 << 12);
}
void configure_accelerometer(void) {
SPI_TypeDef *spi_1 = SPI1;
// First disable it while we configure SPI
spi_1->CR1 &= ~(1 << 6);
// 2-line unidirectional data mode enabled
spi_1->CR1 &= ~(1 << 15);
// Reset baud rate and set to fPCLK/16
// because APB2 peripheral clock currently is 84 MHz
// and the max clock of the accelerometer is 10 MHz.
spi_1->CR1 &= ~(0x7 << 3);
spi_1->CR1 |= (0x3 << 3);
// Set clock phase to 1
spi_1->CR1 |= (1 << 0);
// Set clock polarity to 1
spi_1->CR1 |= (1 << 1);
// 8 bit data frame format
spi_1->CR1 &= ~(1 << 11);
// MSB first
spi_1->CR1 &= ~(1 << 7);
// Software slave management enabled
spi_1->CR1 |= (1 << 9);
spi_1->CR1 |= (1 << 8);
// Master configuration enabled
spi_1->CR1 |= (1 << 2);
// SS output enabled
// spi_1->CR2 |= (1 << 2);
// Enable SPI
spi_1->CR1 |= (1 << 6);
// Wait a little bit for accelerometer to turn on
for (int i=0; i<1000000; i++);
}
void pull_slave_high(void) {
// Wait until SPI is no longer busy
SPI_TypeDef *spi_1 = SPI1;
while ((spi_1->SR >> 7) & 1);
GPIO_TypeDef *gpio_e = GPIOE;
gpio_e->BSRR |= (1 << 19);
}
void pull_slave_low(void) {
// Wait until SPI is no longer busy
SPI_TypeDef *spi_1 = SPI1;
while ((spi_1->SR >> 7) & 1);
GPIO_TypeDef *gpio_e = GPIOE;
gpio_e->BSRR |= (1 << 3);
}
void turn_on_accelerometer(void) {
// Set output data rate to 100Hz
// and enable X-axis, Y-axis.
transmit_only(0x20, 0x63);
receive_dummy_data();
// Temp test checking the WHO_AM_I register on the accelerometer.
SPI_TypeDef *spi_1 = SPI1;
pull_slave_low();
wait_till_transmit_complete();
uint8_t address = 0x0F | 0x80;
spi_1->DR = address;
wait_till_transmit_complete();
while (true) {
volatile bool is_busy = (spi_1->SR >> 7) & 1;
volatile bool is_rx_buffer_not_empty = (spi_1->SR >> 0) & 1;
if (!is_busy && is_rx_buffer_not_empty) {
break;
}
}
volatile uint32_t data = spi_1->DR;
pull_slave_high();
}
/*
* Transmit is synchronous.
*/
void transmit_only(uint8_t address, uint8_t data) {
SPI_TypeDef *spi_1 = SPI1;
// Select the accelerometer as the slave
pull_slave_low();
// Wait till transmit buffer is ready
wait_till_transmit_complete();
spi_1->DR = address;
// Wait till transmit buffer is ready
wait_till_transmit_complete();
spi_1->DR = data;
// Wait till transmit buffer has been read
wait_till_transmit_complete();
// Deselect the slave
pull_slave_high();
}
void wait_till_transmit_complete(void) {
SPI_TypeDef *spi_1 = SPI1;
while (true) {
volatile bool is_busy = (spi_1->SR >> 7) & 1;
volatile bool is_transmit_buffer_empty = (spi_1->SR >> 1) & 1;
if (!is_busy && is_transmit_buffer_empty) {
break;
}
}
}
void receive_dummy_data(void) {
SPI_TypeDef *spi_1 = SPI1;
spi_1->DR;
spi_1->SR;
}
You are working with SPI incorrectly.
This bus works in this way:
master (MCU) sends byte in MOSI
line at the same (!) time slave (LIS) sends byte in MISO line. In this moment slave dont know, what exactly byte master transfers to it.
To transfer one byte, you should:
write byte in data register
wait for completition of transfer
read data register
Thus, to read WHO_AM_I register, we obtain next sequence:
init SPI
flush data register (just read SPI->DR)
send command
wait
read dummy data (your 0xFF)
write second byte (0x00 or 0xFF, it doesn't matter)
wait
read correct answer from LIS

Delayed uart command execution

I'm writing a small embedded program, where I send some commands over uart to the atmega328p chip. The commands start with the character $ and end with the character # (so I know when to perform the parsing). Upon receiving the command I parse it and turn the device on (COMMAND:TURN_ON_I1) or off (COMMAND:TURN_OFF_I1). The application currently looks like this:
// ------- Defines -------- //
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/power.h>
#include <stdio.h>
#include <string.h>
#include "pinDefines.h"
#include "USART.h"
#define RECEIVE_BUFFER_SIZE 100
// Control output value
#define output_low(port,pin) port &= ~(1<<pin)
#define output_high(port,pin) port |= (1<<pin)
// Set pin mode (input or output)
#define set_input(portdir,pin) portdir &= ~(1<<pin)
#define set_output(portdir,pin) portdir |= (1<<pin)
// The DDRD port contains only two pins:
#define REL_BTN_SIM_2 PD6 // PD6 = REL_BTN_SIM_2
void initUSART(void) { /* requires BAUD */
UBRR0H = UBRRH_VALUE; /* defined in setbaud.h */
UBRR0L = UBRRL_VALUE;
#if USE_2X
UCSR0A |= (1 << U2X0);
#else
UCSR0A &= ~(1 << U2X0);
#endif
/* Enable USART transmitter/receiver */
UCSR0B = (1 << TXEN0) | (1 << RXEN0);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); /* 8 data bits, 1 stop bit */
}
void printString(const char myString[]) {
uint8_t i = 0;
while (myString[i]) {
transmitByte(myString[i]);
i++;
}
}
uint8_t receiveByte(void) {
loop_until_bit_is_set(UCSR0A, RXC0); /* Wait for incoming data */
return UDR0; /* return register value */
}
void transmitByte(uint8_t data) {
/* Wait for empty transmit buffer */
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = data; /* send data */
}
int main(void) {
//$COMMAND:TURN_ON_I1#
//$COMMAND:TURN_OFF_I1#
char s[RECEIVE_BUFFER_SIZE];
char readSerialCharacter;
// -------- Inits --------- //
DDRB = 0b00000111;
DDRC = 0b00001000;
DDRD = 0b11000000;
initUSART();
// ------ Event loop ------ //
while (1) {
printString("Waiting for the start of string (char $).\r\n");
do { } while ( receiveByte() != '$'); // Wait for start of string.
// Fill the array until the end of transmission is received
int i=0;
do {
// If nearing end of buffer, don't fill the buffer and exit the loop
if(i<RECEIVE_BUFFER_SIZE-1){
readSerialCharacter = receiveByte();
s[i++] = readSerialCharacter;
}else
break;
} while (readSerialCharacter != '#'); // Wait for end of string.
s[i] ='\0'; // Terminate the string
printString("The whole received command:\r\n");
printString(s);
printString("\r\n");
// Other commands (temperature, relay control)
// REL_BTN_SIM_2
else if(strstr(s, "COMMAND:TURN_ON_I1") != NULL)
{
printString("Will set I1 on!");
output_high(PORTD, REL_BTN_SIM_2);
}
else if(strstr(s, "COMMAND:TURN_OFF_I1") != NULL)
{
printString("Will set I1 off!");
output_low(PORTD, REL_BTN_SIM_2);
}
else
printString("Unknown command.\r\n");
// Clear the buffer
memset(s,'\0', sizeof(s));
}
/* End event loop */
return (0);
}
I noticed that after I send a command around seven or eight times (or more), the serial communication is interrupted or that the command is executed with a delay. I can also see, that the debug strings "Will set I1 off!", "Will set I1 on!" are printed, but the state of the outputs are not changed (or are changed with a delay of a couple of seconds).
I was wondering if someone would know, what I'm doing wrong?
Thanks.
You have a nice definition of set_output(), but you are not using it. So I suspect that you never enabled the output driver. By setting the port register, you just enable the weak pull-up. Maybe that is not strong enough to switch on your relay driver fast. Do you have a capacitor in that driver circuit?

S3c2440(ARM9) spi_read_write Flash Memory

I am working on SPI communication.Trying to communicate SST25VF032B(32 MB microchip SPI Flash).
When I am reading the Manufacturer Id it shows MF_ID =>4A25BF
but originally it is MF_ID =>BF254A. I am getting it simply reverse, means first bite in 3rd and 3rd byte in first.
What could be the possible reason for that?
My SPI Init function is here:
//Enable clock control register CLKCON 18 Bit enables SPI
CLKCON |= (0x01 << 18);//0x40000;
printk("s3c2440_clkcon=%08ld\n",CLKCON);
//Enable GPG2 Corresponding NSS port
GPGCON =0x1011;//010000 00 01 00 01
printk("s3c2440_GPGCON=%08ld\n",GPGCON);
SPNSS0_ENABLE();
//Enable GPE 11,12,13,Corresponding MISO0,MOSI0,SCK0 = 11 0x0000FC00
GPECON &= ~((3 << 22) | (3 << 24) | (3 << 26));
GPECON |= ((2 << 22) | (2 << 24) | (2 << 26));
//GPEUP Set; all disable
GPGUP &= ~(0x07 << 2);
GPEUP |= (0x07 << 11);
//SPI Register section
//SPI Prescaler register settings,
//Baud Rate=PCLK/2/(Prescaler value+1)
SPPRE0 = 0x18; //freq = 1M
printk("SPPRE0=%02X\n",SPPRE0);
//polling,en-sck,master,low,format A,nomal = 0 | TAGD = 1
SPCON0 = (0<<5)|(1<<4)|(1<<3)|(0<<2)|(0<<1)|(0<<0);
printk("SPCON1=%02ld\n",SPCON0);
//Multi-host error detection is enabled
SPPIN0 = (0 << 2) | (1 << 1) | (0 << 0);
printk("SPPIN1=%02X\n",SPPIN0);
//Initialization procedure
SPTDAT0 = 0xff;
My spi_read_write function as follows:
static char spi_read_write (unsigned char outb)
{
// Write and Read a byte on SPI interface.
int j = 0;
unsigned char inb;
SPTDAT0 = outb;
while(!SPI_TXRX_READY) for(j = 0; j < 0xFF; j++);
SPTDAT0 = outb;
//SPTDAT0 = 0xff;
while(!SPI_TXRX_READY) for(j = 0; j < 0xFF; j++);
inb = SPRDAT0;
return (inb);
}
My Calling function is:
MEM_1_CS(0);
spi_read_write(0x9F);
m1 = spi_read_write(0x00);
m2 = spi_read_write(0x00);
m3 = spi_read_write(0x00);
MEM_1_CS(1);
printk("\n\rMF_ID =>%02X-%02X-%02X",m1,m2,m3);
Please guide me what to do?
Thanks in Advance!!
There's no apparent problem with the SPI function.
The problem is with your printing function.
Arm is little endian processor. it keeps the bytes reversed in memory.
You need to print it reverse order and you'll be fine.
I was banging my head on this from last couple of days and finally I find the solution. All I needed to change my spi_read_write function as follows.
static char spi_read_write (unsigned char outb)
{
int j = 0;
unsigned char inb;
while(!SPI_TXRX_READY) for(j = 0; j < 0xFF; j++);
SPTDAT0 = outb;
while(!SPI_TXRX_READY) for(j = 0; j < 0xFF; j++);
inb = SPRDAT0;
return (inb);
}
CHANGES MADE:
First of all we have to check whether the SPI_TXRX_READY then fill the register with the value SPTDAT0 = outb;.
Thanks all for your kind support.

AVR code not running when interrupt vector is present

Trying to get an ATmega162 USART up and running. This code does exactly what I expect it to:
#define F_CPU 14745600UL
#define UBRR_1 F_CPU / 16 / 9600 - 1
#define UBRR_2 F_CPU / 16 / 31250 - 1
#include <inttypes.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
int main(){
uint16_t ubrr1 = UBRR_1;
UBRR0H = (uint8_t)(ubrr1 >> 8);
UBRR0L = (uint8_t)ubrr1;
UCSR0B = _BV(TXEN0);
UCSR0C = _BV(URSEL0) | _BV(UCSZ00) | _BV(UCSZ01);
uint16_t ubrr2 = UBRR_2;
UBRR1H = (uint8_t)(ubrr2 >> 8);
UBRR1L = (uint8_t)ubrr2;
UCSR1B = _BV(RXEN1);
UCSR1C = _BV(URSEL1) | _BV(UCSZ10) | _BV(UCSZ11);
DDRB = _BV(PB0) | _BV(PB1);
PORTB |= _BV(PB0);
while (1){
PORTB ^= _BV(PB0);
_delay_ms(50);
// byte received on usart 1
if ((UCSR1A & _BV(RXC1)) != 0){
// usart 0 ready to write
if ((UCSR0A & _BV(UDRE0)) != 0){
uint8_t b = UDR1;
UDR0 = b;
}
}
}
return 0;
}
That is, initializes the two USARTs at different baud rates, reads from USART1 and writes to USART0. Works great. Yes, I know that _delay_ms() is messing with the timing, but it works fine for this example. Now, as soon as I enable the RX interrupt on USART1 and add the appropriate vector, the main loop stops running (the LED isn't blinking, at least):
#define F_CPU 14745600UL
#define UBRR_1 F_CPU / 16 / 9600 - 1
#define UBRR_2 F_CPU / 16 / 31250 - 1
#include <inttypes.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
int main(){
uint16_t ubrr1 = UBRR_1;
UBRR0H = (uint8_t)(ubrr1 >> 8);
UBRR0L = (uint8_t)ubrr1;
UCSR0B = _BV(TXEN0);
UCSR0C = _BV(URSEL0) | _BV(UCSZ00) | _BV(UCSZ01);
uint16_t ubrr2 = UBRR_2;
UBRR1H = (uint8_t)(ubrr2 >> 8);
UBRR1L = (uint8_t)ubrr2;
UCSR1B = _BV(RXEN1);
UCSR1C = _BV(URSEL1) | _BV(UCSZ10) | _BV(UCSZ11);
DDRB = _BV(PB0) | _BV(PB1);
// enable usart1 rx interrupt
UCSR1B |= _BV(RXCIE1);
PORTB |= _BV(PB0);
// enable interrupts
sei();
while (1){
PORTB ^= _BV(PB0);
_delay_ms(50);
}
return 0;
}
ISR(USART1_RXC_vect){
uint8_t byte = UDR1;
if ((UCSR0A & _BV(UDRE0)) != 0){
UDR0 = byte;
}
}
The weirdest part is that it's not the sei(); and UCSR1B |= _BV(RXCIE1); lines that make the program stop working -- it's the existence of the ISR. As soon as I comment out that function, the main loop executes normally. Did I miss a flag somewhere?
It's possible this has been caused by the M161C fuse bit (in the extended fuse byte) becoming programmed. This puts the ATmega162 into ATmega161 compatibility mode which causes the device to have a different layout of the interrupt vector table (which the compiler won't know about.) See enter link description here Page 57 for the details. You could test this by compiling with -mmcu=atmega161 and seeing if it fixes the problem.
The other thing which would cause similar behaviour is if this code is run on an (almost identical-looking) ATmega16 instead of an ATmega162 as the UDR1 register is in a different place in the IO register map, meaning that the RXC interrupt flag would never get cleared and the handler would re-enter forever. You can check the register values the compiler is using by disassembling with avr-objdump.