Initiating UART without polling

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi guys,

Doin a small project for a friend, it is to be a temperature controller with PC interface(RS232 of course)

I have made myself a decent uart library with the standard ring-buffer, and got it up and running.

At the moment i do poll for data to be transmittet to the PC, but i find this method very limiting/confusing. For example, if i update the TX buffer inside a submenu, the data will not be sent before exiting the submenu and reaching the polling code.

I know, it is kind of trivial, might just be me having a brain fart, but how do you transmitt data immediatly after updating the buffer instead of waiting for the poll??

Edit: By the way, the code is interrupt driven from the point when first byte is transmitted....

Kim

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just look at the avr-gcc example code.
Or the CodeVision Wizard code.

Your putchar() and getchar() functions push and pull data from their respective buffers. Always with a test for full and empty buffers. (in which case they wait)

The interrupt routines look after themselves. Your program never interfere with them.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kherseth wrote:
For example, if i update the TX buffer inside a submenu, the data will not be sent before exiting the submenu and reaching the polling code.

Then you must use interrupts.

An easy example can be seen here:

https://www.avrfreaks.net/index.p...

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am using interrupts for the most parts, maybe i really should be using UDRE instead of TXC interrupt? I`ll give that ago.

Thanks for the answers ;)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I am using interrupts for the most parts

Then what, exactly, are you polling?

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have to poll to check if there is any new data in the buffer.

As long as the buffer contains new data, the transmission of that is done with interrupt. But when there is no more data to send the interrupt process stops. Then, when adding data to the buffers, nothing happens until the main code updates the UDR register.

I'll attach the code, controller is mega16:
Main program and interrupts:

#include "avr/io.h"
#include "avr/interrupt.h"
#include "uart_ring.h"
#include "string.h"
#include "adc.h"

// F_CPU 3686400
#define USART_BAUDRATE 19200
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

#define ENABLED 0
#define DISABLED 1


#define HEATER 0x01
//#define 

int main()
{
	//PORTB = BAUD_PRESCALE;
	const unsigned char Menu[5][64] = {
	{"\r1: Display SetTemp\n\r2: Adjust Temp:\n\r3: Show current temp\0"},
	{"\n\rCurrent Setpoint: \0"},
	{"\n\rAdjust Temp\0"},
	{"\n\rCurrent Temperature: \0"},
	{"\n\rEnable/disable ouput\0"}
	};

	const unsigned char Stats[2][10] = {
	{"\rEnabled\0"},
	{"\rDisabled\0"}
	};
	const unsigned char CLRSCR[] = {"\E[H\E[J\0"};
	
	unsigned int Menu_Level = 0, Temperature = 78,Measured = 0, Status = 0, cnt;
	unsigned char Choice, Input = 0;
	UBRRL = BAUD_PRESCALE;
	UBRRH = (BAUD_PRESCALE >> 8);
	UCSRB |= (1 << RXEN) | (1 << TXEN) | (1 << UDRIE) | (1 << RXCIE);// | (1 << TXCIE);// | (1 << UDRIE);   // Turn on the transmission and reception circuitry
   	UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes
	
	DDRD &= ~(0x02);
	DDRB = 0xFF;
	DDRA = 0x00;
	
	Setup_ADC();
	//Start_ADC();
	
//	Puts(&CLRSCR[0]);
//	Puts(&Menu[0][0]);
	
	sei();
	Menu_Level = 0;	

	while(1)
	{
		if(Data_Status_RX() != 0)
		{
			Choice = Getch_RX();
			if(Choice == '1') // Display set temperature
			{
				Puts(&Menu[1][0]);
				Putch_TX(Temperature);
			}
			else if (Choice == '2') // Adjust Temperature
			{
				Puts("Adjust temperature\ra - increase\rz-decrease\rq - Enter\0");

				while(Input != 'q')
				{
					Puts(Menu[1][0]);
					//Putch_RX(Temperature);
					Input = '0';
					while(Data_Status_RX() == 0)
					{
						asm volatile("nop\n\t"::);
					}

					Input = Getch_RX();
					if(Input == 'a')
					{
						Temperature++;
						while((UCSRA & (1 << UDRE)) == 0){}						
						//UDR = 0x01;
					}
					else if(Input == 'z')
					{
						Temperature--;
						while((UCSRA & (1 << UDRE)) == 0){}
						//UDR = 0x01;
					}
				}
				Input = '0';
				Choice = '0';
				//Puts(&Menu[2][0]);
			}
/*FERDIG?*/	else if (Choice == '3') // Show actual temperature
			{
				Puts(&Menu[3][0]);
				Putch_TX(Measured);		
			}
/*FERDIG*/	else if (Choice == '4') // Enable/Disable Output
			{
				if((Status & 0x01) == 1)
				{
					Status &= ~HEATER; // Turn of heater element
					PORTB &= ~HEATER;
					Puts("\rHeater Disabled\0");
				}
				else
				{
					Status |= HEATER;
					PORTB |= HEATER;
					Puts("\rHeater Enabled\0");
				}
				//Puts(&Menu[4][0]);	
			}

			else if (Choice == '5')
			{
				ADCSRA |= (1 << ADSC);
				Choice = '0';
			}
				
/*FERDIG*/	else if (Choice == '9') // Display level0 menu
			{
				for(cnt = 0; cnt < 5; cnt++)
				{
					Puts(&Menu[cnt][0]);
					Putch_TX("/n/r");
				}
			}
		}
		if(Data_Status_TX() != 0)
		{
			while((UCSRA & (1 << UDRE)) == 0)
			{}
			UDR = Getch_TX();
		}
	}
}


ISR(ADC_vect)
{
	Putch_TX(ADCH);
	Putch_TX(ADCL);
	PORTB = ~PORTB;
}

ISR(USART_RXC_vect)
{
	Putch_RX(UDR);
}

ISR(USART_UDRE_vect)
{
	if(Data_Status_TX() != 0)
	{
		//while((UCSRA & (1 << UDRE)) == 0){}
		UDR = Getch_TX();
	}
	else
	{
		UCSRB &= ~(1<<UDRIE);
	}

}

Buffer source file:

#include "uart_ring.h"


unsigned char Rx_Buffer[RX_BUFFER_SIZE];
unsigned char Tx_Buffer[TX_BUFFER_SIZE];

unsigned int Rx_Put_Point = 0, Rx_Get_Point = 0, Rx_Data_cnt = 0;
unsigned int Tx_Put_Point = 0, Tx_Get_Point = 0, Tx_Data_cnt = 0;


void Putch_RX(unsigned char RX_Byte)
{
	Rx_Buffer[Rx_Put_Point] = RX_Byte;
	
	if(Rx_Put_Point == RX_BUFFER_SIZE)
	{
		Rx_Put_Point = 0;
	}
	else
	{
		Rx_Put_Point++;
	}
	
	Rx_Data_cnt++;
}

unsigned char Getch_RX()
{
	if(Rx_Get_Point == RX_BUFFER_SIZE)
	{
		Rx_Get_Point = 0;
	}
	else
	{
		Rx_Get_Point++;
	}
	Rx_Data_cnt--;

	return Rx_Buffer[Rx_Get_Point-1];
}


void Putch_TX(unsigned char TX_Byte)
{
	Tx_Buffer[Tx_Put_Point] = TX_Byte;
	
	if(Tx_Put_Point == TX_BUFFER_SIZE)
	{
		Tx_Put_Point = 0;
	}
	else
	{
		Tx_Put_Point++;
	}
	Tx_Data_cnt++;
}

void Puts(unsigned char String[0])
{
	unsigned char temp = 'u';
	unsigned int i = 0;
	while(temp != '\0')
	{
		temp = String[i];
		if(temp != '\0')
		{
			Putch_TX(temp);
		}
		i++;
	}
}

unsigned char Getch_TX()
{
	if(Tx_Get_Point == TX_BUFFER_SIZE)
	{
		Tx_Get_Point = 0;
	}
	else
	{
		Tx_Get_Point++;
	}
	Tx_Data_cnt--;
	return Tx_Buffer[Tx_Get_Point-1];
}

unsigned int Data_Status_RX()
{
	return Rx_Data_cnt;
}

unsigned int Data_Status_TX()
{	
	if(Tx_Data_cnt > 0)
	{
		return Tx_Data_cnt;
	}
	else 
	return 0;
}

Here everything works perfectly, but if i remove

      if(Data_Status_TX() != 0)
      {
         while((UCSRA & (1 << UDRE)) == 0)
         {}
         UDR = Getch_TX();
      }

Nothing is transmitted because the interrupt is stopped. The UDRE interrupt also has to be stopped as it will just loop inside it if not(datasheet says so).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1. Read some known working implementations.
You will see that you have to disable the UART interrupts whenever you amend the buffer pointers.

2. It is fatal to call blocking code from inside an interrupt. e.g. the ADC . What happens if the TX buffer is already full? Even if the TX drains, it cannot execute its own ISR()

3. Treat IRQs as flag setting events. And process the flags in your foreground code.

4. Regarding TXC or UDRE, it is up to you. UDRE is simpler, but most importantly copy a known working algorithm.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi David,

1. hmm, never tought of that, but it does make sense when you mention it :)
2/3. Yeah i know, should probably have mentioned that calling those functions is just for testing on my workbench, they will of course be moved to main code when the ADC is working as i want. The amount of data is very small compared to the buffer so for testing i leave it like this, but for the final revision it will be fixed.
4. I have done some searching, but i fail to see the exact solution. I`ll try to go in deeper and study others code more deeply.

Thanks for the reply, really helpful:)