Skip to content

Commit

Permalink
merge serial
Browse files Browse the repository at this point in the history
  • Loading branch information
jlbirccyn committed Oct 28, 2019
2 parents 5fa7881 + 7c2e001 commit 5517b77
Show file tree
Hide file tree
Showing 14 changed files with 502 additions and 64 deletions.
Binary file modified documentation/manual/msp430/porting.pdf
Binary file not shown.
46 changes: 46 additions & 0 deletions documentation/manual/msp430/porting.tex
Expand Up @@ -1002,6 +1002,35 @@ \subsection{Dynamic update}

Note that the 21MHz and 24 MHz frequencies overclock the CPU capabilities and may not work.

A callback can be added each time the CPU clock is updated. This is done through the function:
\begin{lstlisting}
void tpl_add_freq_update_callback(tpl_freq_update_item *freqObs);
\end{lstlisting}
Where \lstinline{freqObs} is an item of a single linked list of function calls. This functionnality is implemented in the serial line driver (for debug purpose) of the launchpad like this:

\begin{lstlisting}
#include "tpl_clocks.h"

tpl_freq_update_item tpl_serial_callback = {&tpl_serial_update_freq,NULL};

void tpl_serial_begin()
{
/* make sure we are informed of a clock update. */
tpl_add_freq_update_callback(&tpl_serial_callback);
..
}

void tpl_serial_update_freq()
{
//callback that updates the serial baudrate configuration
//in function of the new input clock.
}

\end{lstlisting}

The frequency of the MCU is defined using the DCO. The function \lstinline{uint32_t tpl_getDCOFrequency();} returns the DCO output frequency in Hz. This can be used in the function callback.


\section{Low power in idle}

When Trampoline runs the idle task, the MCU can be put in low power mode. This is done by setting the attribute \lstinline{IDLE_POWER_MODE} in the \lstinline{OS} object. Possible values are \lstinline{ACTIVE}, \lstinline{LPM0}, \lstinline{LPM1}, \lstinline{LPM2} and \lstinline{LPM3}. Default value, that is without setting this attribute, is \lstinline{ACTIVE}.
Expand Down Expand Up @@ -1077,6 +1106,23 @@ \section{Memory mapping and memory protection}

The TI MSP430 uses a very simple memory protection scheme. The Memory Protection Unit allows to define 2 boundaries, SEGB1 and SEGB2 and the access right corresponding to 3 regions, the one below SEGB1 (excluded), the one between SEGB1 (included) and SEGB2 (excluded) and the one above SEGB2 (included). Some addresses locations, the 16 bytes starting à \lstinline{0xFF80} contain the JTAG password. Writing random values at theses addresses bricks the MCU. To prevent that, Trampoline initialize the MPU so that addresses below the start of FRAM (peripherals and SRAM) may be read and written, addresses from start of FRAM to \lstinline{0x10000} may be read and executed and addresses from \lstinline{0x10000} to the end of the FRAM may be read and written.

\section{Libraries}
\subsection{Serial line}
The launchpad kits use a serial line over USB that can be used for debugging purpose. The configuration is 115200 bauds, 8N1.

The library should be declared in the .oil file (so that dedicated files are included in the build process)
\begin{lstlisting}
BUILD = TRUE {
LIBRARY = serial;
};
\end{lstlisting}

The library is quite limited at this date, and it can only send characters (no reception). There is no ring buffer, and there is a waiting loop if the previous character is not yet sent.

An example is given for the msp430fr5969 launchpad.

The library supports various MCU change frequencies, and the output frequency is updated (the current message may be corrupted!).

\bibliographystyle{plain}
\bibliography{porting}

Expand Down
@@ -0,0 +1,7 @@
serial
build
*_exe
*.bin
*.map
build.py
make.py
11 changes: 11 additions & 0 deletions examples/msp430x/small/msp430fr5969/launchpad/serial/README.md
@@ -0,0 +1,11 @@
# Blink example

This application is a simple periodic example

The SystemCounter is at 1ms.

The task "blink" prints "hello world" to the serial line 115200, 8N1 of the launchpad, that is connected to the USB (through the embbeded debugger).

`
goil --target=msp430x/small/msp430fr5969/launchpad --templates=../../../../../../goil/templates/ serial.oil
`
28 changes: 28 additions & 0 deletions examples/msp430x/small/msp430fr5969/launchpad/serial/serial.c
@@ -0,0 +1,28 @@
#include "tpl_os.h"
#include "msp430.h"
#include <stdint.h>
#include "tpl_clocks.h"

#define APP_Task_serial_START_SEC_CODE
#include "tpl_memmap.h"

FUNC(int, OS_APPL_CODE) main(void)
{
// Disable the GPIO power-on default high-impedance mode
// to activate previously configured port settings
PM5CTL0 &= ~LOCKLPM5;
//set GPIO P1.0 (LED2) as an output
P1DIR = 0x01;
tpl_serial_begin();
StartOS(OSDEFAULTAPPMODE);
return 0;
}

TASK(serial)
{
tpl_serial_print_string("Hello world!\n");
TerminateTask();
}

#define APP_Task_serial_STOP_SEC_CODE
#include "tpl_memmap.h"
72 changes: 72 additions & 0 deletions examples/msp430x/small/msp430fr5969/launchpad/serial/serial.oil
@@ -0,0 +1,72 @@
OIL_VERSION = "2.5";

IMPLEMENTATION trampoline {
/* This fix the default STACKSIZE of tasks */
TASK {
UINT32 STACKSIZE = 100 ;
} ;

/* This fix the default STACKSIZE of ISRs */
ISR {
UINT32 STACKSIZE = 100 ;
} ;
};

CPU serial {
OS config {
STATUS = EXTENDED;
PAINT_STACK = TRUE;
PAINT_REGISTERS = TRUE;
CPU_FREQ_MHZ = 8;

BUILD = TRUE {
TRAMPOLINE_BASE_PATH = "../../../../../..";
APP_SRC = "serial.c";
APP_NAME = "serial_exe";
CFLAGS = "-O0 -g3 -gdwarf-2 -ggdb"; //gdb usage
LDFLAGS = "-Map=serial.map";
LIBRARY = serial;
//use either msp-gcc (provided with Energia)..
COMPILER = "msp430-gcc";
ASSEMBLER = "msp430-gcc";
LINKER = "msp430-ld";
COPIER = "msp430-objcopy";
//or GCC for MSP (provided by TI)
//COMPILER = "msp430-elf-gcc";
//ASSEMBLER = "msp430-elf-gcc";
//LINKER = "msp430-elf-ld";
//COPIER = "msp430-elf-objcopy";
//CFLAGS = "-I/opt/ti/ccs920/ccs/ccs_base/msp430/include_gcc";
SYSTEM = PYTHON;
};
SYSTEM_CALL = TRUE;
MEMMAP = TRUE {
COMPILER = gcc;
LINKER = gnu_ld { SCRIPT = "script.ld"; };
ASSEMBLER = gnu_as;
MEMORY_PROTECTION = FALSE;
};
};

APPMODE std {};

TASK serial {
PRIORITY = 3;
AUTOSTART = FALSE;
ACTIVATION = 1;
SCHEDULE = FULL;
};

ALARM serial_serial {
COUNTER = SystemCounter;
ACTION = ACTIVATETASK {
TASK = serial;
};
AUTOSTART = TRUE {
APPMODE = std;
ALARMTIME = 200;
CYCLETIME = 200;
};
};
};

Expand Up @@ -3,3 +3,10 @@
* MSP430 Specific configuration file for Launchpad SDK
*/

CPU launchpad {
LIBRARY serial {
PATH = "msp430x/small/msp430fr5969/launchpad/serial";
CHEADER = "serial.h";
CFILE = "serial.c";
};
};
12 changes: 12 additions & 0 deletions machines/msp430x/small/msp430fr5969/launchpad/serial/README.md
@@ -0,0 +1,12 @@
# Serial over USB support

The lib offers a lightweight serial communication for the launchpad boards with serial over USB

The basic implementation opens the serial port (115200, 8N1) to push debug messages

At this date, it supports:
* update the baud rate parameters when there are DCO frequency updates.

At this date, it does **not** support:
* transmit using an interrupt (and a ring buffer)
* receive msgs
78 changes: 78 additions & 0 deletions machines/msp430x/small/msp430fr5969/launchpad/serial/serial.c
@@ -0,0 +1,78 @@
#include "tpl_clocks.h"
#include <msp430.h>
#include <stdlib.h> //NULL

#define OS_START_SEC_CONST_16BIT
#include "tpl_memmap.h"

/** these 2 tabulars are generated from the serial.py script
* that off-line compute the register values to configure
* UART timings (depending on both the input frequency (dco)
* and the uart frequency (115200 bauds)
*/
const uint16_t tpl_brwTab[] = {
0x8, 0x8, 0x1, 0x2, 0x1, 0x3, 0x2, 0x4,
0x2, 0x8, 0x3, 0xb, 0x4, 0xd, 0x0, 0x0};
const uint16_t tpl_mctlwTab[] = {
0xd600, 0xd600, 0x1171, 0x44e1, 0x52e1, 0xddc1, 0xbb21, 0x5551,
0x44e1, 0xf7a1, 0xddc1, 0x4461, 0x5551, 0x2501, 0x0, 0x0};

#define OS_STOP_SEC_CONST_16BIT
#include "tpl_memmap.h"

#define OS_START_SEC_CODE
#include "tpl_memmap.h"

void tpl_serial_update_freq()
{
uint16_t dcoConfig = tpl_getDCOConfig();
//set Software reset (and reinit register)
UCA0CTLW0 = UCSWRST;
//default 8N1, lsb first, uart, input clk SMCLK
UCA0CTLW0 |= UCSSEL__SMCLK;
//baud rates are pre-calculated for 115200.
UCA0BRW = tpl_brwTab[dcoConfig];
UCA0MCTLW = tpl_mctlwTab[dcoConfig];
//get out of reset state
UCA0CTLW0 &= ~UCSWRST;
}

void tpl_serial_putchar(char c)
{
//wait until previous op is ok
while(!(UCA0IFG & UCTXIFG));
UCA0IFG &= ~UCTXIFG; //RAZ
UCA0TXBUF = c;
}

void tpl_serial_print_string(char *str)
{
while(*str)
tpl_serial_putchar(*str++);
}

tpl_freq_update_item tpl_serial_callback = {&tpl_serial_update_freq,NULL};

void tpl_serial_begin()
{
/* make sure we are informed of a clock update. */
tpl_add_freq_update_callback(&tpl_serial_callback);
/* First: set SMCLK to DCO */
CSCTL0 = CSKEY; /* Get access to CSCTLx regs */
CSCTL2 &= ~SELS_7; /* Set DCO as SMCLK (clear field.. */
CSCTL2 |= SELS__DCOCLK; /* .. and set correct DCO value) */
/* then remove the DIVS division */
CSCTL3 &= ~(DIVS0_L | DIVS1_L | DIVS2_L);
/* set IO: fonction 10 for P2.0 (Tx) and P2.1 (Rx) */
P2SEL0 &= ~0x03;
P2SEL1 |= 0x03;
/** use USCI A0, that is connected to the USB target.
* connect using 115200 8N1
* set the initial frequency
**/
tpl_serial_update_freq();
}

#define OS_STOP_SEC_CODE
#include "tpl_memmap.h"

18 changes: 18 additions & 0 deletions machines/msp430x/small/msp430fr5969/launchpad/serial/serial.h
@@ -0,0 +1,18 @@
#ifndef __TPL_SERIAL_H__
#define __TPL_SERIAL_H__

/* function that should be called each time
* the DCO frequency is changed to recalculate the
* correct baud rate parameters.
**/
void tpl_serial_update_freq();

/** simply put one char on the serial line */
void tpl_serial_putchar(char c);

/** print a standard null terminated string on the serial line*/
void tpl_serial_print_string(char *str);

/** configure the serial line. Should be called at startup.*/
void tpl_serial_begin();
#endif
81 changes: 81 additions & 0 deletions machines/msp430x/small/msp430fr5969/launchpad/serial/serial.py
@@ -0,0 +1,81 @@
#! /usr/bin/env python
# -*- coding: UTF-8 -*-
from __future__ import print_function
from math import *

# This simple python script computes baud-rate settings
# for different input frequencies

# The algorithm is extracted from the user's guide
# (slau367o.pdf), p.776
# the 2 tabulars fracFreq and ucbrsTab are extracted from
# table 30-4 of this user's guide
# tabular DCOfreq gives the frequencies of the DCO from
# its configuration (dcofsel[3..1] | dcorsel).
# the algorithm is the one in "Baud-rate settings quick set up"


fracFreq = [
0.0000, 0.0529, 0.0715, 0.0835,
0.1001, 0.1252, 0.1430, 0.1670,
0.2147, 0.2224, 0.2503, 0.3000,
0.3335, 0.3575, 0.3753, 0.4003,
0.4286, 0.4378, 0.5002, 0.5715,
0.6003, 0.6254, 0.6432, 0.6667,
0.7001, 0.7147, 0.7503, 0.7861,
0.8004, 0.8333, 0.8464, 0.8572,
0.8751, 0.9004, 0.9170, 0.9288]

ucbrsTab = [
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x11,
0x21, 0x22, 0x44, 0x25, 0x49, 0x4A, 0x52, 0x92,
0x53, 0x55, 0xAB, 0x6B, 0xAD, 0xB5, 0xB6, 0xD6,
0xB7, 0xBB, 0xDD, 0xED, 0xEE, 0xBF, 0xDF, 0xEF,
0xF7, 0xFB, 0xFD, 0xFE]


DCOfreq = [1000000, 1000000,2670000, 5330000,
3500000, 7000000,4000000, 8000000,
5330000,16000000,7000000,21000000,
8000000,24000000, 0, 0]

def exportTab(valList,name):
print('const uint16_t '+name+'[] = {',end='')
i = 0;
for val in valList:
if i != 0:
print(', ',end='')
if i%8 == 0:
print('\n\t',end='')
print(hex(val),end='')
i = i+1
print('};')

uartFreq = 115200
brw = []
mctlw = []
for freq in DCOfreq:
ucbr = 0
ucos16 = 0
ucbrf = 0
ucbrs = 0
if freq != 0:
N = (float)(freq)/uartFreq
if N > 16:
ucos16 = 1
ucbr = (int)(N/16)
ucbrf = (int)(((N/16)-floor(N/16))*16)
else:
ucbr = (int)(N)
frac = N-floor(N);
i = 1
while frac > fracFreq[i]:
i = i+1
i = i-1
ucbrs = ucbrsTab[i]
#regs
brw.append(ucbr)
mctlw.append(ucbrs << 8 | ucbrf << 4 | ucos16)

exportTab(brw, 'tpl_brwTab')
exportTab(mctlw, 'tpl_mctlwTab')

0 comments on commit 5517b77

Please sign in to comment.