Hi,
I'm new to this forum, so I'll do my best to describe my problem:
The code below uses interrupts to receive the longest strings possible. It puts its content inside a linked list buffer, then transfers that content to a second linked list buffer when it receives a EOL, and finally transmits the content of this last buffer.
My problem is that when I send +20 long strings, the USART hangs. ¿Is there a way to optimize this code and solve that problem? I think it may be related to an incompatible pointer type in the functions byerx and byetx that erase each linked list.
Note: The linked lists are defined in a header file, and the code itself is started from the execution of USART_Init. I'm using PuTTY for Windows to test the USART.
I'm new to this forum, so I'll do my best to describe my problem:
The code below uses interrupts to receive the longest strings possible. It puts its content inside a linked list buffer, then transfers that content to a second linked list buffer when it receives a EOL, and finally transmits the content of this last buffer.
My problem is that when I send +20 long strings, the USART hangs. ¿Is there a way to optimize this code and solve that problem? I think it may be related to an incompatible pointer type in the functions byerx and byetx that erase each linked list.
Note: The linked lists are defined in a header file, and the code itself is started from the execution of USART_Init. I'm using PuTTY for Windows to test the USART.
Code:
// includes
#define F_CPU 16000000UL // MCU Clock Speed - needed for baud rate value computation
#define TX_BUFFLEN 30 // Send buffer size
#define RX_BUFFLEN 30 // Receive buffer size
// includes
#include <avr/io.h>
#include <avr/interrupt.h>
#include <string.h>
#include <stdlib.h>
#include "USART_implement_me.h"
char rx_buffer[10];
volatile uint8_t portbhistory = 0; // default is high because the pull-up
void pushtx(volatile struct node_tx ** head, int val) {
/* now we can add a new variable */
struct node_tx * new_node = (struct node_tx*)malloc(sizeof(struct node_tx));
volatile struct node_tx *last = *head; /* used in step 5*/
/* 2. put in the data */
new_node->val = val;
/* 3. This new node is going to be the last node, so make next
of it as NULL*/
new_node->next = NULL;
/* 4. If the Linked List is empty, then make the new node as head */
if (*head == NULL)
{
*head = new_node;
return;
}
/* 5. Else traverse till the last node */
while (last->next != NULL)
last = last->next;
/* 6. Change the next of last node */
last->next = new_node;
return;
}
void pushrx(volatile struct node_rx ** head, int val) {
/* now we can add a new variable */
struct node_rx * new_node = (struct node_rx*)malloc(sizeof(struct node_rx));
volatile struct node_rx *last = *head; /* used in step 5*/
/* 2. put in the data */
new_node->val = val;
/* 3. This new node is going to be the last node, so make next
of it as NULL*/
new_node->next = NULL;
/* 4. If the Linked List is empty, then make the new node as head */
if (*head == NULL)
{
*head = new_node;
return;
}
/* 5. Else traverse till the last node */
while (last->next != NULL)
last = last->next;
/* 6. Change the next of last node */
last->next = new_node;
return;
}
// The initialisation function. Call it once from your main() program before
// issuing any USART commands with the functions below!
//
// Call it at any time to change the USART communication parameters.
//
// Returns zero in case of success, non-zero for errors.
uint8_t USART_Init(struct USART_configuration config)
{
DDRD = (1 << DDB5);
// You can recycle your previous code. But remember, this time you are
// supposed to configure interrupts! Maybe you]ll have to extend it a little bit?
unsigned int ubrr = F_CPU/16/config.baudrate-1;
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/*Enable receiver and transmitter */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, 2stop bit */
DDRB &= ~(1 << DDB0); // Clear the PB0 pin
// PB0 (PCINT0 pin) is now an input
PORTB |= (1 << PORTB0); // turn On the Pull-up
// PB0 is now an input with pull-up enabled
PCICR |= (1 << PCIE0); // set PCIE0 to enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); // set PCINT0 to trigger an interrupt on state change
//UCSR0B |=
/* interrupt on receive */
//(1 << TXCIE0);
UCSR0B |=
///* interrupt on send */
(1 << RXCIE0);
UCSR0B |=
///* interrupt on send */
(1 << UDRIE0);
volatile struct node_rx * headd = NULL;
headd = (struct node_rx*)malloc(sizeof(struct node_rx));
if (headd == NULL) {
USART_Transmit_char('e');
return 1;
}
//headd->val = ' ';
//headd->next = NULL;
volatile struct node_tx * head = NULL;
head = (struct node_tx*)malloc(sizeof(struct node_tx));
if (head == NULL) {
USART_Transmit_char('e');
return 1;
}
//head->val = ' ';
//head->next = NULL;
if (config.databits == 8)
{
UCSR0C |= (1<<USBS0);
}
else if (config.databits == 7){
UCSR0C |= (0<<USBS0);
}
else if (config.databits == 9){
//Activates 9th data bit
UCSR0C |= (1<<USBS0);
UCSR0B |= (1 << UCSZ02);
}
else {
return 1;
}
if (config.stopbits == 1){
UCSR0C|= (1<<UCSZ00);
}
else if (config.stopbits == 2) {
UCSR0C|= (3<<UCSZ00);
}
else {
return 1;
}
if (config.parity == 1) {
UCSR0C |= (1 << UPM01);
}
else if (config.parity == 2) {
UCSR0C |= (1 << UPM01);
UCSR0C |= (1 << UPM00);
} else if (config.parity != 0) {
return 1;
}
sei(); // turn on interrupts
while(1);
return 0;
}
// Transmits a single character
void USART_Transmit_char(uint8_t data)
{
/* Wait for empty transmit buffer */
while ( !( UCSR0A & (1<<UDRE0)) )
;
/* Put data into buffer, sends the data */
UDR0 = data;
}
/* Function to delete the entire linked list */
void byetx(struct node_tx** head_ref)
{
/* deref head_ref to get the real head */
struct node_tx* current = *head_ref;
struct node_tx* next;
while (current != NULL)
{
next = current->next;
free(current);
current = next;
}
/* deref head_ref to affect the real head back
in the caller. */
*head_ref = NULL;
}
/* Function to delete the entire linked list */
void byerx(struct node_rx ** head_ref)
{
/* deref head_ref to get the real head */
struct node_rx* current = *head_ref;
struct node_rx* next;
while (current != NULL)
{
next = current->next;
free(current);
current = next;
}
/* deref head_ref to affect the real head back
in the caller. */
*head_ref = NULL;
}
ISR (PCINT0_vect)
{
USART_Transmit_char('r');
/* interrupt code here */
if ( (PINB & (1 << PINB0)) == 1 ) {
portbhistory = 0;
USART_Transmit_char('L');
PORTB |= (1<<PORTB0);
}
else {
portbhistory = 1;
USART_Transmit_char('H');
PORTB &= ~(1<<PORTB0);
}
}
ISR(USART_RX_vect)
{
//PORTB ^= (1 << PORTB5);
volatile uint8_t u8temp;
u8temp=UDR0;
//USART_Transmit_char(u8temp);
int value;
pushrx(&headd, u8temp);
if (u8temp == '\r'){
//volatile node_tx * current = head;
volatile struct node_rx * curr = headd;
while ((curr) != NULL) { // set curr to head, stop if list empty.
value = curr->val;
pushtx(&head, value);
curr = curr->next; // advance head to next element.
//free(curr->val);
}
byerx(headd);
//disable reception and RX Complete interrupt
UCSR0B &= ~((1<<RXEN0)|(1<<RXCIE0));
//enable transmission and UDR0 empty interrupt
UCSR0B |= (1<<TXEN0)|(1<<UDRIE0);
}
}
ISR(USART_UDRE_vect)
{
volatile char ch;
volatile struct node_tx * current = head;
while (current != NULL) {
//printf("%d\n", current->val);
ch = current->val; //pop(&head);
USART_Transmit_char(ch);
//free(current);
//USART_Transmit_char('c');
//USART_Transmit_char(current->val);
current = current->next;
//free(current);
}
if (ch == '\r'){
byetx(&head);
//enable reception and RX Complete interrupt
UCSR0B |= ((1<<RXEN0)|(1<<RXCIE0));
//disable transmission and UDR0 empty interrupt
UCSR0B &= ~(1<<TXEN0)|(1<<UDRIE0);
}
}