Code si almost all rewritten.
+++ /dev/null
-what's this?
-------------
-it's a simple example project for the MSP430 series MCU and the GCC port
-of the mspgcc project. the project contains a makefile and uses assembler
-and C sources. this time it is a software UART with Timer_A.
-
-this example shows the following features:
- - Timer_A uart, full duplex
- o same pins as BSL (P1.1 TX, P2.2 RX)
- o it contains a reusable code
-
- - software FLL
- the watch crystal is used as reference and the main clock
- is adjusted to 1.536MHz on startup
-
- - use uprintf to print formated strings and do a printf
- emulation that prints to the serial port.
-
- - the main loop is a simple line editor. when a return character
- ('\r', usualy RETURN key) is received, it writes the received
- characters from the buffer to the serial port.
- connect a terminal at 9600,N,8,1 to try it out.
-
- - makefile
- o compile and link
- o include assembler files
- o convert to intel hex format
- o generate a listing with mixed C / assembly
-
-required hardware
------------------
-
- - a MSP430F1121 or larger device (any from the F1x series)
- connect pins P1.1 (TX) and P2.2 (RX) through level converters
- to a terminal. you can also use a BSL hardware, the same pins
- are used.
-
- - watch crystal 32.768kHz
-
- - optionaly a LED on P2.5 (470 Ohms series resistor to GND)
-
-disclaimer
-----------
-this example is part of the mspgcc project http://mspgcc.sf.net
-see license.txt for details.
-
-chris
\ No newline at end of file
+++ /dev/null
-#ifndef FLL_H
-#define FLL_H
-
-void fllInit(void); //do an FLL loop to adjust system frequency
-
-#endif //FLL_H
+++ /dev/null
-#include "hardware.h"
-.text
-.global fllInit ; SW FLL to init DCO/SMCLK -frequency
- .type fllInit, @function
-fllInit:
- mov.b #BCSCTL1_FLL, &BCSCTL1 ; Init basic clock control reg 1
- mov.b #BCSCTL2_FLL, &BCSCTL2 ; Init basic clock control reg 2
- mov #TACTL_FLL, &TACTL ; SMCLK is TA-clock / Timer stopped
- bis #MC1, &TACTL ; Start timer: Continuos Mode
- mov #CCTL2_FLL, &CCTL2 ; Init CCR2 and Clear capture flag
-
-.Lwait0:bit #CCIFG, &CCTL2 ; Test/Wait for capture flag
- jz .Lwait0 ; May be used with INT / LPM0 later ?
- mov &CCR2, r15 ; Store CCR2 init-value
- bic #CCIFG, &CCTL2 ; Clear capture flag
-.Lwait1:bit #CCIFG, &CCTL2 ; Test/Wait for capture flag
- jz .Lwait1 ; May be used with INT / LPM0 later ?
- bic #CCIFG, &CCTL2 ; Clear capture flag
- mov.b &BCSCTL1, r14 ; Store current Rsel value
- bic.b #0x0f8, r14 ; Mask for Rsel bits
- mov.b &DCOCTL, r13 ; Store current DCO value
-
-.LfllUP:cmp.b #DCOCTL_MAX, r13 ; Needs Rsel to be increased ?
- jne .LfllDN ; No
- cmp.b #7, r14 ; Is max Rsel already selected ?
- jge .LfllER ; Yes, Rsel can not be increased
- inc.b &BCSCTL1 ; Increase Rsel
- jmp .LfllRx ; Test DCO again
-
-.LfllDN:cmp.b #DCOCTL_MIN, r13 ; Needs Rsel to be decreased ?
- jne .LfllCP ; No
- cmp.b #0, r14 ; Is min Rsel already selected ?
- jeq .LfllER ; Yes, Rsel can not be increased
- dec.b &BCSCTL1 ; Decrease Rsel
-.LfllRx:mov.b #60h, &DCOCTL ; Center DCO (may be optimized later ?)
- jmp .Lwait0 ; Test DCO again
-.LfllCP:
- mov &CCR2, r12 ; Read captured value
- sub r15, r12 ; Subtract last captured value
- mov &CCR2, r15 ; Store CCR2 value for next pass
- cmp #DCO_FSET, r12 ; DCO_FSET= SMCLK/(32768/4)
- jl .LfllI ;
- jeq .LfllOK ;
-.LfllD: dec.b &DCOCTL ; Decrement value
- jmp .Lwait0 ;
-.LfllI: inc.b &DCOCTL ; Increment value
- jmp .Lwait0 ;
-
-.LfllER: ; error, currently ingnored
-.LfllOK:clr &CCTL2 ; stop CCR2
- ret ;
#ifndef HARDWARE_H
#define HARDWARE_H
-#define __msp430_have_port3
-#define __MSP430_HAS_PORT3__
-
#include <io.h>
#include <signal.h>
#include <iomacros.h>
#define QCNT_VECTOR 14
-//PINS
-//PORT1
-#define TX BIT1
-
-//PORT2
-#define RX BIT2
-#define LED BIT1
-
-//Port Output Register 'P1OUT, P2OUT':
-#define P1OUT_INIT TX //Init Output data of port1
-#define P2OUT_INIT 0 //Init Output data of port2
-#define P3OUT_INIT 0 //Init Output data of port3
-
-//Port Direction Register 'P1DIR, P2DIR':
-#define P1DIR_INIT TX //Init of Port1 Data-Direction Reg (Out=1 / Inp=0)
-#define P2DIR_INIT ~RX //Init of Port2 Data-Direction Reg (Out=1 / Inp=0)
-#define P3DIR_INIT 0xff //Init of Port3 Data-Direction Reg (Out=1 / Inp=0)
-
-//Selection of Port or Module -Function on the Pins 'P1SEL, P2SEL'
-#define P1SEL_INIT 0 //P1-Modules:
-#define P2SEL_INIT RX //P2-Modules:
-#define P3SEL_INIT 0 //P3-Modules:
-
-//Interrupt capabilities of P1 and P2
-#define P1IE_INIT 0 //Interrupt Enable (0=dis 1=enabled)
-#define P2IE_INIT 0 //Interrupt Enable (0=dis 1=enabled)
-#define P1IES_INIT 0 //Interrupt Edge Select (0=pos 1=neg)
-#define P2IES_INIT 0 //Interrupt Edge Select (0=pos 1=neg)
-
-#define IE_INIT 0
-#define WDTCTL_INIT WDTPW|WDTHOLD
-
-#define BCSCTL1_FLL XT2OFF|DIVA1|RSEL2|RSEL0
-#define BCSCTL2_FLL 0
-#define TACTL_FLL TASSEL_2|TACLR
-#define CCTL2_FLL CM0|CCIS0|CAP
-
-#define TACTL_AFTER_FLL TASSEL_2|TACLR|ID_0
-
-//#define BAUD 40 //9600 @3MHz div 8
-//#define BAUD 20 //19200 @3MHz div 8
-//#define BAUD 20 //9600 @1.5MHz div 8
-//#define BAUD 140 //9600 @1.5MHz div 8
-
-//#define BAUD 2083 //9600 @20.0MHz div 1
-//#define BAUD 1042 //19200 @20.0MHz div 1
-//#define BAUD 521 //38400 @20.0MHz div 1
-//#define BAUD 347 //57600 @20.0MHz div 1
-//#define BAUD 174 //115200 @20.0MHz div 1
-//#define BAUD 87 //230400 @20.0MHz div 1
-
-#define BAUD 208 //115200 @24.0MHz div 1
+//HW UART registers
+#define UART_OFFSET 0x0100
-//Selection of 'Digitally Controlled Oszillator' (desired frquency in HZ, 1..3 MHz)
-#define DCO_FREQ 1536000 //3072000/2 makes 9600 a bit more precise
+#define UBAUD_ UART_OFFSET + 00
+#define UTX_ UART_OFFSET + 02
+#define URX_ UART_OFFSET + 04
+#define USTAT_ UART_OFFSET + 06
+#define UIE_ UART_OFFSET + 07
-//Automatic, do not edit
-#define DCO_FSET (DCO_FREQ/8192) //DCO_FSET = DCO_FREQ / (32768/4)
-#define DCOCTL_MAX 0xff // Used from FLL to check when Rsel must be changed
-#define DCOCTL_MIN 0 // Used from FLL to check when Rsel must be changed
+sfrw(UBAUD, UBAUD_);
+sfrb(UTX, UTX_);
+sfrb(URX, URX_);
+sfrb(USTAT, USTAT_);
+sfrb(UIE, UIE_);
-#endif //HARDWARE_H
+#endif
-/*
-see README.txt for details.
+/**
+This is a sample application for openMSP430 softcore MCU with external HW UART
+peripheral <git@rtime.felk.cvut.cz:fpga/uart> and quadcount peripheral.
-original by: chris <cliechti@gmx.net>
+First of all "Hello world" is printed and then application works like echo and
+also prints quadrature count whenever its value is changed (only whole turns
+are reported).
-modified by: Vladimir Burian <buriavl2@fel.cvut.cz>
+Baudrate is set to 115200.
*/
+
#include "hardware.h"
#include <stdlib.h>
#include <stdio.h>
-#include "swuart.h"
-#include "fll.h"
+#include "uart.h"
+
/**
QuadCounter value
*/
inline uint32_t qcount() {
uint32_t result = 0;
-
+
result |= QCNTL;
result |= ((uint32_t)QCNTH << 16);
-
+
return result;
}
}
+/**
+Print bits of byte in format b'xxxxxxxx'
+*/
+void print_byte_flags(char flags) {
+ int i;
+
+ putchar('b');
+ putchar('\'');
+
+ for (i = 8; i != 0; i--) {
+ if ((flags & 0x80) != 0) {
+ putchar('1');
+ } else {
+ putchar('0');
+ }
+
+ flags = flags << 1;
+ }
+
+ putchar('\'');
+ putchar('\n');
+}
+
+
/**
Delay function.
*/
-void delay(unsigned int d) {
- while(d--) {
+void delay(unsigned long int a, unsigned long int b) {
+ unsigned long int i;
+
+ while (a--) {
+ i = b;
+ while (i--) {
nop();
nop();
- }
+ }
+ }
}
+
/**
-Main function with init an an endless loop that is synced with the
-interrupts trough the lowpower mode.
+Main function with init and an endless loop.
*/
int main(void) {
- int reading = 0;
- int pos = 0;
- char buf[40];
- int led = 0;
-
- WDTCTL = WDTCTL_INIT; //Init watchdog timer
-
- P1OUT = P1OUT_INIT; //Init output data of port1
- P1SEL = P1SEL_INIT; //Select port or module -function on port1
- P1DIR = P1DIR_INIT; //Init port direction register of port1
- P1IES = P1IES_INIT; //init port interrupts
- P1IE = P1IE_INIT;
-
- P2OUT = P2OUT_INIT; //Init output data of port2
- P2SEL = P2SEL_INIT; //Select port or module -function on port2
- P2DIR = P2DIR_INIT; //Init port direction register of port2
- P2IES = P2IES_INIT; //init port interrupts
- P2IE = P2IE_INIT;
-
- P3DIR = 0xff;
- P3OUT = 0xff; //light LED during init
- delay(65535); //Wait for watch crystal startup
- delay(65535);
-// fllInit(); //Init FLL to desired frequency using the 32k768 cystal as reference.
- P3OUT = 0x00; //switch off LED
-
- TACTL = TACTL_AFTER_FLL; //setup timer (still stopped)
- CCTL0 = CCIE|CAP|CM_2|CCIS_1|SCS; //select P2.2 with UART signal
- CCTL1 = 0; //
- CCTL2 = 0; //
- TACTL |= MC1; //start timer
-
+
+ //UBAUD = 0x04E1; //24.00MHz - 9600 baud
+ UBAUD = 0x0067; //24.00MHz - 115200 baud
+
eint(); //enable interrupts
-
- printf("\r\n====== openMSP430 in action ======\r\n"); //say hello
- printf("\r\nSimple Line Editor Ready\r\n"); //say hello
-
- printf("\n[QCount = 0x%08lX]\n", qcount());
-
- while (1) { //main loop, never ends...
- printf("> "); //show prompt
- reading = 1;
- while (reading) { //loop and read characters
- LPM0; //sync, wakeup by irq
-
- led++; // Some lighting...
- if (led==9) {
- led = 0;
- }
- P3OUT = (0x01 << led);
-
- switch (rxdata) {
- //process RETURN key
- case '\r':
- //case '\n':
- printf("\r\n"); //finish line
- buf[pos++] = 0; //to use printf...
- printf(":%s\r\n", buf);
- reading = 0; //exit read loop
- pos = 0; //reset buffer
- break;
- //backspace
- case '\b':
- if (pos > 0) { //is there a char to delete?
- pos--; //remove it in buffer
- putchar('\b'); //go back
- putchar(' '); //erase on screen
- putchar('\b'); //go back
- }
- break;
- //other characters
- default:
- //only store characters if buffer has space
- if (pos < sizeof(buf)) {
- putchar(rxdata); //echo
- buf[pos++] = rxdata; //store
- }
- }
- }
+
+
+ puts("Hello world\n");
+
+ for (;;) {
+ putchar(getchar());
}
+
}
# makfile configuration
NAME = ta_uart
-OBJECTS = main.o swuart.o fll.o
+OBJECTS = main.o uart.o
CPU = msp430x1121
ASFLAGS = -mmcu=${CPU} -mforce-hwmul -x assembler-with-cpp -D_GNU_ASSEMBLER_ -c
FORCE:
#project dependencies
-main.o: main.c hardware.h
-fll.o: fll.s hardware.h
-swuart.o: swuart.s hardware.h
+main.o: main.c uart.h hardware.h
+uart.o: uart.h hardware.h
+++ /dev/null
-#!/usr/bin/env python
-#very simple serial terminal
-#http://pyserial.sf.net package required
-#input characters are sent directly, received characters are displays as is
-#baudrate and echo configuartion is done through globals:
-
-#<cliechti@gmx.net>
-
-import sys, os, serial, threading, getopt
-#EXITCHARCTER = '\x1b' #ESC
-EXITCHARCTER = '\x04' #ctrl+d
-
-#first choosea platform dependant way to read single characters from the console
-if os.name == 'nt': #sys.platform == 'win32':
- import msvcrt
- def getkey():
- while 1:
- if echo:
- z = msvcrt.getche()
- else:
- z = msvcrt.getch()
- if z == '\0' or z == '\xe0': #functions keys
- msvcrt.getch()
- else:
- return z
-
-elif os.name == 'posix':
- #XXX: Untested code derrived from the Python FAQ....
-# import termios, TERMIOS, sys, os
- import termios, sys, os
- fd = sys.stdin.fileno()
- old = termios.tcgetattr(fd)
- new = termios.tcgetattr(fd)
- new[3] = new[3] & ~TERMIOS.ICANON & ~TERMIOS.ECHO
- new[6][TERMIOS.VMIN] = 1
- new[6][TERMIOS.VTIME] = 0
- termios.tcsetattr(fd, TERMIOS.TCSANOW, new)
- s = '' # We'll save the characters typed and add them to the pool.
- def getkey():
- c = os.read(fd, 1)
- if echo: sys.stdout.write(c)
- return c
- def clenaup_console():
- termios.tcsetattr(fd, TERMIOS.TCSAFLUSH, old)
- sys.exitfunc = clenaup_console #terminal modes have to be restored on exit...
-
-else:
- raise "Sorry no implementation for your platform (%s) available." % sys.platform
-
-
-def reader():
- """loop forever and copy serial->console"""
- while 1:
- sys.stdout.write(s.read())
-
-def writer():
- """loop forever and copy console->serial"""
- while 1:
- c = getkey()
- if c == EXITCHARCTER: break #exit on esc
- s.write(c) #send character
- if convert_outgoing_cr and c == '\r':
- s.write('\n')
- if echo: sys.stdout.write('\n')
-
-
-#print a short help message
-def usage():
- print >>sys.stderr, """USAGE: %s [options]
- Simple Terminal Programm for the serial port.
-
- options:
- -p, --port=PORT: port, a number, defualt = 0 or a device name
- -b, --baud=BAUD: baudrate, default 9600
- -r, --rtscts: enable RTS/CTS flow control (default off)
- -x, --xonxoff: enable software flow control (default off)
- -e, --echo: enable local echo (default off)
- -c, --cr: disable CR -> CR+LF translation
-
- """ % sys.argv[0]
-
-if __name__ == '__main__':
- #parse command line options
- try:
- opts, args = getopt.getopt(sys.argv[1:],
- "hp:b:rxec",
- ["help", "port=", "baud=", "rtscts", "xonxoff", "echo", "cr"])
- except getopt.GetoptError:
- # print help information and exit:
- usage()
- sys.exit(2)
-
- port = 0
- baudrate = 9600
- echo = 0
- convert_outgoing_cr = 1
- rtscts = 0
- xonxoff = 0
- for o, a in opts:
- if o in ("-h", "--help"): #help text
- usage()
- sys.exit()
- elif o in ("-p", "--port"): #specified port
- try:
- port = int(a)
- except ValueError:
- port = a
- elif o in ("-b", "--baud"): #specified baudrate
- try:
- baudrate = int(a)
- except ValueError:
- raise ValueError, "Baudrate must be a integer number"
- elif o in ("-r", "--rtscts"):
- rtscts = 1
- elif o in ("-x", "--xonxoff"):
- xonxoff = 1
- elif o in ("-e", "--echo"):
- echo = 1
- elif o in ("-c", "--cr"):
- convert_outgoing_cr = 0
-
- try:
- s = serial.Serial(port, baudrate, rtscts=rtscts, xonxoff=xonxoff)
- except:
- print "could not open port"
- sys.exit(1)
- print "--- Miniterm --- type Ctrl-D to quit"
- #start serial->console thread
- r = threading.Thread(target=reader)
- r.setDaemon(1)
- r.start()
- #enter console->serial loop
- writer()
-
- print "\n--- exit ---"
+++ /dev/null
-#ifndef SWUART_H
-#define SWUART_H
-
-void serPutc(char); //send one character over timer_a uart
-extern char rxdata;
-#endif //SWUART_H
+++ /dev/null
-#include "hardware.h"
-
-;variables
-.data
- .comm rxdata,1,1 ;char var
- .comm rxshift,1,1 ;char var
- .comm rxbit,2,2 ;short var, aligned
-
-.text
-
-interrupt(TIMERA0_VECTOR) ;register interrupt vector
-;interrupt handler to receive as Timer_A UART
-.global ccr0 ;place a label afterwards so
-ccr0: ;that it is used in the listing
- add rxbit, r0
- jmp .Lrxstart ;start bit
- jmp .Lrxdatabit ;D0
- jmp .Lrxdatabit ;D1
- jmp .Lrxdatabit ;D2
- jmp .Lrxdatabit ;D3
- jmp .Lrxdatabit ;D4
- jmp .Lrxdatabit ;D5
- jmp .Lrxdatabit ;D6
-; jmp .Lrxlastbit ;D7 that one is following anyway
-
-.Lrxlastbit: ;last bit, handle byte
- bit #SCCI, &CCTL0 ;read last bit
- rrc.b rxshift ;and save it
- clr rxbit ;reset state
- mov #CCIE|CAP|CM_2|CCIS_1|SCS, &CCTL0 ;restore capture mode
- mov.b rxshift, rxdata ;copy received data
- bic #CPUOFF|OSCOFF|SCG0|SCG1, 0(r1) ;exit all lowpower modes
- ;here you might do other things too, like setting a flag
- ;that the wakeup comes from the Timer_A UART. however
- ;it should not take longer than one bit time, otherwise
- ;charcetrs will be lost.
- reti
-
-.Lrxstart: ;startbit, init
- clr rxshift ;clear input buffer
- add #(BAUD/2), &CCR0 ;startbit + 1.5 bits -> first bit
- mov #CCIE|CCIS_1|SCS, &CCTL0;set compare mode, sample bits
- jmp .Lrxex ;set state,...
-
-.Lrxdatabit: ;save databit
- bit #SCCI, &CCTL0 ;measure databit
- rrc.b rxshift ;rotate in databit
-
-.Lrxex: add #BAUD, &CCR0 ;one bit delay
- incd rxbit ;setup next state
- reti
-
-; void serPutc(char)
-;use an other Capture/Compare than for receiving (full duplex).
-;this one is without interrupts and OUTMOD, because only
-;this way P1.1 can be used. P1.1 is prefered because the
-;BSL is on that pin too.
-.global putchar
- .type putchar, @function
-putchar: ;send a byte
- mov #0, &CCTL1 ;select compare mode
- mov #10, r13 ;ten bits: Start, 8 Data, Stop
- rla r15 ;shift in start bit (0)
- bis #0x0200, r15 ;set tenth bit (1), thats the stop bit
- mov &TAR, &CCR1 ;set up start time
-.Lt1lp: add #BAUD, &CCR1 ;set up for one bit
- rrc r15 ;shift data trough carry
- jc .Lt1 ;test carry bit
-.Lt0: bic.b #TX, &P1OUT ;generate pulse
- jmp .Ltc ;
-.Lt1: bis.b #TX, &P1OUT ;just use the same amount of time as for a zero
- jmp .Ltc ;
-.Ltc: bit #CCIFG, &CCTL1 ;wait for compare
- jz .Ltc ;loop until the bit is set
- bic #CCIFG, &CCTL1 ;clear for next loop
- dec r13 ;decrement bit counter
- jnz .Lt1lp ;loop until all bits are transmitted
- ret
--- /dev/null
+#include "hardware.h"
+#include "uart.h"
+
+int putchar(int c) {
+ while (USTAT & 0x20) {}
+ UTX = c;
+ return 0;
+}
+
+int getchar() {
+ while (!(USTAT & 0x10)) {}
+ return URX;
+}
+
--- /dev/null
+#ifndef UART_H
+#define UART_H
+
+int putchar(int c);
+
+int getchar();
+
+#endif
+