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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.