Project Objective: Develop an open source AIS Alarm that alerts sailors that a new marine vessel with AIS is within range

 

This post will add 38400 baud UART to the existing code and test it.

/*
 * dAISy_Alarm_V002 - adds UART at 38400 baud
 * dAISy_Alarm_V001 - implements millisecond timer and blinks LED
 *
 * MCLK, SCLK set to 8 MHz
 * ACLK set to 32768 Hz
 * Milliseconds counted on timer B0
 * UART at 38400 baud
 *
 * Frank Milburn    30 December 2017
 * Developed on MSP430FR2111 with CCS V7.2, compiler TIv17.9.0.STS
 */
#include "driverlib.h"
// Miscellaneous
#define DEBUG                 2                // 0 = no debug, 1...3 is increasing debug
// Clock and Timer related definitions
#define TIMER_UP_COUNT        8000             // approximately 1 millisecond @ 8 MHz
#define MCLK_FREQ_MHZ         8                // master clock frequency
// GPIO related definitions
#define LED_WARN  GPIO_PORT_P1,GPIO_PIN0       // warning LED
#define TX_PIN    BIT7                         // TX pin is P1.7
#define RX_PIN    BIT6                         // RX pin is P1.6
// Function prototypes
void initClocks(void);                         // initialize clocks
void initGPIO(void);                           // initialize GPIO
void initTimerB0(void);                        // initialize timer B0
void initUART(void);                           // initialize UART
unsigned long milliSecs(void);                 // returns milliseconds since counter started
// Global variable declarations
const unsigned long BEEP_LEN  = 10;            // beep length in milliseconds
volatile unsigned long MILLIS = 0;             // running count of milliseconds
volatile unsigned char RXData = 0;             // for testing only                   REMOVE
volatile unsigned char TXData = 1;             // for testing only                   REMOVE
int main(void) {

    WDT_A_hold(WDT_A_BASE);                    // stop the watch dog
    PMM_unlockLPM5();                          // activate port settings after power on
    initClocks();
    initGPIO();
    initTimerB0();
    initUART();
    __bis_SR_register(GIE);                    // globally enable interrupts
    for(;;){
        TXData = 0;
        int i;
        for(i = 0; i < 255; i++){
            TXData += 1;                       // Increment TX data and transmit
            EUSCI_A_UART_transmitData(EUSCI_A0_BASE, TXData);
            while(EUSCI_A_UART_queryStatusFlags(EUSCI_A0_BASE,EUSCI_A_UART_BUSY)){
                // Wait until complete
            }
        }
    }
}
// -------------------------------------------------------------------------------------
void initClocks(void){
    __bis_SR_register(SCG0);                    // disable FLL
    CSCTL3 |= SELREF__REFOCLK;                  // Set REFO as FLL reference source
    CSCTL1 = DCOFTRIMEN_1 | DCOFTRIM0
                          | DCOFTRIM1
                          | DCORSEL_3;          // DCOFTRIM=3, DCO Range = 8MHz
    CSCTL2 = FLLD_0 + 243;                      // DCODIV = 8MHz
    __delay_cycles(3);
    __bic_SR_register(SCG0);                    // enable FLL
    CSCTL4 = SELMS__DCOCLKDIV | SELA__REFOCLK;  // set default REFO(~32768Hz) as
                                                // ACLK source, ACLK = 32768Hz
                                                // default DCODIV as MCLK, SMCLK source
}
// -------------------------------------------------------------------------------------
void initGPIO(void){
    GPIO_setAsOutputPin(LED_WARN);
    GPIO_setOutputLowOnPin(LED_WARN);
    P1SEL0 |= TX_PIN | RX_PIN;                  // UART per Table 6-34 of datasheet
}
// -------------------------------------------------------------------------------------
unsigned long milliSecs(void){
    return MILLIS;                              // return milliseconds
}
// -------------------------------------------------------------------------------------
void initTimerB0(void){
    TB0CCTL0 |= CCIE;                            // TBCCR0 interrupt enabled
    TB0CCR0 = TIMER_UP_COUNT;                    // approx 1 millisecond
    TB0CTL |= TBSSEL__SMCLK | MC__UP;            // SMCLK, Up mode
}
// -------------------------------------------------------------------------------------
void initUART(void){
    // Set baud rate to 38400 using parameters in table 21-5 of the Family User Gude
    // UCBRx = 13, UCBRFx = 0, UCBRSx = 0x84, UCOS16 = 1
    // Expected error from the table is:    TX neg    TX pos    RX neg   RX pos
    //                                       -0.32     0.32      -0.64    0.48
    EUSCI_A_UART_initParam param = {0};
    param.selectClockSource = EUSCI_A_UART_CLOCKSOURCE_SMCLK;
    param.clockPrescalar = 13;                                            // UCBRx
    param.firstModReg = 0;                                                // UCBRFx
    param.secondModReg = 0x84;                                            // UCBRSx
    param.parity = EUSCI_A_UART_NO_PARITY;
    param.msborLsbFirst = EUSCI_A_UART_LSB_FIRST;
    param.numberofStopBits = EUSCI_A_UART_ONE_STOP_BIT;
    param.uartMode = EUSCI_A_UART_MODE;
    param.overSampling = EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION;   // UCOS16 = 1
    if(STATUS_FAIL == EUSCI_A_UART_init(EUSCI_A0_BASE, ¶m))
    {
        GPIO_setOutputHighOnPin(LED_WARN);
        return;
    }
    //Enable UART module for operation
    EUSCI_A_UART_enable(EUSCI_A0_BASE);
    //Enable Receive Interrupt
    EUSCI_A_UART_clearInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);
    EUSCI_A_UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);
}
// -------------------------------------------------------------------------------------
// Timer B0 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = TIMER0_B0_VECTOR
__interrupt void Timer_B (void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(TIMER0_B0_VECTOR))) Timer_B (void)
#else
#error Compiler not supported!
#endif
{
    MILLIS++;
}
// -------------------------------------------------------------------------------------
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
    switch(__even_in_range(UCA0IV,USCI_UART_UCTXCPTIFG))
    {
    // Vector 2 - RXIFG - Flag error if RX does not equal TX
    case USCI_UART_UCRXIFG:
            RXData = EUSCI_A_UART_receiveData(EUSCI_A0_BASE);
            if(RXData != TXData) {
                GPIO_setOutputHighOnPin(LED_WARN);   // turn on red LED
                while(1);                            // loop forever
            }
            break;
        default: break;
    }
}

I have had problems implementing UART on the MSP430 before but I must be living right because it pretty much worked first time.  The primary addition is the function initUART().  dAISy can operate at 4800, 9600, 38400 baud - set at 38400 baud here.   The parameters for 38400 baud are taken from table 21-5 in the User Family Guide.

 

The TX pin on the microcontroller is jumpered to the RX pin.  In main() there is a for loop that increments the variable TXData from 0 to 255 over and over again.  TXData is sent over UART to the RX pin on the microcontroller and tested in the ISR that captures received characters.  If the received character is not the same as the transmitted character then a LED is lit and execution is trapped. 

 

This is the first test to see if things are working as expected.  If the jumper is removed, the LED should light up.  Since the microcontroller is using the same clock for TX and RX this may not seem a particularly rigorous test given that UART is asynchronous.  The clock has been tested though and is reasonably accurate and provided the other devices it is communicating with are reasonably accurate it should be OK.  The expected accuracy from the data sheet has been noted in the comments.

 

The second test is to set a breakpoint in debug at line 140 (where RXData is tested against TXData in the ISR).  The two variables can then be examined as the program steps through as shown below.

UART Debug Window

The variables are seen to be equivalent in the upper right hand window with the Expressions tab open.  Test passed.

 

The memory usage should also be noted in the Console at lower left.  FRAM usage is 1278 bytes and RAM is 290 bytes.  Remember that there is a bit less than 4 k of FRAM available and that approximately 2 k is desired for the AIS message ring buffer.  I am still hopeful it will fit comfortably.  If not, there is Plan B which could mean using a different member of the MSP430FRxx family for the microcontroller.

 

For a final test the logic analyzer was hauled out again to check if it is seeing the character sequence that is expected.

Logic Analyzer 38400 baud UART Test

Third test passed.

 

The next post should be a bit more interesting.  The dAISy receiver will be connected to the prototype and a test devised to assure that AIS sentences are received correctly.

 

Past Posts from this Project:

AIS Alarm

AIS Alarm - The Process

AIS Alarm - Prototype Hardware

AIS Alarm - Timers and GPIO

AIS Alarm - Prototype Code Outline

 

References and Links:

WEGMATT LLC - dAISy AIS Receiver - low cost AIS receiver

Texas Instruments MSP430FR2xx FRAM Microcontrollers - Post No. 4

TI MSP430FR2111