blob: 31fda9d06c102d8b2916b677acf27c3f2d9ca217 [file] [log] [blame]
/*
* ======== SysUart.c ========
*/
#include <xdc/runtime/Startup.h>
#include "package/internal/SysUart.xdc.h"
#define USE_8MHZ 1
#define RED 0x01
#define GREEN 0x02
#define FOREVER -1
static void etx();
static void flash(Int color, Int period, Int count);
static void init(void);
static void myPutc(Char ch);
/*
* ======== SysUart_Module_startup ========
*/
Int SysUart_Module_startup(Int state)
{
init();
return (Startup_DONE);
}
/*
* ======== SysUart_abort ========
*/
Void SysUart_abort(String str)
{
if (str != NULL) {
Char ch;
while ((ch = *str++) != '\0') {
SysUart_putch(ch);
}
}
flash(RED, FOREVER, FOREVER);
etx();
}
/*
* ======== SysUart_exit ========
*/
Void SysUart_exit(Int stat)
{
flash(GREEN, FOREVER, FOREVER);
etx();
}
/*
* ======== SysUart_flush ========
*/
Void SysUart_flush()
{
}
/*
* ======== SysUart_putch ========
*/
Void SysUart_putch(Char ch)
{
myPutc(ch);
}
/*
* ======== SysUart_ready ========
*/
Bool SysUart_ready()
{
return (TRUE);
}
/*
* ======== atexit ========
* The TI RTS library's atexit() implementation requires a _huge_ amount of
* data. We stub it out here and replace exit() and abort() with functions
* that are sufficient for the proper operation of xdc.runtime.System.
*/
int atexit(void (*fxn)(void))
{
return (0);
}
/*
* ======== abort ========
* See atexit() above
*/
void abort(void)
{
/* Define C$$EXIT label because TI debugger uses this to know when
* programs terminate. This can be removed if the debugger is not
* used.
*/
__asm(" .global C$$EXIT");
__asm("C$$EXIT: nop");
for (;;); /* spin forever */
}
/*
* ======== exit ========
* See atexit() above
*/
void exit(int status)
{
SysUart_exit(status);
}
/*
* ======== etx ========
* Flush HW TX buffers
*/
static void etx()
{
myPutc(4); /* ascii EOT */
myPutc(0);
myPutc(0);
abort();
}
#if 0
/* standard header assumes linker command file definitions */
#include <ti/apps/msp430/msp430x22x4.h>
#else
/* "pure-C" definitions below are sufficient for this module */
#define IE2 (*(volatile int8_t *)0x0001) /* 8-bit */
#define IFG2 (*(volatile int8_t *)0x0003) /* 8-bit */
#define DCOCTL (*(volatile int8_t *)0x0056) /* 8-bit */
#define BCSCTL1 (*(volatile int8_t *)0x0057) /* 8-bit */
#define BCSCTL3 (*(volatile int8_t *)0x0053) /* 8-bit */
#define CALDCO_8MHZ (*(volatile int8_t *)0x10FC) /* 8-bit */
#define CALBC1_8MHZ (*(volatile int8_t *)0x10FD) /* 8-bit */
#define P1OUT (*(volatile int8_t *)0x0021) /* 8-bit */
#define P1DIR (*(volatile int8_t *)0x0022) /* 8-bit */
#define P3SEL (*(volatile int8_t *)0x001B) /* 8-bit */
#define UCA0CTL1 (*(volatile int8_t *)0x0061) /* 8-bit */
#define UCA0BR0 (*(volatile int8_t *)0x0062) /* 8-bit */
#define UCA0BR1 (*(volatile int8_t *)0x0063) /* 8-bit */
#define UCA0MCTL (*(volatile int8_t *)0x0064) /* 8-bit */
#define UCA0RXBUF (*(volatile int8_t *)0x0066) /* 8-bit */
#define UCA0TXBUF (*(volatile int8_t *)0x0067) /* 8-bit */
#define WDTCTL (*(volatile int16_t *)0x120) /* 16-bit */
/* status register bits */
#define GIE (0x0008)
#define CPUOFF (0x0010)
#define LPM0_bits (CPUOFF)
/* watch dog timer control register bit names */
#define WDTPW (0x5A00)
#define WDTHOLD (0x0080)
#define LFXT1S_2 (0x20) /* Mode 2 for LFXT1 : VLO */
#define UCSSEL_2 (0x80) /* USCI 0 Clock Source: 2 */
#define UCBRS_2 (0x04) /* USCI Second Stage Modulation Select 1 */
#define UCSWRST (0x01) /* USCI Software Reset */
#define UCA0RXIE (0x01) /* USCI rx interrupt enable */
/* IFG2 bits */
#define UCA0TXIFG (0x02) /* USCI tx flag bit */
#endif
/*
* ======== init ========
*/
static void init(void)
{
WDTCTL = WDTPW + WDTHOLD; /* Stop watchdog timer */
P1DIR |= 0x03; /* Set P1.0,1 to output direction */
P1OUT = 0; /* turn off LEDs */
#if USE_8MHZ
/* delay loop to ensure proper startup before increasing the DCO from the
* reset startup value of 1MHz.
* This is typically tailored to the power supply used, and in this case
* is overkill for safety due to wide distribution.
*/
{volatile int i; for (i = 0; i < 0xFFFF; i++){}}
BCSCTL1 = CALBC1_8MHZ; /* Set DCO to the default of Simpliciti */
DCOCTL = CALDCO_8MHZ;
BCSCTL3 |= LFXT1S_2; /* LFXT1 = VLO */
#else
BCSCTL1 = CALBC1_1MHZ; /* Set DCO to 1MHz */
DCOCTL = CALDCO_1MHZ;
#endif
/* init the UART (see Table 15-4, Section 15.3.13 MSP430 User's guide) */
P3SEL = 0x30; /* P3.4,5 = USCI_A0 TXD/RXD */
UCA0CTL1 = UCSSEL_2; /* SMCLK */
#if USE_8MHZ
UCA0BR0 = 0x41; /* 8MHz DCO 9600 (UCBRx = 833) */
UCA0BR1 = 0x03; /* 8MHz DC0 9600 */
UCA0MCTL = UCBRS_2; /* 8MHz DC0 Modulation (UCBRSx = 2: UCOS16 = 0, UCBRFx = 0) */
#else
UCA0BR0 = 104; /* 1MHz DC0 9600 (@8MHz 9600, use 0x41) */
UCA0BR1 = 0; /* 1MHz DC0 9600 (@8MHz 9600, use 0x03) */
UCA0MCTL = UCBRS0; /* 1MHz DC0 Modulation (UCBRSx = 1: UCOS16 = 0, UCBRFx = 0) */
#endif
UCA0CTL1 &= ~UCSWRST; /* Initialize USCI state machine */
IE2 |= UCA0RXIE; /* Enable USCI_A0 RX interrupt */
flash(GREEN, 50, 4); /* indicate the init is done */
}
/*
* ======== flash ========
*/
static void flash(Int color, Int period, Int count)
{
if (period == FOREVER) {
P1OUT |= color;
return;
}
while (count) {
volatile unsigned int i; /* volatile to prevent optimization */
P1OUT ^= color; /* toggle P1.1,0 using exclusive-OR */
for (i = period * 1000; i != 0; i--) { /* delay period */
;
}
if (count > 0) { /* if count starts < 0, go forever */
count--;
}
}
}
/*
* ======== myPutc ========
*/
static void myPutc(Char ch)
{
while (!(IFG2 & UCA0TXIFG)) { /* USCI_A0 TX buffer ready? */
;
}
UCA0TXBUF = ch; /* TX -> ch */
}
/*
* ======== USCI0RX_ISR ========
*/
__interrupt void USCI0RX_ISR(void)
{
char c;
c = UCA0RXBUF; /* read the character */
if (SysUart_getLineFxn == NULL) {
return;
}
if (SysUart_lineBuf == NULL) {
SysUart_getLineFxn(&c, 1);
return;
}
if (c == '\n') {
SysUart_lineBuf[module->lineIdx] = 0;
SysUart_getLineFxn(SysUart_lineBuf, module->lineIdx);
module->lineIdx = 0;
}
else if (module->lineIdx < SysUart_lineSize) {
SysUart_lineBuf[module->lineIdx++] = c;
}
}
__asm("\t.global USCI0RX_ISR");
__asm("\t.sect \".usci_rx\"");
__asm("\t.align 2");
__asm("_USCI0_rx_vector:\n\t.field USCI0RX_ISR, 16");