Skip to content

Instantly share code, notes, and snippets.

@RickKimball
Created January 3, 2012 20:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RickKimball/1556906 to your computer and use it in GitHub Desktop.
Save RickKimball/1556906 to your computer and use it in GitHub Desktop.
msp430 serial tool kit software/usci/timera/spi implementations
/**
* main.cpp - swserial/timerserial/usciserial Serial Asynch test driver.
*
* To test: use putty and connect to /dev/ttyACM0 at 9600 Baud
*
*/
#include <msp430.h>
#include <stdio.h>
#include "serial.h"
#define MCLK_FREQ 16000000UL /* run @16MHz */
/**
* typedef Serial - start of a simple serial wrapper class
*/
typedef struct {
/**
* begin() - initialize serial port, sets registers, port direction, and
* alternative port features as required by implementing serial routines.
* Depending on the implementing method, you may not be able to use
* arbitrary rx/tx pins the software only implementation is the only
* version capable of using any arbitrary pin.
*
* baudRate - bits/sec default: 9600
* rxPin - receive pin default: 1 (P1.1) ( g2553 defaults )
* txPin - transmit pin default: 2 (P1.2)
*/
static void begin(uint32_t baud = 9600, int rxPin = 1, int txPin = 2) {
init_serial(1 << txPin, 1 << rxPin, MCLK_FREQ / baud, (MCLK_FREQ / baud) >> 8);
}
/**
* puts - writes the string s to the serial output stream without a trailing
* newline character. Note: this differs from the ISO standard puts()
* function which appends a newline character.
*/
static void puts(register const char *s) {
while(*s) {
putchar(*s++);
}
}
} serial_t;
static serial_t Serial;
static void initMCLK() {
#ifdef __MSP430FR5739
CSCTL0_H = 0xA5; // CS_KEY
CSCTL1 |= DCOFSEL0 + DCOFSEL1; // Set max. DCO setting
CSCTL2 = SELA_3 + SELS_3 + SELM_3; // set ACLK = MCLK = DCO
CSCTL3 = DIVA_0 + DIVS_0 + DIVM_0; // set all dividers
#else
// Use 16MHz DCO factory calibration
DCOCTL = 0;
BCSCTL1 = CALBC1_16MHZ;
DCOCTL = CALDCO_16MHZ;
#endif
}
int main(void) {
WDTCTL = WDTPW | WDTHOLD; /* Disable watchdog */
initMCLK();
// configure serial device using defaults
Serial.begin(9600);
__eint(); // we enable interrupts after user setup() to give them a chance to customize
// goof with people
// printf("\rWelcome to msp430 uNix! %s %s %d, %d:%d %s\r\nlogin: ", "Fri", "Oct", 9, 11, 25, "AM");
Serial.puts("\r\n# ");
int c;
int nCharCnt = 0;
for (;;) {
c = getchar();
// do some minimum line control to handle backspace
if ( c != 127 ) {
putchar(c);
nCharCnt++;
} else {
if (nCharCnt > 0) {
putchar(c);
--nCharCnt;
}
}
// append newline on CR
if ( c == '\r' ) {
Serial.puts("\n# ");
nCharCnt = 0;
}
// restart processor on CTRL-D
if ( c == 0x04 /*CTRL-D*/ ) {
WDTCTL = WDTHOLD; // restart by setting the WDTCTL without a password
}
}
return 0;
}
//------------------------------------------------------------------------
// serial.h - function declarations for compact asm serial routines
//------------------------------------------------------------------------
#ifdef __cplusplus
extern "C" {
#endif
void init_serial(int txPinMask, int rxPinMask, unsigned duration, unsigned durMod);
int getchar(void);
int putchar(int);
#ifdef __cplusplus
} /* extern "C" */
#endif
//------------------------------------------------------------------------------
// serial_priv.inc - msp430 mcu common defines for use with gcc assembler
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// define PC,SP,SR as gcc only uses the register names
//
#define PC r0
#define SP r1
#define SR r2
//------------------------------------------------------------------------------
// define argument registers
// C function arguments are passed in R15-R12
//
// Note: these registers can be used without preservation
//
#define ARG1 R15
#define ARG2 R14
#define ARG3 R13
#define ARG4 R12
;------------------------------------------------------------------------
; File: sw_serial.S - gcc port of serial.asm
;
; Desc: blocking implementations of putchar(), getchar(), and puts()
; uses cycle counting for delay timing. No timers are used.
; can be used with any PORT1 pin
;
; See Also:
; Detailed information available here:
; http://www.43oh.com/forum/viewtopic.php?f=10&t=1727
;------------------------------------------------------------------------
#include <msp430.h>
#include "serial_priv.inc"
.file "serial.S"
.lcomm in_bit_mask, 2 ; Serial in pin mask ( rx )
.lcomm out_bit_mask, 2 ; Serial out pin mask ( tx )
.lcomm bit_dur, 2 ; Bit duration in cycles
.lcomm half_dur, 2 ; Half bit duration in cycles
.text ;
.global init_serial ; void init_serial(unsigned out_mask, unsigned in_mask, unsigned bit_duration);
#if 0
.global puts ; int puts(const char *s); note: no trailing newline
#endif
.global putchar ; int putchar(unsigned c);
.global getchar ; int getchar(void);
.p2align 1,0 ; align on a word boundary
;--------------------------------------------------------------------------------
; void initSerial(int txPinMask, int rxPinMask, int bitDuration)
;--------------------------------------------------------------------------------
.type init_serial,@function
init_serial: ; Setup serial I/O bitmasks and bit duration (32 minimum)
mov ARG1, &out_bit_mask ; Save serial output bitmask
mov ARG2, &in_bit_mask ; Save serial input bitmask
bis ARG1, &P1DIR ; set output pin
bis ARG1, &P1OUT
bic ARG2, &P1DIR ; clear input pin
bis ARG2, ARG1
#ifdef __MSP430FR5739
bic ARG1, &P1SEL0 ; force output pin to digial I/O no pullups
bic ARG1, &P1SEL1 ; force output pin to digial I/O no pullups
#else
bic ARG1, &P1SEL ; force output pin to digial I/O no pullups
#endif
mov ARG3, ARG1
sub #16, ARG3 ; Adjust count for loop overhead
rla ARG3 ; Multiply by 2 because NOP is two bytes
mov ARG3, &bit_dur ; Save bit duration
sub #32, ARG1 ; Adjust count for loop overhead
mov ARG1, &half_dur ; Save half bit duration
ret ; Return
.Lfe1:
.size init_serial,.Lfe1-init_serial
;--------------------------------------------------------------------------------
; int putchar(int c) - writes the character c, cast to an unsigned char to serial out
;--------------------------------------------------------------------------------
.type putchar,@function
putchar: ; Char to tx in R15, R12, R13, R14, R15 trashed
mov &out_bit_mask, R12 ; Serial output bitmask
mov &bit_dur, R14 ; Bit duration
bis #0x0300, ARG1 ; Add Stop bit(s) to tx char
jmp bit_low ; Send start bit...
tx_bit:
mov R14, R13 ; Get bit duration
tx_delay:
nop ; 4 cycle loop
sub #8, R13 ;
jc tx_delay ;
subc R13, PC ; 0 to 3 cycle delay
nop ; 3
nop ; 2
nop ; 1
rra ARG1 ; Get bit to tx, test for zero
jc bit_high ; If high...
bit_low:
bic.b R12, &P1OUT ; Send zero bit
jmp tx_bit ; Next bit...
bit_high:
bis.b R12, &P1OUT ; Send one bit
jnz tx_bit ; If tx data is not zero, then there are more bits to send...
ret ; Return when all bits sent
.Lfe2:
;--------------------------------------------------------------------------------
; int getchar(void) - read one character (blocking)
;--------------------------------------------------------------------------------
.type getchar,@function
getchar:
mov &bit_dur, R14 ; Bit duration
mov &in_bit_mask, R13 ; Input bitmask
mov #0x01FF, ARG1 ; 9 bits - 8 data + stop
rx_start: ; Wait for start bit
mov &P1IN, R12 ; Get serial input
and R13, R12 ; Mask and test bit
jc rx_start ; Wait for low...
mov &half_dur, R13 ; Wait for 1/2 bit time
rx_delay:
nop ; Bit delay
sub #8, R13
jc rx_delay
subc R13, PC ; 0 to 3 cycle delay
nop ; 3
nop ; 2
nop ; 1
mov &P1IN, R12 ; Get serial input
and &in_bit_mask, R12 ;
rrc ARG1 ; Shift in a bit
mov R14, R13 ; Setup bit timer
jc rx_delay ; Next bit...
rla ARG1 ; Move stop bit to carry
swpb ARG1 ; Move rx byte to lower byte, start bit in msb
ret ; Return with rx char and start bit in R15, stop bit in carry
.Lfe3:
.size getchar,.Lfe3-getchar
;--------------------------------------------------------------------------------
#if 0 /* NOT USED, implemented in C externally */
;--------------------------------------------------------------------------------
.type puts,@function
;--------------------------------------------------------------------------------
; int puts(const char *s) - writes the string s and a trailing newline to serial out.
;--------------------------------------------------------------------------------
puts:
push R11 ; Tx string using putchar
mov ARG1, R11 ; String pointer in R15, copy to R11
putsloop:
mov.b @R11+, ARG1 ; Get a byte, inc pointer
tst.b ARG1 ; Test if end of string
jz putsx ; Yes, exit...
call #putchar ; Call putchar
jmp putsloop
putsx:
pop R11 ; restore original R11
ret ;
.Lfe4:
.size puts,.Lfe4-puts
;--------------------------------------------------------------------------------
#endif /* NOT USED, implemented in C externally */
;--------------------------------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment