CVS: libraries/mspgcc checksum_xor.c,NONE,1.1 delay.S,NONE,1.1 event_scheduler.c,NONE,1.1 eventhandler.S,NONE,1.1 eventhandler_idle.S,NONE,1.1 flash_erase_segment.c,NONE,1.1 flash_write_byte.c,NONE,1.1 flash_write_word.c,NONE,1.1 fll.c,NONE,1.1 hex_decode.c,NONE,1.1 hex_decode_inline.c,NONE,1.1 hex_encode.c,NONE,1.1 hex_fromdigit.c,NONE,1.1 hexdump.c,NONE,1.1 lineeditor.c,NONE,1.1 makefile,NONE,1.1 ringbuffer_clear.c,NONE,1.1 ringbuffer_get.c,NONE,1.1 ringbuffer_len.c,NONE,1.1 ringbuffer_put.c,NONE,1.1 simple_readline.c,NONE,1.1
Chris Liechti <[email protected]>
| Newsgroups | gmane.comp.hardware.texas-instruments.msp430.gcc.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/mspgcc/libraries/mspgcc
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19935/libraries/mspgcc
Added Files:
checksum_xor.c delay.S event_scheduler.c eventhandler.S
eventhandler_idle.S flash_erase_segment.c flash_write_byte.c
flash_write_word.c fll.c hex_decode.c hex_decode_inline.c
hex_encode.c hex_fromdigit.c hexdump.c lineeditor.c makefile
ringbuffer_clear.c ringbuffer_get.c ringbuffer_len.c
ringbuffer_put.c simple_readline.c
Log Message:
initial import of mspgcc library
featuring an event handler/scheduler, ringbuffer, flash erase/write, checksum, hex, delay and a line editor
--- NEW FILE: checksum_xor.c ---
// 16 bit bitwise xor checksum
unsigned short checksum_xor(const void *address, unsigned int length) {
unsigned short checksum = 0xffff; // start inverted, so we don't have to invert at the end
length >>= 1; // calcualte size in words (rounds down if size is odd)
while (length--) {
checksum ^= *((unsigned short *)address)++;
}
return checksum;
}
--- NEW FILE: delay.S ---
.global delay
.type delay, @function
delay:
tst R15 ; 1
jz .Lend ; 2
.Ldelay:
dec R15 ; 1 ] loop
jnz .Ldelay ; 2 ]
.Lend: ret ; 3
.Ldelay_end:
.size delay,.Ldelay_end-delay
--- NEW FILE: event_scheduler.c ---
#include "mspgcc/eventhandler.h"
// This table has to be provided by the user.
extern const SCHEDULER_TABLE scheduler_table[];
static volatile unsigned short event_time;
static unsigned short event_last_time;
void scheduler_increment(void) {
event_time++;
}
void scheduler_reset(void) {
event_time = 0;
event_last_time = 0;
}
void event_scheduler(void) {
while (event_time != event_last_time) {
const SCHEDULER_TABLE *table_entry = scheduler_table;
while (table_entry->modulo) {
if ((event_last_time % table_entry->modulo) == table_entry->shift) {
EVENTHANDLER_LAUNCH(table_entry->eventbits); //set task bit
}
table_entry++;
}
event_last_time++; //advance in time
}
}
--- NEW FILE: eventhandler.S ---
#include "mspgcc/eventhandler.h"
; variables
.data
.global eventhandler_bits
.comm eventhandler_bits,2,2 ;short var, aligned. eventbits are stored here
.text
// event handler mainloop. This function never returns.
.global eventhandler
.type eventhandler, @function
eventhandler:
mov R15, eventhandler_bits ; save parameter to eventhandler_bits
.Ltsk1: mov #EVENT00_bits, R15 ; bitmask, used to scan task bits
mov #eventhandler_table, R14 ; pointer to task function table
.Ltsk2: tst @R14 ; is table entry valid?
jz .Lnoevent ; end of table reached -> exit loop
bit R15, eventhandler_bits ; test mask on event bits
jc .Ldoevent ; if bit is set -> call event function
rrc R15 ; shift mask. carry is zero
incd R14 ; increment pointer on event function
jmp .Ltsk2 ; loop
.Lnoevent: ; if it was last entry...
call #eventhandler_idle
jmp .Ltsk1 ; restart searching on wakeup
.Ldoevent:
bic R15, eventhandler_bits ; clear taskbit we're handling here
call @R14 ; call event handler itself, no need to save registers
jmp .Ltsk1 ; loop
.Leventhandler_end:
.size eventhandler,.Leventhandler_end-eventhandler
--- NEW FILE: eventhandler_idle.S ---
// must include one of the msp430 headerfiles to get the LPM definitions
// doesn't matter which one as all MSP430 are compatible in this respect.
// this one is a small CPU and does not generate too much entries in the
// listing files ;-)
#include <msp430x11x.h>
.global eventhandler_idle
.type eventhandler_idle, @function
eventhandler_idle:
bis #LPM0, r2 ; go in lowpower mode until wakeup trough interrupt
ret
.Leventhandler_idle_end:
.size eventhandler_idle,.Leventhandler_idle_end-eventhandler_idle
--- NEW FILE: flash_erase_segment.c ---
#include <signal.h>
#include <msp430/flash.h>
// FCTL2 must be initialized by the user
critical void flash_erase_segment(void *address) {
FCTL3 = FWKEY; // unlock
FCTL1 = FWKEY|ERASE; // select segment erase
*(unsigned short*)address = 0xffff; // erase
FCTL1 = FWKEY; // disable flash writing
FCTL3 = FWKEY|LOCK; // lock
}
--- NEW FILE: flash_write_byte.c ---
#include <signal.h>
#include <msp430/flash.h>
// FCTL2 must be initialized by the user
// NMI, Oscillator Fault interrupts must be disabled by the user
// byte copy (works with unaligned data)
critical void flash_write(void *dst, const void *src, unsigned int size) {
FCTL3 = FWKEY; // unlock
FCTL1 = FWKEY|WRT; // select write
//going trough the buffer in reverse to save some code memory
while (size) {
size--; //decrement before using as array indexing starts at 0, not 1
((unsigned char *)dst)[size] = ((unsigned char *)src)[size]; // copy
}
FCTL1 = FWKEY; // disable flash writing
FCTL3 = FWKEY|LOCK; // lock
}
--- NEW FILE: flash_write_word.c ---
#include <signal.h>
#include <msp430/flash.h>
// FCTL2 must be initialized by the user
// NMI, Oscillator Fault interrupts must be disabled by the user
// word copy
// data must be word aligned
critical void flash_write_word(void *dst, const void *src, unsigned int size) {
FCTL3 = FWKEY; // unlock
FCTL1 = FWKEY|WRT; // select write
//calculate size in words: divide by two (round down size if it is odd)
size >>= 1;
//going trough the buffer in reverse to save some code memory
while (size) {
size--; //decrement before using as array indexing starts at 0, not 1
((unsigned short *)dst)[size] = ((unsigned short *)src)[size]; // copy
}
FCTL1 = FWKEY; // disable flash writing
FCTL3 = FWKEY|LOCK; // lock
}
--- NEW FILE: fll.c ---
#include <signal.h>
#include <msp430/basic_clock.h>
#include <msp430/timera.h>
// set DCO to selected frequency
// MCLK = multiplier*ACLK
critical void fll_adjust(unsigned short multiplier) {
unsigned short compare;
unsigned short old_capture = 0;
CCTL2 = CCIS0|CM0|CAP; // Define CCR2, CAP, ACLK
TACTL = TASSEL_SMCLK|TACLR|MC1; // SMCLK, continous mode
while (1) {
while (!(CCTL2 & CCIFG)) {} // Wait until capture occured!
CCTL2 &= ~CCIFG; // Capture occured, clear flag
compare = CCR2 - old_capture; // SMCLK difference
old_capture = CCR2; // Save current captured SMCLK
if (multiplier == compare) {
break; // if equal, leave "while(1)"
} else if (multiplier < compare) { // DCO is too fast, slow it down
DCOCTL--;
if (DCOCTL == 0xff) { // Did DCO role under?
BCSCTL1--; // Select next lower RSEL
}
} else {
DCOCTL++;
if (DCOCTL == 0x00) { // Did DCO role over?
BCSCTL1++; // Select next higher RSEL
}
}
}
CCTL2 = 0; // Stop CCR2 function
TACTL = 0; // Stop Timer_A
}
--- NEW FILE: hex_decode.c ---
#include "mspgcc/util.h"
unsigned int hex_decode(void *dst, unsigned int maxsize, const char *src, unsigned int size) {
unsigned int pos = 0;
while ((pos < maxsize) && (pos < size/2)) {
((unsigned char *)dst)[pos] = (hex_fromdigit(src[0])<<4) | hex_fromdigit(src[1]);
src += 2;
pos++;
}
return pos;
}
--- NEW FILE: hex_decode_inline.c ---
#include "mspgcc/util.h"
//decode hex string to binary in place (overwriting the source string)
unsigned int hex_decode_inline(void *srcdst, unsigned int size) {
unsigned char *src = srcdst;
unsigned int pos = 0;
while (pos < size/2) { //calculate size in binary characters not source hex digits
((unsigned char *)srcdst)[pos] = (hex_fromdigit(src[0])<<4) | hex_fromdigit(src[1]);
src += 2;
pos++;
}
return pos;
}
--- NEW FILE: hex_encode.c ---
const unsigned char HEX_DIGITS[16] = "0123456789ABCDEF";
unsigned int hex_encode(char *dst, unsigned int maxsize, const void *src, int size) {
unsigned int pos = 0;
unsigned int count = 0;
while ((maxsize > 2) && (pos < size)) {
unsigned char byte = ((unsigned char*)src)[pos++];
*dst++ = HEX_DIGITS[byte >> 4];
*dst++ = HEX_DIGITS[byte & 0xf];
maxsize -= 2;
count += 2;
}
//write trailing null byte if there is enough space
if (maxsize) {
*dst = '\0';
}
return count;
}
--- NEW FILE: hex_fromdigit.c ---
unsigned char hex_fromdigit(unsigned char x) {
if (x >= '0' && x <= '9') return x - '0';
x |= 0x20; //make letter lowercase
if (x >= 'a' && x <= 'f') return x - ('a' - 10);
return 0;
}
--- NEW FILE: hexdump.c ---
#include <ctype.h>
#include <stdio.h>
//byte reads are used
//this function is not able to dump the 16 bit peripherals
void hexdump(const void *buffer, unsigned int length, unsigned int address) {
const unsigned char *src = buffer;
while (length) {
unsigned int line_length = (length < 16) ? length : 16;
//address
printf("%04x ", address);
//hex dump
for (int i = 0; i < line_length; i++) {
if (i == 8) putchar(' '); //add an additional space after eight values
printf("%02x ", src[i]);
}
//fill for shorter lines
for (int i = 16 - line_length; i; i--) {
if (i == 8) putchar(' '); //add an additional space after eight values
printf(" ");
}
//spacer
printf(" ");
//ascii dump
for (int i = 0; i < line_length; i++) {
putchar(isprint(src[i]) ? src[i] : '.');
}
//finish
putchar('\n');
src += line_length;
length -= line_length;
address += line_length;
}
}
--- NEW FILE: lineeditor.c ---
#include <stdio.h>
#include "mspgcc/util.h"
unsigned char lineeditor_simple_process_key(LINEEDITOR_STATE *state, char key) {
//process the character
switch (key) {
case '\r': // return (is ignored)
break;
case '\n': // newline
putchar((unsigned char)key); // echo
return 1; // exit with true
case '\b': // backspace
case '\x7f': // backspace (alternative)
if (state->position) { // only if line is nonempty
state->position--; // remove last character from the buffer
state->line[state->position] = '\0'; // ensure null termination
putchar('\b'); // overprint last character
putchar(' '); // with a space
putchar('\b'); // reposition cursor
}
break;
default: // text
if (state->position < (state->line_size - 1)) {
state->line[state->position++] = key; // store, advance in buffer
state->line[state->position] = '\0'; // ensure null termination
putchar((unsigned char)key); // echo
}
break;
}
return 0; // line not yet finished, return false
}
--- NEW FILE: makefile ---
# makfile configuration
LIBRARYNAME = mspgcc
CSOURCES = hexdump.c lineeditor.c simple_readline.c fll.c checksum_xor.c \
ringbuffer_put.c ringbuffer_get.c ringbuffer_clear.c ringbuffer_len.c \
flash_erase_segment.c flash_write_byte.c flash_write_word.c \
hex_decode_inline.c hex_decode.c hex_encode.c hex_fromdigit.c \
event_scheduler.c
ASOURCES = eventhandler.S eventhandler_idle.S delay.S
CPU = msp1
ASFLAGS = -mmcu=${CPU} -D_GNU_ASSEMBLER_ -I ../include
CFLAGS = -mmcu=${CPU} -O2 -Wall -std=gnu99 -g -I ../include
#switch the compiler (for the internal make rules)
CC = msp430-gcc
AS = msp430-gcc
AR = msp430-ar
OBJECTS = ${CSOURCES:.c=.o} ${ASOURCES:.S=.o}
.PHONY: all FORCE clean
#all should be the first target. it's built when make is run without args
all: lib$(LIBRARYNAME).a lib$(LIBRARYNAME).lst dependencies.d
lib$(LIBRARYNAME).a: $(OBJECTS)
$(AR) rcf $@ $^
lib$(LIBRARYNAME).lst: lib$(LIBRARYNAME).a
msp430-objdump -dSt $^ >$@
@echo "----- RAM/Flash Usage -----"
msp430-size $^
clean:
rm -f lib$(LIBRARYNAME).a lib$(LIBRARYNAME).lst ${OBJECTS} dependencies.d
#dummy target as dependecy if something has to be build everytime
FORCE:
#project dependencies
dependencies.d:
$(CC) -MM ${CFLAGS} ${CSOURCES} > dependencies.d
ifdef ASOURCES
$(CC) -MM ${ASFLAGS} ${ASOURCES} >> dependencies.d
endif
-include dependencies.d
--- NEW FILE: ringbuffer_clear.c ---
#include "mspgcc/ringbuffer.h"
#include <signal.h>
critical void ringbuffer_clear(RINGBUFFER_TYPE *buffer) {
buffer->fill = 0;
buffer->read_pos = 0;
buffer->write_pos = 0;
}
--- NEW FILE: ringbuffer_get.c ---
#include "mspgcc/ringbuffer.h"
#include <signal.h>
critical int ringbuffer_get(RINGBUFFER_TYPE *buffer) {
//buffer not empty?
if (buffer->fill) {
//wrap around read position
while (buffer->read_pos >= buffer->size) {
buffer->read_pos -= buffer->size;
}
//update size info
buffer->fill--;
//get byte from buffer, update read position and return
return buffer->memory[buffer->read_pos++];
} else {
return -1;
}
}
--- NEW FILE: ringbuffer_len.c ---
#include "mspgcc/ringbuffer.h"
int ringbuffer_len(RINGBUFFER_TYPE *buffer) {
return buffer->fill;
}
--- NEW FILE: ringbuffer_put.c ---
#include "mspgcc/ringbuffer.h"
#include <signal.h>
critical int ringbuffer_put(RINGBUFFER_TYPE *buffer, char character) {
//is there space in the buffer?
if (buffer->fill < buffer->size) {
//wrap around write position
while (buffer->write_pos >= buffer->size) {
buffer->write_pos -= buffer->size;
}
//write the character
buffer->memory[buffer->write_pos++] = character;
//update size info
buffer->fill++;
return buffer->fill;
} else {
return -1;
}
}
--- NEW FILE: simple_readline.c ---
#include "mspgcc/util.h"
//buffer has to be maxlen+1 bytes large
void simple_readline(char *line_buffer, unsigned int maxlen) {
// initialize line editor
LINEEDITOR_STATE lineeditor = {
line: line_buffer,
line_size: maxlen,
};
while (1) {
int key = getchar();
//abort on errors/EOF
if (key < 0) break;
//process the character
if (lineeditor_simple_process_key(&lineeditor, key)) {
break;
}
}
}
-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf