AVR USART Programming - c

I am currently working on a project where we have to use an AVR ATMEGA328 micro-controller, specifically the USART peripheral, to control 8 LED's. We have to send commands to the micro-controller that will turn on, off, and blink the LED's at different rates. I have written a program in C that I think will do the job, but I would like someone to look at it and help me fix any mistakes that I may have. Your help will be greatly appreciated!
*P.S. Each command in the commands array associates with its corresponding LED state in the LED array. The LED's are connected to PORTB of the micro-controller.
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
/* Arrays that contain all input commands and LED states */
const char *commands[] = {"ON0","ON1","ON2","ON3","ON4","ON5","ON6","ON7","ON8","OFF0","OFF1","OFF2","OFF3","OFF4","OFF5","OFF6","OFF7","OFF8","BLINK0","BLINK1","BLINK2","BLINK3","BLINK4","BLINK5","BLINK6","BLINK7","BLINK8","STOP"\0}
int LEDs[28] = {0X01,0X02,0X04,0X08,0X10,0X20,0X40,0X80,0XFF,0XFE,0XFD,0XFB,0XF7,0XEF,0XDF,0XBF,0X7F,0,0X01,0X02,0X04,0X08,0X10,0X20,0X40,0X80,0XFF,0}
int i;
int j;
int Blinky(int j); // Function to execute blinking commands where j is the argument
{
PORTB = LEDs[j];
_delay_ms[250 + (j-18) * 50]; /* Calculates blinking delay times */
PORTB = 0;
_delay_ms[250 + (j-18) * 50];
}
int main(void)
{
DDRB=0XFF; // PORTB is set to output
DDRD=0X02; // Turns on the transmit pin for the USART in PORTD
/* Setup USART for 9600,N,8,1 */
USCR0B = 0X18;
USCR0C = 0X06;
UBRR0 = 51;
sei(); // Enable Global Interrupts
char input;
if(UCSR0A & 0X80) /* Reads data from the USART and assigns the contents to the character input */
input = UDR0;
j=28;
char cmd;
cmd = *commands[i];
for(i=0; i<28; i++)
{
if(input==cmd) /* If the contents of UDR0 are equal to one of the commands */
j = i;
}
while(1)
{
if(j<18)
PORTB=LEDs[j]; // Executes the "ON" and "OFF" commands
else if(j<27)
Blinky(j); // Executes the blinking command by calling the Blinky function
else if(j=27)
PORTB=0; // Executes the "STOP" command
else
PORTB=0; // Accounts for typing errors
}
return(0);
}

There is a lot wrong with this program, but code review is not the purpose of Stack Overflow. See the FAQ for how to ask an appropriate question.
That said, some of the obvious problems are:
The _delay_ms() function needs to be called with a compile-time constant. It won't work correctly if the parameter needs to be calculated at run-time.
if you don't read any char from USART, then you still go through the rest of the loop.
char cmd declares a character variable, but then you assign a pointer to it.
i is used before it is set to a meaningful value.
input== cmd will likely never be true as one side is a character and the other is a pointer.
This question will likely close soon. Good luck, and come back if you have a question better suited to Stack Overflow.

Related

Pic 18f4550 capture mode

I would like to measure a pulse using the pic 18f4550 in capture mode, this pulse is generated by the pic microcontroller itself, for this I use a function which plays the role of the XOR logic gate (you find the function that I've used below). with RC0 and RC2 the inputs and RC6 the signal output. the pulse leaving RC6 enters ccp2 to be measured.
The problem I found is that the ccp2 cannot detect the impulse generated by the microcontroller. I don't know if there are any conditions to connect the pins of the microcontroller or something.
If anyone has an answer or a hint to fix this, I will be grateful!
and if you have any questions feel free to ask .thanks !!
UPDATE: I changed some instructions in the code, now the RC6 output provides a signal. but my LCD does not display anything. the RC6 output is present below.
UPDATE 2: the while(1) in the xor() function blocking the rest of my program, so the program never get out of xor() and my LCD wont display anything. when I don't use the while loop in xor () my RC6 produce anything, the same for the LCD.
I don't know where the problem is, I did everything in my power to find the bug . but the system still not working!!!
I will leave the program as it is, so new readers can understand what I am talking about.
#include <stdio.h>
#include <stdlib.h>
#include "osc_config.h"
#include "LCD_8bit_file.h"
#include <string.h>
unsigned long comtage,capt0,x;
char pulse[20];
char cosinus[20];
float period,dephTempo,deph,phi;
void init (){
IRCF0 =1; /* set internal clock to 8MHz */
IRCF1 =1;
IRCF2 =1;
PIE2bits.CCP2IE=1;
PIR2bits.CCP2IF=0;
CCPR2 =0; /*CCPR1 is capture count Register which is cleared initially*/
T3CONbits.RD16=1;
T3CKPS0=0;
T3CKPS1=0;
TMR3CS=0;
TMR3IF=0;
T3CCP2=0; /*Timer3 is the capture clock source for CCP2*/
}
void xor()
{
while(1)
{
if (PORTCbits.RC0==PORTCbits.RC2)
{
PORTCbits.RC6=0;
}
else if (PORTCbits.RC0!=PORTCbits.RC2)
{
PORTCbits.RC6=1;
}
}
}
void main()
{
TRISCbits.TRISC0=1;
TRISCbits.TRISC2=1;
TRISCbits.TRISC6=0;
xor();
LCD_Init();
while(1)
{
CCP2CON = 0b00000101;
PIR2bits.CCP2IF = 0;
TMR3ON = 0;
TMR3 = 0;
while (!PIR2bits.CCP2IF);
TMR3ON = 1;
CCP2CON = 0b00000100;
PIR2bits.CCP2IF = 0;
while (!PIR2bits.CCP2IF);
comtage = CCPR2;
dephTempo = (((float)comtage /30.518)/65536 );
sprintf(pulse,"%.3f ",dephTempo);
LCD_String_xy(0,0,"the pulse width is : ");
LCD_String_xy(2,9,pulse);
}
}

PuTTY not sending data to AVR serial

in an exercise for my embedded programming course we have to program an Atmega328p AVR chip to receive data through the serial port. We have to do this by calling a function that waits until it receives a char. Next it should display the ascii value of that char in led lights, but I am having trouble even receiving it. I've done a lot of debugging and I think I narrowed it down to PuTTY not even sending the data, or the AVR not receiving it properly. I will put my code in below:
/*
From the PC should come a char, sent via the serial port to the USART data register.
It will arrive in the RXB, which receives data sent to the USART data register.
While running the loop, the program should encounter a function that is called and waits for the RXB to be filled.
Then it will read the RXB and return it to the main loop.
The result will be stored and processed accordingly.
*/
#define F_CPU 15974400
#include <util/delay.h>
#include <avr/io.h>
#include <stdlib.h>
#include <avr/interrupt.h>
void writeChar(char x);
void initSerial();
char readChar();
int main(void)
{
initSerial();
while (1)
{
char c = readChar(); //reads char, puts it in c
_delay_ms(250); //waits
writeChar(c); // spits that char back into the terminal
}
}
void initSerial(){
UCSR0A = 0;
//UCSR0B = (1 << TXEN0); // Enable de USART Transmitter
UCSR0B = 0b00011000; //transmit and receive enable
//UCSR0C = (1 << UCSZ01) | (0 << UCSZ00); /* 8 data bits, 1 stop bit */
UCSR0C = 0b00100110; // Even parity, 8 data bits, 1 stop bit
UBRR0H=00;
UBRR0L=103; //baudrade 9600 bij
}
void writeChar(char x){
while(!(UCSR0A & (1 << UDRE0))); // waits until it can send data
UDR0 = x; // Puts x into the UDR0, outputting it
}
char readChar(){
while (!(UCSR0A & (1 << RXC0))); //waits until it can send data
return UDR0; // returns the contents of the UDR0 (the receiving part of course
}
The problem is that when I enter anything in PuTTY (that I assume I set up correctly. https://prnt.sc/rc7f0f and https://prnt.sc/rc7fbj seem to be the important screens.
Thanks in advance, I am completely out of ideas.
I fixed it myself. I figured it out while taking it downstairs to test it on another laptop. I still had LEDs put in all pins of PORTD, all on input mode (that's the default mode). I quick look at the Atmega328p user guide (section 2.5.3) revealed that the pin D0 was actually the RxD in for the USART. By putting an LED on it and effectively grounding it, it was always pulled low, and would never be put high by the CPU, which would stop the while loop check while (!(UCSR0A & (1 << RXC0))); //waits until it can send data in readChar();
So by simply removing that led it would work again. Obviously that would mean it was floating, so I set the DDRD to all be output, as nothing needed to be input anyway.
That ended up fixing it.

I need to know why my interrupts are not working here

I am using stm8l - discovery and i have created a code for toggling a led for every 1 second using timer (TIM1) but this is not working properly. I am missing something here in my configuration
I could enter the interrupt function for the first time but after that it does not enter the interrupt function. Someone please look into and help me out
enter code here
#include <iostm8l.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "defs.h"
unsigned int count = 0;
#svlreg #interrupt void TIM1(void)
{
count += 1;
TIM1_SR1 &= ~(0x01);
}
main()
{
CLK_DIVR = 0x00; // Set the frequency to 16Mhz
CLK_PCKENR2 = 0x02; // clock for timer1
PC_DDR = 0x80; // direction output for led
PC_CR1 = 0x80; // fast push pull mode
PE_DDR = 0x80; // direction output for led
PE_CR1 = 0x80; // fast push pull mode
TIM1_PSCRH = 0x3e; //to create a frequency for 1000 hz
TIM1_PSCRL = 0x80; // so prescalar is 16000
TIM1_CR1 = 0x01;
TIM1_IER = 0x01;
_asm("rim\n");
while(1)
{
if (count == 1000)
{
PE_ODR ^= 0x80;
count = 0;
}
}
}
The interrupt enters only one time but after that it does not enter. So variable "count" remains at value 1
You are using magic numbers for the bit masks instead of defined constants, so the code is pretty damn hard to read for you and me both. Change this so that the code ends up like for example
TIM1_SR1 &= ~TIM1_SR1_UIF;
Since this is a 8 bit MCU it is also absolutely essential that you u suffix all integer contants, or they will be of type signed int, which you don't want.
For example this code TIM1_SR1 &= ~(0x01); is equivalent to TIM1_SR1 &= -2. Very easy to write accidental subtle bugs this way. I recommend studying Implicit type promotion rules.
It is highly recommended to disassemble every ISR you write to see what machine code you actually end up with, and single step it through the debugger while watching the register as well. This particular register seems to ignore having 1 written to it, so you could probably just do TIM1_SR = TIM1_SR1_UIF;. Incorrectly cleared timer flags inside ISRs is one of the most common bugs in embedded systems.
Quoting the manual:
UIF: Update interrupt flag
– At overflow or underflow if UDIS = 0 in the TIM1_CR1 register
– When CNT is re-initialized by software using the UG bit in TIM1_EGR register, if URS = 0 and UDIS = 0 in the TIM1_CR1 register.
– When CNT is re-initialized by a trigger event (refer to the TIM1_SMCR register description), if URS = 0 and UDIS = 0 in the TIM1_CR1 register
Your code doesn't appear to do any of this, so it is pretty safe to assume the timer counter isn't reset.
Another problem is that count must be declared as volatile or otherwise the compiler might optimize out this code completely:
if (count == 1000)
{
PE_ODR ^= 0x80;
count = 0;
}

Audio Transfer Callbacks not executing with STM32F469I-Discovery

I'm new to embedded programming and I'm currently working on a project with an STM32F469I-discovery board. I'm using eclipse with the ARM tool chain and the supplied drivers. I'm getting stuck on playing a binary audio file flashed into the chip at a specific address. I've very simply based my code on some of the example files, although very much cut down as I'm just trying to get it to work.
At the moment, the code works up to the point where it plays the buffer, but then it appears to get stuck. The buffer is playing in a loop (I've changed the size of the buffer to confirm this) and you can hear it, but that's all that happens. The transfer interrupt callbacks never execute, and hence the buffer does not refil and the full sample is never played.
I've tried using an external interupt to refil the buffer, but when I try this, it gets stuck. I've also tried to debug it by turning on LEDs, but this has confirmed that effectively it gets stuck shortly after playing the sample. The infinite while loop never executes, and the transfer interrupts never execute.
My question is - why is it getting stuck and why are the interrupts not being triggered?
Any help would be greatly appreciated!
#include "main.h"
static void SystemClock_Config(void);
#define AUDIO_FILE_ADDRESS 0x08010000
#define AUDIO_FILE_SIZE (180*1024)
#define PLAY_HEADER 0x2C
#define PBSIZE 4096
uint16_t PlayBuff[PBSIZE];
int OFFSET = 0;
int TransferState = 0;
int CycleCount1 = 1;
int CycleCount2 = 1;
int main(void)
{
uint32_t PlaybackPosition = PBSIZE + PLAY_HEADER;
HAL_Init();
/* Configure the system clock to 180 MHz */
SystemClock_Config();
// Fill the buffer first time round
for(int i=0; i <= PBSIZE; i++)
{
PlayBuff[i]=*((__IO uint16_t *)(AUDIO_FILE_ADDRESS + PLAY_HEADER + i));
}
BSP_AUDIO_OUT_Init(2,50,AUDIO_FREQUENCY_16K );
BSP_AUDIO_OUT_Play(PlayBuff,PBSIZE);
while(1){
if(TransferState==1){
// refill the first part of the buffer
TransferState=0;
OFFSET = CycleCount1*PBSIZE;
for(int i=0; i <= PBSIZE/2; i++){
PlayBuff[i]=*((__IO uint16_t *)(AUDIO_FILE_ADDRESS + PLAY_HEADER + OFFSET));
}
CycleCount1++;
}
if(TransferState==2){
// refill the second part of the buffer
OFFSET = CycleCount2*PBSIZE+PBSIZE;
TransferState=0;
for(int i=PBSIZE/2; i <= PBSIZE; i++){
PlayBuff[i]=*((__IO uint16_t *)(AUDIO_FILE_ADDRESS + PLAY_HEADER + OFFSET));
}
CycleCount2++;
}
}
}
void BSP_AUDIO_OUT_TransferComplete_CallBack(void)
{
TransferState=2;
}
void BSP_AUDIO_OUT_HalfTransfer_CallBack(void){
TransferState=1;
}
In the interests of identifying the cause of the problem, I've further trimmed down the code so that all it does is play the buffer. I've removed the interrupt calls to try and identify what's causing the issue.
What it should do is configure the system clock, fill the buffer, initialise the audio, then turn on the LED. It should then play the audio buffer, wait 1s, then turn off the LED. It plays the buffer in a loop (as it should as it's in circular mode) but then gets stuck and never turns off the LED. I've tried running it in normal mode but it simply plays the buffer once, and then gets stuck.
This leads me to think I've configured/filled the buffer incorrectly.
#include "main.h"
static void SystemClock_Config(void);
#define AUDIO_FILE_ADDRESS 0x08010000
#define PLAY_HEADER 0x17569
#define PBSIZE 4096
uint16_t PlayBuff[PBSIZE];
int main(void)
{
BSP_LED_Init(LED1);
HAL_Init();
/* Configure the system clock to 180 MHz */
SystemClock_Config();
// Fill the buffer first time round
for(int i=0; i <= PBSIZE; i++)
{
PlayBuff[i]=*((__IO uint16_t *)(AUDIO_FILE_ADDRESS + PLAY_HEADER + i));
}
BSP_AUDIO_OUT_Init(OUTPUT_DEVICE_HEADPHONE ,50,AUDIO_FREQUENCY_44K );
BSP_LED_On(LED1);
BSP_AUDIO_OUT_Play(PlayBuff,PBSIZE);
HAL_Delay(1000);
BSP_LED_Off(LED1);
}
Furthermore, I've also found instances of other people online having similar issues although with no solution so far. Any help would be greatly appreciated.
I've found the problem. I hadn't set the DMA interupt in the stm32f4xx_it.c.
void DMA2_Stream3_IRQHandler(void)
{
HAL_DMA_IRQHandler(haudio_out_sai.hdmatx);
}
I've also found that when using BSP_AUDIO_OUT_Play() the sound is wrong with something bassy fluctating underneath it.
Using the following worked correctly.
/* Start the playback */
if(0 != audio_drv->Play(AUDIO_I2C_ADDRESS, NULL, 0))
{
Error_Handler();
}
if(HAL_OK != HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t *) PlayBuff, PLAY_BUFF_SIZE))
{
Error_Handler();
}
I am not familiar with the specific board, from what i see possibly you need to define TransferState as volatile.
volatile int TransferState = 0;
It is quite common issue in embedded and multi-threaded development. The compiler can optimize the variable TransferState in a register so it never actually sees the update from a different context(the callback). Volatile prevents it from doing so

cycling through leds

Please help me with this code, it is making me crazy. This is a very simple program with 8-bit timer, cycling through all 8 leds (one-by-one). Am using ATSTK600 board.
My timers are working well, I think there is some problem with the loops (when I debug this program using avr studio-gcc, I can see all the leds working as I want but when I transfer it on board...leds don't blink). Am going crazy with this type of behavior.
Here is my code:
#include <avr/io.h>
#include <avr/interrupt.h>
volatile unsigned int intrs, i, j = 0;
void enable_ports(void);
void delay(void);
extern void __vector_23 (void) __attribute__ ((interrupt));
void enable_ports()
{
DDRB = 0xff;
TCCR0B = 0x03;
TIMSK0 = 0x01;
//TIFR0 = 0x01;
TCNT0 = 0x00;
//OCR0A = 61;
intrs = 0;
}
void __vector_23 (void)
{
for(i = 0; i<=8; i++)
{
while(1)
{
intrs++;
if(intrs >= 61)
{
PORTB = (0xff<<i);
intrs = 0;
break;
}
}
}
PORTB = 0xff;
}
int main(void)
{
enable_ports();
sei();
while(1)
{
}
}
Your interrupt routine is flawed. intrs counts only the number of times the loop has executed, not the number of timer interrupts as its name suggests. 61 iterations of that loop will take very little time. You will see nothing perceivable without an oscilloscope.
The following may be closer to what you need:
void __vector_23 (void)
{
intrs++;
if(intrs > 60)
{
intrs = 0;
PORTB = (0xff<<i);
i++ ;
if(i == 8 )
{
i = 0 ;
PORTB = 0xff;
}
}
}
Although setting the compare register OCR0A to 61 as in your commented out code would avoid the need for the interrupt counter and reduce unnecessary software overhead.
Are you sure that the code downloaded to the board is not optimized?
Have you attached volatile attribute to the PORTB identifier?
Is there a way for you to slow down the code (outside the debugger)? Any chance it's running but fast that you don't see it?
Can you verify that your intended code is in fact running (outside the debugger)?
When interrupt occurs, handler very quickly counts 62*9 times and finally sets PORTB to 0x00, so leds do only very short flash which is not visible. You see it in sumulator just because it runs slower and do not emulate visual dimming effect of fast port switching. Program has a design flaw: it tries to do full blinking cycle in single interrupt. That's wrong--only a single step should be performed in interrupt call. So handler should look like this:
void __vector_23 (void)
{
intrs++;
if(intrs >= 61)
{
PORTB = (0xff<<i);
intrs = 0;
i++;
if(i>8) i = 0;
}
}
Try this.
There is guidelin on interrupts handlers: Interrupt handler should be as fast and short as possible. Do not perform complex tasks in interrupts (cycle loop is one of them, if you get cycle in interrupt, try to remove it). Do not wait or delay in interrupts.
If you're seeing the behaviour you want when debugging with avr studio-gcc, then that gives you some confidence that your program is "good" (for some sense of the word "good"). So it sounds as though you need to focus on a different area: what is the difference between your debug environment and your stand-alone download?
When doing a stand-alone download, do you know if your program is running at all?
Are the LEDs blinking, or turning on at all? You don't explicitly say in your question, but that question could be very relevant to the debugging process. Does it look like the right behaviour, running at a different speed? If so, then your program is probably not doing some sort of initialisation that the debugger was doing.
When doing a stand-alone download, is the program being compiled with different settings compared to the debug version? Perhaps compiler optimisation settings are changing your program's timing characteristics.
(Your question would be better if you gave more detail about what the stand-alone download is doing. In general, it is hard for someone to debug a remote system when they're given few or no details about what is happening. Do all/some of the LEDs turn on at all?)

Resources