Last active
December 30, 2017 22:36
-
-
Save RickKimball/7183254 to your computer and use it in GitHub Desktop.
msp430 example showing timer used to periodically send 50 baud async data
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 50baud.c - example of sending 50 baud async serial output on P1.1 | |
* code uses timer sourced from VLO and sleeps between reports. | |
* | |
* P1.0 - optionally output ACLK for measurement of VLO | |
* P1.1 - 50 baud async serial output | |
* P1.6 - indicator led, on during serial transmission | |
* | |
* TIMER0 - continuous up mode sourced with ACLK (VLO) | |
* TIMER0_A0 - 50 baud ISR enabled and disable for 8-N-1 transmission | |
* TIMER0_A1 - periodic timer, counts seconds and exits sleep mode when | |
* target time reached, and sets auto timer | |
* | |
* Author: rick@kimballsoftware.com | |
* Date: 10/27/2013 | |
* msp430-elf-gcc -g -Os 50baud_asm.c _start.S -mmcu=msp430g2231 \ | |
* -minrt -nostartfiles \ | |
* -L /home/user/Msp430GCCopensource/msp430-elf/lib/ldscripts -T msp430g2231.ld | |
* || | |
* msp430-gcc -g -Os 50baud_asm.c -mmcu=msp430g2231 -mdisable-watchdog \ | |
* -ffunction-sections -fdata-sections -Wl,--gc-sections | |
*/ | |
#include <msp430.h> | |
#include <stdint.h> | |
static const uint32_t MCLK_HZ = 1000000; /* how fast to run the cpu */ | |
static const uint32_t XTAL_HZ = 11680; /* VLO frequency, measure your chip and set here */ | |
/* | |
* ---- timer based serial code ---- | |
*/ | |
#define BAUD 300 | |
#define BAUD_2 (BAUD/2) | |
#define TICKS_PER_BIT ((XTAL_HZ+(BAUD_2))/BAUD) | |
#define TICKS_PER_BIT_DIV2 ((XTAL_HZ+(BAUD_2))/BAUD/2) | |
static const unsigned data_mask = 0xff; | |
static const unsigned stop_mask = 0x01; | |
static volatile unsigned int TX_BUF; /* 1 character tx buffer, used by ISR */ | |
#if 0 | |
#define ALWAYS_INLINE __attribute__((always_inline)) | |
#else | |
#define ALWAYS_INLINE inline | |
#endif | |
static void ALWAYS_INLINE init_serial(void); | |
static void ALWAYS_INLINE init_systick(void); | |
static void ALWAYS_INLINE send_packet(void); | |
void init_serial(void) | |
{ | |
TA0CCTL0 = OUT; /* set idle state of P1.1 to high */ | |
P1DIR |= BIT1; P1SEL |= BIT1; /* configure TA0.0/P1.1 as output */ | |
TA0CTL = TASSEL_1 | MC_2 | TACLR; /* continuous up based on VLOCLK */ | |
} | |
/* | |
* putchar() - send one serial byte | |
* | |
* NOTE: by implementing putchar(), printf will work on larger msp430 G series | |
*/ | |
int putchar(int c) | |
{ | |
register unsigned value; | |
value = (stop_mask << 8 )| (c & data_mask); /* stop bit '1' and data */ | |
value <<= 1; /* add start bit '0' */ | |
while(TA0CCTL0 & CCIE); /* busy wait for previous transmission to finish */ | |
TA0CCR0 = TA0R; /* get current timer count */ | |
TA0CCR0 += TICKS_PER_BIT; /* set up next bit transition time */ | |
TA0CCTL0 = OUTMOD0 | CCIE; /* default TX_PIN HIGH and re-enable interrupts */ | |
TX_BUF = value; /* queue up the byte for ISR */ | |
return 1; | |
} | |
void putstr(const uint8_t *s) | |
{ | |
while(*s) { | |
putchar(*s++); | |
} | |
} | |
/* | |
* send_packet - TODO: take your data sample and create your custom packet data | |
*/ | |
void send_packet(void) | |
{ | |
static uint8_t packet_id; /* persistent packet number, starts at 0 */ | |
static char hex_tbl[]="0123456789abcdef"; | |
P1OUT ^= BIT6; | |
++packet_id; | |
putchar('U'); | |
putchar(hex_tbl[(packet_id >> 4) & 0b1111]); | |
putchar(hex_tbl[packet_id & 0b1111]); | |
putchar('\r'); | |
putchar('\n'); | |
P1OUT ^= BIT6; | |
} | |
/* | |
* putch_bit_isr() - use timer interrupt to send next bit | |
* | |
* outputs each bit using LSB order | |
*/ | |
__attribute__ ((interrupt(TIMER0_A0_VECTOR))) | |
void putch_bit_isr(void) | |
{ | |
__asm__ volatile | |
( | |
" add %[ticks],%[ccr0]\n" | |
" bis %[outmod2],%[cctl0]\n" | |
" rra %[tx_buf], %[tx_buf]\n" | |
" jnc 1f\n" | |
" bic %[outmod2],%[cctl0]\n" | |
"1:\n" | |
" jnz 2f\n" | |
" bic %[ccie],%[cctl0]\n" | |
"2:\n" | |
: /* return value */ | |
: /* named constants / variables */ | |
[ticks] "i" (TICKS_PER_BIT), | |
[outmod2] "i" (OUTMOD2), | |
[ccie] "i" (CCIE), | |
[ccr0] "m" (TA0CCR0), | |
[cctl0] "m" (TA0CCTL0), | |
[tx_buf] "m" (TX_BUF) | |
: /* collobered registers */ | |
"cc" | |
); | |
} | |
#if 0 | |
/* original c version */ | |
__attribute__ ((interrupt(TIMER0_A0_VECTOR))) | |
void putch_bit_isr(void) | |
{ | |
TA0CCR0 += TICKS_PER_BIT; /* setup next time to send next bit, OUT is set then */ | |
TA0CCTL0 |= OUTMOD2; /* reset OUT (set to 0) OUTMOD2|OUTMOD0 (0b101) */ | |
if (TX_BUF & 0x01) { /* look at LSB, if 1 */ | |
TA0CCTL0 &= ~OUTMOD2; /* then set OUT (set to 1) OUTMOD0 (0b001) */ | |
} | |
if (!(TX_BUF >>= 1)) { /* if all bits transmitted ? */ | |
TA0CCTL0 &= ~CCIE; /* then disable interrupt, send no more bits */ | |
/* NOTE: this indicates byte transmit complete */ | |
} | |
} | |
#endif | |
/* | |
* --- periodic timer code --- | |
*/ | |
static const long xmit_every_n_secs = 3; /* send a report ever n seconds */ | |
static volatile unsigned long secs; /* total running seconds */ | |
static volatile unsigned long secs_til_wakeup; /* countdown time in seconds */ | |
/* | |
* enable_systick() - | |
* | |
* NOTE: assumes a low frequency clock source of less than < 64kHz | |
* also assumes some other routines initializes the timer ctl. | |
*/ | |
void init_systick(void) | |
{ | |
secs_til_wakeup = xmit_every_n_secs; | |
TA0CCR1 = XTAL_HZ; | |
TA0CCTL1 = CCIE; | |
} | |
#if 0 | |
#pragma vector=TIMER0_A1_VECTOR | |
__interrupt | |
#else | |
__attribute__ ((interrupt(TIMER0_A1_VECTOR))) | |
#endif | |
void systick_isr(void) | |
{ | |
volatile unsigned reset_flag = TA0IV; /* reset the intr flag by reading */ | |
(void) reset_flag; /* get rid of unused warning */ | |
TA0CCR1 += XTAL_HZ; /* add 1 second to target time */ | |
secs++; /* seconds since start */ | |
if (!(--secs_til_wakeup)) { /* decr seconds count, exit when 0 */ | |
secs_til_wakeup = xmit_every_n_secs; | |
LPM3_EXIT; /* let main code run */ | |
} | |
} | |
/* | |
* | |
*/ | |
int main(void) | |
{ | |
WDTCTL = WDTHOLD | WDTPW; | |
BCSCTL1 = CALBC1_1MHZ; /* Set DCO to 1MHz */ | |
DCOCTL = CALDCO_1MHZ; | |
BCSCTL3 = (BCSCTL3 & ~LFXT1S_3) | LFXT1S_2; /* configure ACLK with VLO */ | |
init_serial(); /* configure timer as a serial device */ | |
init_systick(); /* configure timer as periodic timer */ | |
P1OUT &= ~BIT6; /* configure led indicator */ | |
P1DIR |= BIT6; | |
#if 1 /* enable to measure clocks */ | |
P1DIR |= BIT0 | BIT4; | |
P1SEL |= BIT0 | BIT4; | |
#endif | |
__enable_interrupt(); /* most things are handled in the isr routines */ | |
while( 1 ) { | |
send_packet(); /* send a bunch of bits at 50 baud */ | |
LPM3; /* deep sleep until xmit_every_n_secs reached */ | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* -*- Mode: Asm -*- */ | |
;----------------------------------------------------- | |
; _start.S - minimal c runtime for msp430-elf-gcc | |
; This is a hacked up version of the crt0.S from msp430-gcc | |
; modified to work with msp430-elf-gcc. This allows the | |
; smaller msp430g2xxx chips to link successfully with | |
; very little extra code | |
; | |
.section .text, "ax", @progbits | |
.global _start | |
_start: | |
;----------------------------------------------------- | |
__init_stack: | |
mov #__stack, r1 | |
mov #0x5a80, &0x120 ; WDTCTL = WDTPW|WDTHOLD | |
;----------------------------------------------------- | |
__copy_data: | |
mov #__romdatacopysize, r12 | |
tst r12 | |
jz 2f | |
1: | |
decd r12 ; assumes data section aligned to word boundary | |
mov.w __romdatastart(r12), __datastart(r12) | |
jne 1b | |
2: | |
;----------------------------------------------------- | |
__clear_bss: | |
mov #__bsssize, r12 | |
tst r12 | |
jz 2f | |
1: | |
decd r12 ; assumes bss section aligned to word boundary | |
clr __bssstart(r12) | |
jne 1b | |
2: | |
jz main | |
;----------------------------------------------------- | |
.section .resetvec, "ax", @progbits | |
.word _start ; point reset vector to init code above |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment