Skip to content

Instantly share code, notes, and snippets.

@osvein
Last active August 29, 2015 14:25
Show Gist options
  • Select an option

  • Save osvein/fb4d7b863e76e40c6161 to your computer and use it in GitHub Desktop.

Select an option

Save osvein/fb4d7b863e76e40c6161 to your computer and use it in GitHub Desktop.
USART with stdio and flow control for the AVR
/*
* Spor - real-time tracking using GPS and SMS
* Copyright (C) 2015 Oskar Sveinsen
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <avr/sfr_defs.h>
#include "usart.h"
static inline char *put_head_(struct usart_buf *);
static inline char *get_tail_(struct usart_buf *);
FILE usart_stream = FDEV_SETUP_STREAM(usart_putc, usart_getc, _FDEV_SETUP_RW);
FILE *usart_open(struct usart_mmap mmap, unsigned int ubrr, bool u2x, struct usart_flowctl flowctl, struct usart_buf buf_rx, struct usart_buf buf_tx) {
usart_mmap = mmap;
*(usart_mmap.ubrrl) = (char)ubrr;
*(usart_mmap.ubrrh) = (char)(ubrr >> 8);
if (u2x) {
*(usart_mmap.ucsra) |= _BV(U2X);
}
else {
*(usart_mmap.ucsra) &= ~_BV(U2X);
}
usart_flowctl = flowctl;
usart_buf_rx = buf_rx;
usart_buf_tx = buf_tx;
return &usart_stream;
}
FILE *usart_open(struct usart_mmap mmap, unsigned int ubrr, bool u2x, struct usart_flowctl flowctl) {
return usart_open(mmap, ubrr, u2x, flowctl, usart_buf_null, usart_buf_null);
}
FILE *usart_open(struct usart_mmap mmap, unsigned int ubrr, bool u2x) {
return usart_open(mmap, ubrr, u2x, usart_flowctl_null, usart_buf_null);
}
FILE *usart_open(struct usart_mmap mmap) {
unsigned int ubrr = *(mmap.ubrrl) | (*(mmap.ubrrh) << 8);
bool u2x = (*(mmap.ucsra) & _BV(U2X)) ? true : false;
return usart_open(mmap, ubrr, u2x);
}
int usart_getc(FILE *stream) {
if (usart_buf_rx.limit_tail != NULL) {
return *((usart_buf_rx.tail)++);
}
else {
loop_until_bit_is_set(*(usart_mmap.ucsra), 7);
return *(usart_mmap.udr);
}
}
int usart_putc(char c, FILE *stream) {
if (usart_buf_tx.limit_tail != NULL) {
*(++(usart_buf_tx.head)) = c;
}
else {
loop_until_bit_is_set(*(usart_mmap.ucsra), 5);
*(usart_mmap.udr) = c;
}
return c;
}
ISR(USART_RX_vect) {
if (usart_buf_rx.limit_tail != NULL) {
*(++(usart_buf_rx.head)) = *(usart_mmap.udr);
}
}
ISR(USART_UDRE_vect) {
if (usart_buf_tx.limit_tail != NULL) {
if (usart_buf_rx.tail > usart_buf_rx.limit_head) {
usart_buf_rx.tail = usart
}
*(usart_mmap.udr) = *((usart_buf_rx.tail)++);
}
}
char *put_head_(struct usart_buf *buf) {
buf->head++;
if (buf->head > buf->limit_head || buf->head < buf->limit_tail) {
buf->head = buf->limit_tail;
}
return *(buf->head);
}
char *get_tail_(struct usart_buf *buf) {
char c = *(buf->tail++);
if (buf->tail > buf->limit_head || buf->tail < buf->limit_tail) {
buf->tail = buf->limit_tail;
}
return c;
}
/*
* Spor - real-time tracking using GPS and SMS
* Copyright (C) 2015 Oskar Sveinsen
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef USART_H
#define USART_H
#ifdef __cplusplus
extern "C" {
#endif
struct usart_mmap {
char *udr; // USART I/O Data Register n
char *ucsra; // USART Control and Status Register n A
char *ucsrb; // USART Control and Status Register n B
char *ucsrc; // USART Control and Status Register n C
char *ubrrh; // USART Baud Rate Registers - high byte
char *ubrrl; // USART Baud Rate Registers - low byte
};
struct usart_flowctl {
char mode; // flow control mode
#define USART_FLOWCTL_MODE_NULL 0x0
#define USART_FLOWCTL_MODE_SOFT 0x5
#define USART_FLOWCTL_MODE_HARD (USART_FLOWCTL_MODE_SOFT << 1)
#define USART_FLOWCTL_MODE_ALL (USART_FLOWCTL_MODE_SOFT | USART_FLOWCTL_MODE_HARD)
#define USART_FLOWCTL_MODE_TX 0x3
#define USART_FLOWCTL_MODE_RX (USART_FLOWCTL_MODE_TX << 2)
char soft_resume; // software flow control character to resume flow
char soft_stop; // software flow control character to stop flow
bool (*hard_get)(void); // get hardware transmit flow control
void (*hard_set)(bool); // set hardware receive flow control
};
extern struct usart_flowctl usart_flowctl_null = {
.mode = USART_FLOWCTL_MODE_NULL,
};
struct usart_buf {
char *limit_tail;
char *limit_head;
char *tail;
char *head;
};
extern struct usart_buf usart_buf_null = {
.limit_tail = NULL,
};
FILE *usart_open(struct usart_mmap, unsigned int ubrr, bool u2x, struct usart_flowctl, struct usart_buf buf_rx, struct usart_buf buf_tx);
FILE *usart_open(struct usart_mmap, unsigned int ubrr, bool u2x, struct usart_flowctl);
FILE *usart_open(struct usart_mmap, unsigned int ubrr, bool u2x);
FILE *usart_open(struct usart_mmap);
void usart_putc(char, FILE *);
void usart_getc(FILE *);
extern const FILE usart_stream;
extern struct usart_mmap usart_mmap;
extern struct usart_flowctl usart_flowctl;
extern struct usart_buf usart_buf_rx;
extern struct usart_buf usart_buf_tx;
#ifdef __cplusplus
} // extern "C"
#endif
#endif // USART_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment