/*
* XIOH power sequence
* Copyright (C) 2013 Avencall
*
* serial.c - trace to serial console
* WARNING: TRACES ARE NOT TO BE ACTIVATED FOR PRODUCTION FIRMWARES
* (this .c file is guarded by TRACE_SERIAL)
* Authors:
* Guillaume Knispel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
/* - MSP_BSL_TXD and MSP_BSL_RXD are named according to their main role
* on the board (potentially booting the MSP with a serial port), and
* not according to their main low impedance physical connection to the
* MSP430. In this software they will actually be used for the debugging
* serial connection, unrelated with the standard MSP BSL function.
*/
#include "compiler.h"
#include "config.h"
#ifdef TRACE_SERIAL
MASK_MISRA
#include
#include
#include
#include
UNMASK_MISRA
#include "def.h"
#include "main.h"
#include "hardware.h"
#include "serial.h"
/*
# For UCOS16 = 0:
def baud_slow(freq, ucbr, ucbrs):
zeros = 8 - ucbrs
return 1. / ((zeros * ucbr + ucbrs * (ucbr + 1)) / float(freq) / 8.)
>>> baud_slow(2000000, 17, 3)
115107.91366906476
*/
void SerialInit(void)
{
// Configure the USCI as an UART @ 115200 bauds
// Precondition: SMCLK = 2MHz
UCA0CTL1 |= UCSWRST;
UCA0CTL0 = 0; // select UART mode and framing
UCA0CTL1 = 0xC1; // UCSSEL=11b => SMCLK; (keep) UCSWRST = 1;
UCA0BR0 = 17;
UCA0BR1 = 0;
UCA0MCTL = 0x06; // UCOS16=0; UCBRSx=3; UCBRFx=0 (dont care);
UCA0STAT = 0;
UCA0CTL1 &= ~UCSWRST;
}
#ifdef TEST_LOOP_SPEED
u8 tl_delta = 0;
s8 tl_state = 10;
#define TL_UNKNOWN 0xFFFFu
u16 tl_num = TL_UNKNOWN;
u16 ref_Timer_A_count = 0;
u16 tl_emit(void)
{
if (tl_state == TL_SAVED) {
u16 value = tl_num | ((u16)tl_delta << 14);
tl_num = TL_UNKNOWN;
tl_state = TL_WAIT;
return value;
} else
return 0xFFFFu;
}
#endif /* TEST_LOOP_SPEED */
static void serial_putchar(unsigned char c)
{
while (!(IFG2 & UCA0TXIFG))
; /* nothing */
UCA0TXBUF = c;
}
/* like fputs, but hardcoded to serial output and can't fail */
void serial_puts(const char *s)
{
for (; *s; s++) {
serial_putchar((unsigned char)*s);
ResetSoftWD();
}
}
// TB_SIZE must be a power of 2
#define TB_SIZE 256
u8 trace_buffer[TB_SIZE];
u16 tb_beg = 0;
u16 tb_fill = 0;
static inline u16 TB_I(u16 raw_idx)
{
return raw_idx & (TB_SIZE - 1);
}
static void trace_byte(u8 val)
{
if (tb_fill == TB_SIZE) {
tb_beg = TB_I(tb_beg + 1);
tb_fill--;
}
trace_buffer[TB_I(tb_beg + tb_fill)] = val;
tb_fill++;
}
void trace(u16 tstamp, u8 state, u8 infos)
{
trace_byte(tstamp >> 8);
trace_byte(tstamp & 0xff);
trace_byte(state);
trace_byte(infos);
}
static inline char hex_nibble(u8 n)
{
return n + ((n > 9) ? 'a' - 10 : '0');
}
static inline void dump_byte(char b[3], u8 n)
{
b[0] = hex_nibble(n >> 4);
b[1] = hex_nibble(n & 0xf);
b[2] = ' ';
}
void dump_trace(void)
{
static char buf[64];
u16 pos = 0;
#define flush() \
do { \
buf[pos] = 0; \
serial_puts(buf); \
pos = 0; \
} while (0)
u16 i;
serial_puts("TRACE:\r\n");
pos = 0;
for (i = 0; i < tb_fill; i++) {
dump_byte(buf + pos, trace_buffer[TB_I(tb_beg + i)]);
pos += 3;
if ((i & 15) == 15) {
buf[pos++] = '\r';
buf[pos++] = '\n';
} else if ((i & 7) == 7) {
buf[pos++] = ' ';
}
if (pos >= 56)
flush();
}
flush();
if (i & 15) serial_puts("\r\n");
}
static void trace_slps3n_changes(u8 state)
{
static u8 save_s3inreg = 0;
u8 new_s3inreg = SLP_S3_N(inreg);
if ((new_s3inreg ^ save_s3inreg) & SLP_S3_N(bit)) {
trace(TRACE_WHAT(Timer_A_count, tl_emit()),
state, new_s3inreg & SLP_S3_N(bit));
}
save_s3inreg = new_s3inreg;
}
static void trace_tstamp_loop(u8 state)
{
static u16 save_timer_a_count = 0;
u16 new_timer_a_count = Timer_A_count;
u8 new_s3inreg = SLP_S3_N(inreg);
if (new_timer_a_count < save_timer_a_count) {
trace(TRACE_WHAT(new_timer_a_count, tl_emit()),
state, new_s3inreg & SLP_S3_N(bit));
}
save_timer_a_count = new_timer_a_count;
}
void trace_changes(u8 state)
{
trace_slps3n_changes(state);
trace_tstamp_loop(state);
}
#endif /* TRACE_SERIAL */