I am trying to transmit a byte on the uart of an attiny2313 but the transmit hangs in the loop that waits until UDR is available.
I am using the internal 8MHz clock.
Uart configured for 9600baud 8bit 1stopbit
My init code is as following:
#define F_CPU 8000000UL
#define USART_BAUDRATE 9600UL
#define USART_UBBR_VALUE ((F_CPU / (USART_BAUDRATE << 4)) - 1)
UBRRL = (uint8_t)USART_UBBR_VALUE;
UBRRH = (uint8_t)(USART_UBBR_VALUE >> 8);
UCSRB = ((1 << TXEN) | (1<<RXEN));
UCSRC = ((1 << UCSZ1) | (1 << UCSZ0));
After init I enable global interrupts using sei().
Transfer:
while (!(UCSRA & (1<<UDRE)));
UDR = 'B';
It hangs on the while loop, when I remove power from the device, it finally breaks while loop on last moment and sents the B.
I have tried adding delay of 200ms after init but didn't work.
I use similar code for an atmega88 and this is working fine.
Anyone an idea why it stays in the while loop?
Related
Im trying to display A on TERA TERM simulator but when i run my code on ATMEL STUDIO 7 the code doesn't stop running.
This is my code below i am running the program on the simulator tool available on atmel studio 7 and i believe i am configuring the UART correctly
#include <avr/io.h>
void configureUART(void);
void sendUART(unsigned char);
int main(void)
{
configureUART();
sendUART('A');
}
void sendUART(unsigned char transmitByte)
{
while ((UCSRA & (1 << UDRE))== 0);
// Data register is ready, transmit out the byte.
UDR = transmitByte;
}
void configureUART()
{
//Baud Rate Config 9600 => 0x4D
UBRRH = 0x00;
UBRRL = 0x4D;
//Need to use UCSRC Register w/ asynchronous op. and 1 stop bit w/ 8 data bits
UCSRC = (1 << URSEL) | (0 << USBS) | (1 << UCSZ0) | (1 << UCSZ0) ;
//Transmit and Receive
UCSRB = (1 << RXEN) | (1 << TXEN);
}
I am having an issue in getting my computer (virtual COM port, to be exact) to communicate with my STM32L053R8T6 (Nucleo) board by DMA and USART. Here is my code for the DMA and USART part:
#include "Device/Include/stm32l0xx.h" // Device header
#include "JB.h"
#include <string.h>
#define PCLK 32000000
#define BAUD 19200
uint8_t stringtosend[] = "test\n";
uint8_t stringtoreceive[] = " ";
void ENABLE_UART_DMA(void){
RCC->AHBENR |= RCC_AHBENR_DMA1EN; //enable periph.clk for DMA1
/**Enabling DMA for transmission
* DMA1, Channel 4 mapped for USART2TX
* USART2 TDR for peripheral address
* stringtosend for data address
* Memory increment, memory to peripheral | 8-bit transfer | transfer complete interrupt**/
DMA1_CSELR->CSELR = (DMA1_CSELR->CSELR & ~DMA_CSELR_C4S) | (4 << (3 * 4));
DMA1_Channel4->CPAR = (uint32_t)&(USART2->TDR);
DMA1_Channel4->CMAR = (uint32_t)stringtosend;
DMA1_Channel4->CCR = DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE;
/**Enabling DMA for reception
* DMA1, Channel 5 mapped for USART2RX
* USART2 RDR for peripheral address
* stringtoreceive for data address
* Data size given
* Memory increment, peripheral to memory | 8-bit transfer | transfer complete interrupt**/
DMA1_CSELR->CSELR = (DMA1_CSELR->CSELR & ~DMA_CSELR_C5S) | (4 << (4 * 4));
DMA1_Channel5->CPAR = (uint32_t)&(USART2->RDR);
DMA1_Channel5->CMAR = (uint32_t)stringtoreceive;
DMA1_Channel5->CNDTR = sizeof(stringtoreceive);
DMA1_Channel5->CCR = DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_EN;
NVIC_SetPriority(DMA1_Channel4_5_6_7_IRQn, 0); //NVIC enabled, max priority, channels 4-7
NVIC_EnableIRQ(DMA1_Channel4_5_6_7_IRQn);
}
void CONFIGURE_UART_PARAM(void){
RCC->IOPENR |= ( 1ul << 0); //Enable GPIOA clock
RCC->APB1ENR |= ( 1ul << 17); //Enable USART#2 clock
GPIOA->AFR[0] &= ~((15ul << 4* 3) | (15ul << 4* 2) ); //Clear PA2,PA3
GPIOA->AFR[0] |= (( 4ul << 4* 3) | ( 4ul << 4* 2) ); //Set PA2,PA3
GPIOA->MODER &= ~(( 3ul << 2* 3) | ( 3ul << 2* 2) ); //Same as above
GPIOA->MODER |= (( 2ul << 2* 3) | ( 2ul << 2* 2) );
USART2->BRR = PCLK/BAUD;
USART2->CR3 = USART_CR3_DMAT | USART_CR3_DMAR; //Enable DMA mode in transmit and receive
/*UART enabled for transmission and reception*/
USART2->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
while((USART2->ISR & USART_ISR_TC) != USART_ISR_TC)
{
/* add time out here for a robust application */
}
USART2->ICR = USART_ICR_TCCF;
}
void CONFIGURE_EXTI(void){
SYSCFG->EXTICR[0] = ((SYSCFG->EXTICR[0] & 0x0000) | SYSCFG_EXTICR4_EXTI13_PC); //clear EXTICR and set to PC13(B1)
EXTI->FTSR |= EXTI_FTSR_TR13; //falling edge trigger
EXTI->IMR |= EXTI_IMR_IM13; //unmask
NVIC_SetPriority(EXTI4_15_IRQn, 0); //def interrupt
NVIC_EnableIRQ(EXTI4_15_IRQn);
}
/*************************************************************************************************************************************************************************************************************************/
/*************************************************************************************************************************************************************************************************************************/
/*Interrupt Handlers*/
void DMA1_Channel4_5_6_7IRQHandler(void){
if((DMA1->ISR & DMA_ISR_TCIF4) == DMA_ISR_TCIF4){
DMA1->IFCR = DMA_IFCR_CTCIF4; //Clear Channel 4 Transfer Complete flag
}
else if((DMA1->ISR & DMA_ISR_TCIF5) == DMA_ISR_TCIF5){
DMA1->IFCR = DMA_IFCR_CTCIF5; //Clear Channel 5 Transfer Complete flag
DMA1_Channel5->CCR &= ~DMA_CCR_EN;
DMA1_Channel5->CNDTR = sizeof(stringtoreceive);/* Data size */
DMA1_Channel5->CCR |= DMA_CCR_EN;
}
}
void EXTI4_15_IRQHandler(void){
if(!(GPIOC->IDR & (1 << 13))){
/* Clear EXTI 13 flag */
EXTI->PR = EXTI_PR_PIF13;
/* start 8-bit transmission with DMA */
DMA1_Channel4->CCR &= ~DMA_CCR_EN; //channel disable
DMA1_Channel4->CNDTR = sizeof(stringtosend);/* Data size */
DMA1_Channel4->CCR |= DMA_CCR_EN; //channel enable
}
}
//void EXTI4_15_IRQHandler(void){
// if((EXTI->PR & EXTI_PR_PIF13) == EXTI_PR_PIF13){
// /* Clear EXTI 13 flag */
// EXTI->PR = EXTI_PR_PIF13;
//
// /* start 8-bit transmission with DMA */
// DMA1_Channel4->CCR &= ~DMA_CCR_EN; //channel disable
// DMA1_Channel4->CNDTR = sizeof(stringtosend);/* Data size */
// DMA1_Channel4->CCR |= DMA_CCR_EN; //channel enable
// }
//}
Now then, this specific code is based on an example from the STM32L0 snippets package 1.20, USART/Communcation Using DMA. USART 1 was simply redefined to USART 2 (as that is the one used by the virtual COM port), and the DMA channels were redefined according to that as well. However, the problem here is very simple: it will only print stringtosend once (would like to do it every time button B1 is pressed), and will not receive data by RX either - as if it completely ignores the DMA interrupt handler - which I am not sure how to test (no trace features available on this board). What I have seems to reflect the reference manual well enough, and all the main does is:
int main(){
SystemCoreClockInit();
CONFIGURE_UART_PARAM();
ENABLE_UART_DMA();
pushbutton_def();
CONFIGURE_EXTI();
while(1){
}
...which should just react to the defined interrupts, however it does not, and for the life of me, I cannot see why. I would love if you could help me - I would also like to avoid HAL or LL APIs - this is not a complex enough project to warrant their usage (several inputs, outputs, comms between two boards by USART/DMA), plus I would prefer to learn working closer to the register level.
Thanks!
edit (in response to Berendi's suggestions):
1. GPIOC was defined in another file, called with pushbutton_def():
RCC->IOPENR |= (1UL << 2); //enable GPIOC
I understand exactly what you mean by your explanation (indeed, the register referred by those two is "the same", 0x00000020U), but I am not sure as to how to redefine it: here is my attempt after looking at the reference manual (SYSCFG part) and the source (still, it does not work):
SYSCFG->EXTICR[3] = ((SYSCFG->EXTICR[3] & 0x0000) | SYSCFG_EXTICR4_EXTI13_PC);
As suggested, I have added USART2->ICR = USART_ICR_TCCF; to the EXTIhandler, right after the DMA channels. I have kept it in the USART definition. The message is still only being sent once, though.
GPIOC is not enabled
Here,
RCC->IOPENR |= ( 1ul << 0); //Enable GPIOA clock
you should enable GPIOC too.
EXTI13 is mapped to PA13
Here,
SYSCFG->EXTICR[0] = ((SYSCFG->EXTICR[0] & 0x0000) | SYSCFG_EXTICR4_EXTI13_PC); //clear EXTICR and set to PC13(B1)
you are setting the configuration register for EXTI0-EXTI3, actually mapping EXTI1 to PC1. EXTI13 remains mapped to PA13, which is actually SWDIO, connected to the onboard debugger. I guess the traffic on SWDIO triggers the EXTI interrupt, the handler checks PC13 which is always reading 0 because the port is disabled, and enables DMA. DMA transmit works only once though, because
USART_ISR_TC is not cleared in the interrupt
but only once at startup. You should move this line
USART2->ICR = USART_ICR_TCCF;
to the EXTI interrupt handler.
I'm not sure why receiving doesn't work, perhaps the DMA handler has no chance to run, because EXTI is constantly retriggered by SWD traffic. Both interrupts have the same priority, the one with lower interrupt number wins, which is the EXTI handler. If it's always retriggered before it finishes, then it will be called again, not letting the other handler to run.
I'm currently working on a piece of code, which should wait for a comparator interrupt and execute some other code after a set amount of time. Now, I thought using Timer2 in CTC mode would be a good idea to make sure that the program waits for the right amount of time and came up with this:
void setup(){
...
// Set up the timer
TCCR2A = 0;
TCCR2B = 0;
TCNT2 = 0;
OCR2A = 255; // compare match register
TCCR2A = (1 << WGM21); // CTC mode
TCCR2B = ((1 << CS22) | (1 << CS21)); // 256 prescaler
TIMSK2 &= ~(1 << OCIE2A); // disable interrupt
}
ISR(ANALOG_COMP_vect) {
// switchTime is in µs, usual value: around 500µs
// with a 16 Mhz crystal and a 256 prescale we need to devide
// the switchTime by 16 (2^4)
OCR2A = switchTime >> 4;
TCNT2 = 0; // reset counter
TIMSK2 |= (1 << OCIE2A); // enable timer compare interrupt
}
ISR(TIMER2_COMPA_vect) {
TIMSK2 &= ~(1 << OCIE2A); // disable interrupt
// do stuff
}
The awkward thing is, it doesn't work. The ISR timer is immediately called after we leave the ISR comparator (I checked this by toggling a pin in both routines and measuring with an oscilloscope). After a few hours of reading datasheets and randomly changing the code I came up with a line of code that fixed it:
ISR(TIMER2_COMPA_vect) {
TIMSK2 &= ~(1 << OCIE2A); // disable interrupt
OCR2A = 255; // <- apparently fixes all my problems
// do stuff
}
I'm quite confused about this because the frequency of the timer shouldn't be a matter after we call the routine and deactivate the interrupt.
Now I'm quite glad that I've found the solution but I want to know why it works. Something about knowing how to fish and accidentally catching a fish by randomly inserting code.
I think you missed the clearing of pending timer interrupts.
ISR(TIMER2_COMPA_vect) {
TIMSK2 &= ~(1 << OCIE2A); // disable interrupt
/* Clear pending interrupts */
TIFR2 = (1 << TOV2) | (1 << OCF2A) | (1 << OCF2B);
// do stuff
}
I'm not gonna waste your time, and just post the code along with the explanation
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
int main(void){
sei(); //Enable interrupts
DDRB = (1 << PORTB3);//Set pin P3 as an output and other pins as inputs
//PORTB = 0xff;
DDRA = (1 << PORTA7);//Set pin A7 as an output and other pins as inputs
//PORTA = (1 << PORTA7);
TCCR0 = (1 << WGM00) | (1 << WGM01) | (1 << COM01);//Enable PWM, and configure Timer
TIMSK = (1 << TOIE0);//Enabling an interrupt
OCR0 = 255;//Setting comparison value for the Output compare unit
TCCR0 |= (0b110 << CS00);//Selecting the clock as the falling edge on a certain pin
while(1){
/*
* The portion of the code creates a square wave with a period of 39 us, which means that the falling edge occurs at a period of 78us, and since the output period of
* the PWM is 50Hz for a servo, that fits perfectly (1/(79*10^-6 * 256) ~ 50), but for some reason, the servo doesn't move...*/
PORTA ^= (1<< PORT7);
_delay_us(39);
}
}
So, what's the problem?? I don't really have an oscilloscope to measure the frequency, so don't ask me to do that, but a peculiar thing that I did notice was that the voltage across the servo power wires was 2.7V when it should've been 5V, but the power supply itself was supplying 5V, and this only happened when I connected the signal pin to the PWM pin, and it happened regardless of whether the 5V rail was connected to the servo or not... Any ideas on what the problem is??
Your PWM output has a 50% duty cycle, so the effective port output voltage is reduced from 5v to 2.5v when measured with a voltmeter. Assuming you are measuring the voltage against Ground, it won't make any difference if 5v power line is connected to the servo, but it will make a difference if the PWM signal is not connected.
If the servo is bidirectional, then it is possible that the 50% duty cycle keeps it stationary - try a different duty cycle, it looks as if you have hard coded the PWM period, inverting the output every half-cycle. Try something like
PORTA ^= (1<< PORT7);
_delay_us(28);
PORTA ^= (1<< PORT7);
_delay_us(50);
I want to set up the UART on a ATmega88-PA. First I was trying to set an interrupt on UDRE register but this was not working, so for the transmission I use normal polling.
Because the code was not working I started again from 0 with a basic program.
#define F_CPU 1000000UL
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 8UL))) - 1)
char ReceivedByte = '#';
int main (void)
{
UCSR0A = (1 << U2X0);
/* Turn on the transmission and reception circuitry. */
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
/* Use 8-bit character sizes. */
//UCSR0C = (1 << UCSZ00) | (1 << UCSZ01);
/* BAUD prescale */
UBRR0 = 12;
/* Load upper 8-bits of the baud rate value into the high byte of the UBRR register. */
//UBRR0H = (BAUD_PRESCALE >> 8);
/* Load lower 8-bits of the baud rate value into the low byte of the UBRR register. */
//UBRR0L = BAUD_PRESCALE;
UCSR0B |= (1 << RXCIE0);
sei();
DDRB |= 0x04;
PORTB &= ~0x04;
for (;;)
{
/* Do nothing until data have been received and is ready to be read from UDR. */
//while ((UCSR0A & (1 << RXC0)) == 0) {};
/* Fetch the received byte value into the variable "ByteReceived". */
//ReceivedByte = UDR0;
if(ReceivedByte == '1')
PORTB |=0x04;
else
PORTB &=~0x04;
/* Do nothing until UDR is ready for more data to be written to it. */
while ((UCSR0A & (1 << UDRE0)) == 0) {};
/* Echo back the received byte back to the computer. */
UDR0 = ReceivedByte;
}
}
ISR(USART_RX_vect)
{
ReceivedByte = UDR0;
}
And the code is working but when I open an arduino serial monitor and connect my module to that, I receive my poor # but alog with some garbage. Not all the time but mostly, the garbage is 1 or 2 byte. Can someone help me?
EDIT: It seams that when I send from my bleutooth data to a Samsung galaxy S3 the data is perfect...I do not have any clue why on serial monitor, and also when sending data using the same bluetooth to laptop I got a lot of garbage along with the data. If this helps you
answearing my qestion, will be great.
EDIT: sorry forget the last edit, it is send only a char ok, I change the char and also garbage is there. When I send a string is unreadable.
EDIT : As I commneted on the post below of embedded_guy , I solve the problem inserting a _delay_ms(1) after sending each byte. and it is working right now. I believe the statement
while ((UCSR0A & (1 << UDRE0)) == 0) {};
is not doing its job. Hope this will help others.
I don't know if this will work for you, but I really only see a couple of things that could be an issue.
First, all of the examples of setting the BAUD prescale that I could find used two instructions with the high and low registers of UBRR0. If you have already stepped through your code and examined that register to ensure that it is correctly configured, then that is not the issue. Otherwise, I would recommend setting it like this for the value you have it set to in your code:
UBRR0H = 12;
UBRR0L = 0;
The other thing I see is that you are never setting UCSR0C. You have it commented out and I would expect it to operate correctly with its default (reset condition) settings, but it is always good to be explicit just in case.
Finally, you may want to take a look at this page on Simple Serial Communications.
EDIT
Based on your most recent edit, I would take the bluetooth out of the picture. I would recommend connecting a logic analyzer to the UART transmit pin of your microcontroller and see if the data coming out of the atmega is what you expected. If that data is good, I would begin looking at why the bluetooth is not working as I anticipated.
try to use F_CPU with at least 2MHz
make your ReceivedByte volatile, try it like this:
volatile unsigned char ReceivedByte;