Skip to content

Instantly share code, notes, and snippets.

@RickKimball
Created May 12, 2011 21:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RickKimball/969447 to your computer and use it in GitHub Desktop.
Save RickKimball/969447 to your computer and use it in GitHub Desktop.
Simple USCI UART Test code for msp430-gcc uniarch and msp430g2553 hardware
/**
* config.h - configure baud rates, MCLK frequency
*
* License: Do with this code what you want. However, don't blame
* me if you connect it to a heart pump and it stops. This source
* is provided as is with no warranties. It probably has bugs!!
* You have been warned!
*
* Author: Rick Kimball
* email: rick@kimballsoftware.com
* Version: 1.00 Initial version 05-12-2011
*/
#ifndef CONFIG_H_
#define CONFIG_H_
#define F_CPU 16000000 // use calibrated 16MHZ clock
#ifdef __MSPGCC__
#define _enable_interrupts() __bis_status_register(GIE)
#define _disable_interrupts() __bic_status_register(GIE)
#endif
#endif
#
# Makefile - usci_serial
#
# License: Do with this code what you want. However, don't blame
# me if you connect it to a heart pump and it stops. This source
# is provided as is with no warranties. It probably has bugs!!
# You have been warned!
#
# Author: Rick Kimball
# email: rick@kimballsoftware.com
# Version: 1.00 Initial version 05-12-2011
CC=msp430-gcc
CXX=msp430-g++
MCU=msp430g2553
CFLAGS=-mmcu=$(MCU) -O2 -g -Wall
APP=usci_serial
TARGET=Debug
all: $(TARGET)/$(APP).elf
$(TARGET)/$(APP).elf: $(TARGET)/$(APP).o
$(CC) $(CFLAGS) -o $(TARGET)/$(APP).elf $(TARGET)/$(APP).o
msp430-objdump -DS $(TARGET)/$(APP).elf >$(TARGET)/$(APP).lst
msp430-size $(TARGET)/$(APP).elf
$(TARGET)/$(APP).o: config.h ringbuffer.h $(APP).cpp $(APP).h
$(CC) $(CFLAGS) -c -o $(TARGET)/$(APP).o $(APP).cpp
install:
mspdebug -q --force-reset rf2500 "prog $(TARGET)/$(APP).elf"
clean:
rm -f $(TARGET)/$(APP).o $(TARGET)/$(APP).elf $(TARGET)/$(APP).lst
mkdir -p $(TARGET)/
/*
* ringbuffer.h - template for a circular buffer
*
* License: Do with this code what you want. However, don't blame
* me if you connect it to a heart pump and it stops. This source
* is provided as is with no warranties. It probably has bugs!!
* You have been warned!
*
* Author: Rick Kimball
* email: rick@kimballsoftware.com
* Version: 1.00 Initial version 05-12-2011
*/
#ifndef RINGBUFFER_H_
#define RINGBUFFER_H_
/**
* ringbuffer - a template based interrupt safe circular buffer structure with functions
*/
template<typename T, int MAX_ITEMS>
struct ringbuffer {
volatile int head;
volatile int tail;
volatile T buffer[MAX_ITEMS];
/**
* empty() - checks the buffer for data
*
* returns true if empty, false if there is data
*/
inline bool empty() {
bool isEmpty;
_disable_interrupts(); // prevent inconsistent reads
isEmpty = (head == tail);
_enable_interrupts();
return isEmpty;
}
/**
* push_back() - append a byte to the buffer is possible
* assumed to be called from the recv interrupt
*/
inline void push_back(T c) {
int i = (unsigned int) (head + 1) % MAX_ITEMS;
if (i != tail) {
buffer[head] = c;
head = i;
}
}
/**
* pop_front() - remove a value from front of ring buffer
*/
inline T pop_front() {
T c = -1;
_disable_interrupts(); // disable interrupts to protect head and tail values
// This prevents the RX_ISR from modifying them
// while we are trying to read and modify
// if the head isn't ahead of the tail, we don't have any characters
if (head != tail) {
c = (T) buffer[tail];
tail = (unsigned int) (tail + 1) % MAX_ITEMS;
}
_enable_interrupts(); // ok .. let everyone at them
return c;
}
};
typedef ringbuffer<uint8_t, 16> ringbuffer_ui8_16; // ringbuffer, max of 16 uint8_t values
typedef ringbuffer<uint8_t, 32> Ringbuffer_uint8_32; // ringbuffer, max of 32 uint8_t values
#endif /* RINGBUFFER_H_ */
/**
* usci_serial.cpp - simple example using USCI UART + ringbuffer + command line monitor
*
* This code was written to test the new uniarch version of msp430-gcc. I wanted
* to make sure it could generate code for the msp430g2553 running on the TI
* launchpad.
*
* This code mplements a command line interface over the USB-CDC serial at
* 9600-8-N-1. To test you must swap the RX/TX pins on your launchpad to use
* the hardware USCI UART. I disconnected those jumpers on my launchpad and used
* a couple of F-M jumper wires to run the msp430g2553 from a breadboard.
* P1.1=RXD and P1.2=TXD ( this is the opposite of the msp430g2231 default setup )
*
* * License: Do with this code what you want. However, don't blame
* me if you connect it to a heart pump and it stops. This source
* is provided as is with no warranties. It probably has bugs!!
* You have been warned!
*
* Author: Rick Kimball
* email: rick@kimballsoftware.com
* Version: 1.00 Initial version 05-12-2011
*/
#include <msp430.h>
#include <legacymsp430.h>
#include <stdint.h>
#include "config.h"
#include "ringbuffer.h"
#include "usci_serial.h"
/**
* create a ring buffer that holds up to 16 uint8_t bytes
*
* Note: you could change the ringbuffer_ui8_16 typedef to
* make it smaller or larger, just be consistent with what
* you provide the Serial template
*/
ringbuffer_ui8_16 usci_buffer = { 0, 0, { 0 } };
Serial<ringbuffer_ui8_16> usci0 = { usci_buffer };
/**
* USCI0RX_ISR - USCI UART receive character ISR handler
*
* we get an interrupt when a new character arrives via
* the USCI UART receive pin. We just stuff it into
* our buffer and let the main routine consume it.
*/
interrupt(USCIAB0RX_VECTOR) USCI0RX_ISR(void) {
/**
* Note: a side effect of reading UCA0RXBUF
* is the rx interrupt flag is cleared
*/
usci_buffer.push_back(UCA0RXBUF);
}
/**
* main - echo back to the user whatever they type
*/
int main(void) {
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
BCSCTL1 = CALBC1_16MHZ; // set DCO clock for MCLK and SMCLK
DCOCTL = CALDCO_16MHZ;
usci0.init();
__bis_SR_register(GIE); // interrupts enabled
usci0.xmit("\r\nMSP430G2553 Monitor\r\n$ ");
while (true) {
while (!usci0.empty()) {
volatile int c;
c = usci0.recv();
usci0.xmit((uint8_t) c);
}
}
}
#ifndef HW_SERIAL_H
#define HW_SERIAL_H
/**
* Serial - simple access to USCI UART hardware
* code implements interrupt driven input
* and poll driven output.
*
* License: Do with this code what you want. However, don't blame
* me if you connect it to a heart pump and it stops. This source
* is provided as is with no warranties. It probably has bugs!!
* You have been warned!
*
* Author: Rick Kimball
* email: rick@kimballsoftware.com
* Version: 1.00 Initial version 05-12-2011
*/
template<typename T_STORAGE>
struct Serial {
T_STORAGE &_recv_buffer;
/**
* init - setup the USCI UART hardware for 9600-8-N-1
* P1.1 = RX PIN, P1.2 = TX PIN
*/
inline void init() {
P1SEL = BIT1 + BIT2; // P1.1=RXD, P1.2=TXD
P1SEL2 = BIT1 + BIT2; // P1.1=RXD, P1.2=TXD
UCA0CTL1 |= UCSSEL_2; // use SMCLK for USCI clock
UCA0BR0 = 130; // 16MHz 9600
UCA0BR1 = 6; // 16MHz 9600
UCA0MCTL = UCBRS1 + UCBRS0; // Modulation UCBRSx = 3
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
IE2 |= UCA0RXIE; // Enable USCI0RX_ISR interrupt
}
inline bool empty() {
return _recv_buffer.empty();
}
inline int recv() {
return _recv_buffer.pop_front();
}
void xmit(uint8_t c) {
while (!(IFG2 & UCA0TXIFG))
; // USCI_A0 TX buffer ready?
UCA0TXBUF = (uint8_t) c; // TX -> RXed character
}
void xmit(const char *s) {
while (*s) {
xmit((uint8_t) *s);
++s;
}
}
};
#endif /* HW_SERIAL_H */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment