On Jun 17, 2005, at 4:53 AM, Dale Cunningham wrote:
I'm trying to write a bootstrap routine in C that will reside in flash and be copied to RAM for execution. Can anyone give me some helpful hints on how to do that?I've searched the docs for any reference to relocatable code (there will be some subroutines, also in RAM) or preprocessor commands that might be able to specify that this code will be running at a particular address (in this case within the RAM) and haven't been able to find anything that relates to this problem.
I have devised a way to do this for assembly routines. The data and code will be copied to the stack and run from there. The code is in C, but the routine you want to put in the stack must be in assembly for the moment. I have also got some misc routines in there, including buffered SD16 with timestamps, buffered UART in assembly and other stuff. The important routine is WriteBlock() in asmlib.s. It shows how to copy a routine to stack and run it from there. In this case, it is used to write to info memory. I have included the necessary files that should form a good example.
The configuration of this code is in an MSP430F427 with 32.768k XTAL and a multiplexer on analog A2. The selection signal is P2.2.
This whole code is the stuff I want to contribute to the example library of MSPGCC. At the moment, it is not quite "pretty" enough, but I will soon butcher it to parts to form a complete example. The entire code is well commented though.
If any of this code is used, please credit Tennessee Carmel-Veilleux (veill...@tentech.ca)
Best Regards, Tennessee Carmel-Veilleux
/******************************************************************************* * Name: asmlib.h * * Author: Tennessee Carmel-Veilleux * * Created: 05/07/2005 * * Module: USBVoltAmp ASM library declarations * * Version: 1.1 * * Copyright: (C)2005 Tennessee Carmel-Veilleux * * Le Laboratoire de Robotique Pédagogique de l'Université de Montréal peut * * utiliser ce code ainsi que tous les fichiers et composants dérivés pour * * n'importe quel usage qui lui soit utile. * * * * Version history: * * - 1.0 (05/07/2005): Initial release * * - 1.1 (06/04/2005): All basic functions implemented * *******************************************************************************/ #ifndef ASMLIB_H #define ASMLIB_H #include "hardware.h" // Buffered UART buffers extern volatile unsigned char RxQueue[RX_QUEUE_SIZE]; extern volatile unsigned char TxQueue[TX_QUEUE_SIZE]; extern volatile unsigned char RxSize, RxHead, RxTail; extern volatile unsigned char TxSize, TxHead, TxTail; // SD16 buffers and flags extern volatile unsigned short SD16Results[4]; extern volatile unsigned long SD16Timestamps[4]; extern volatile unsigned char SD16Flags; //Function prototypes for the functions in asmlib.S // NO NEED for putchar SINCE IT IS ALREADY DEFINED IN stdio.h // int putchar(int c); int getch(); void WriteBlock(unsigned char *addr); unsigned long int GetIntervalClock(void); #endif //ASMLIB_H
ASMLIB.S
Description: Binary data
/******************************************************************************* * Name: fonctions.c * * Author: Tennessee Carmel-Veilleux * * Created: 05/07/2005 * * Module: USBVoltAmp parser callback functions * * Version: 1.1 * * Copyright: (C)2005 Tennessee Carmel-Veilleux * * Le Laboratoire de Robotique Pédagogique de l'Université de Montréal peut * * utiliser ce code ainsi que tous les fichiers et composants dérivés pour * * n'importe quel usage qui lui soit utile. * * * * Version history: * * - 1.0 (05/07/2005): Initial release * * - 1.1 (06/04/2005): All basic functions implemented * *******************************************************************************/ #include "main.h" #include <stdio.h> #include <string.h> #define putc(c) putchar(c) uint8 EEbuf[128]; // Buffer d'EEPROM (info flash) void RMEM(void) { uint8 d; uint16 a; // Lecture du contenu de la mémoire info (0x1000 à 0x107F) dans le buffer for(a = 0x1000; a < 0x1080; a++) { EEbuf[a-0x1000] = *((uint8 *)(a)); } // Lecture de l'octet désiré a = (uint8)parametre[0]; d = EEbuf[a]; printf("%u\r",d); // Transmission de l'octet if (debug) putc('\n'); } //----------------------------------------------------------------------- // WMEM_x_d<lf><cr> // // Fonction Orphy émulée // Écriture dans l'EEPROM d'un octet. L'écriture se fait seulement // lorsque ZAPPLY appellée (deux blocs de 64 octets s'écriront). // Avant le premier WMEM après un PowerUp ou un ZAPPLY, on doit faire // un ZRMEM dummy pour lire le buffer de l'EEPROM //----------------------------------------------------------------------- void WMEM(void) { uint8 d, a; // Obtention de la donnée et de l'adresse a = (uint8)parametre[0]; d = (uint8)parametre[1]; EEbuf[a] = d; // Écriture dans le buffer printf("%u\r",d); // Transmission de l'octet if (debug) putc('\n'); } //----------------------------------------------------------------------- // APPLY<lf><cr> // // Écriture dans l'EEPROM du bloc EEbuf à partir d'une fonction en // assembleur. Voir WMEM(). //----------------------------------------------------------------------- void APPLY(void) { WriteBlock(EEbuf); putc(ACK_CHAR); putc('\r'); } // Parametre 0: data format (0: DEC, 1:HEX) void DUMP(void) { uint16 i; if (debug) printf("Affichage à partir de $1000 + 0\n\r"); else { if (parametre[0]) { printf("*0000\r"); } else { printf("*0\r"); } } for (i = 0; i < 128; i++) { if (parametre[0]) { printf("%02X",EEbuf[i]); } else { printf("%u",EEbuf[i]); } if (debug) putc(' '); else putc('\r'); } }
/******************************************************************************* * Name: hardware.h * * Author: Tennessee Carmel-Veilleux * * Created: 05/07/2005 * * Module: USBVoltAmp hardware constants * * Version: 1.1 * * Copyright: (C)2005 Tennessee Carmel-Veilleux * * Le Laboratoire de Robotique Pédagogique de l'Université de Montréal peut * * utiliser ce code ainsi que tous les fichiers et composants dérivés pour * * n'importe quel usage qui lui soit utile. * * * * Version history: * * - 1.0 (05/07/2005): Initial release * * - 1.1 (06/04/2005): All basic functions implemented * *******************************************************************************/ #ifndef HARDWARE_H #define HARDWARE_H #define __MSP430_427__ #include <io.h> #include <signal.h> #include <iomacros.h> #define FALSE 0 #define TRUE 1 #define NULL 0 //#define SMCLK (1048576ul) #define SMCLK (2097152ul) #define HOST_BAUD (115200ul) #define LED0 0x01 // LED0 is on P2.0 #define SW0 0x02 // SW0 is on P2.1 #define CHAN_SEL 0x04 // SEL is on P2.2 //Port Output Register 'P1OUT, P2OUT': #define P1OUT_INIT 0 // Init Output data of port1 #define P2OUT_INIT 0 // Init Output data of port2 //Port Direction Register 'P1DIR, P2DIR': #define P1DIR_INIT 0xff // Init of Port1 Data-Direction Reg (Out=1 / Inp=0) #define P2DIR_INIT 0x15 // Init of Port2 Data-Direction Reg (Out=1 / Inp=0) //Selection of Port or Module -Function on the Pins 'P1SEL, P2SEL' #define P1SEL_INIT 0x22 // P1-Modules: #define P2SEL_INIT 0x30 // P2-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) // WDT in interval mode for RTC (ACLK / 32768 interrupt rate) #define WDTCTL_INIT (WDTPW | WDTTMSEL | WDTCNTCL | WDTSSEL) // TimerA in continuous up mode, interrupt on overflow, clear on init, Clk = (ACLK / 8) (4096 Hz) #define TACTL_INIT (TASSEL0 | MC1 | ID1 | ID0 | TAIE) #define ACK_CHAR '^' /* UART queue constants */ #define RX_QUEUE_SIZE 32 #define TX_QUEUE_SIZE 16 /* SD16 init values for 1048581 Hz */ #define SD16CTL_INIT (SD16DIV0 | SD16SSEL1 ) // External reference, ACLK / 2 clock (16384 Hz) #define SD16CCTL0_INIT (SD16IE | SD16GRP) // CH0 Interrupt enabled, group operation, 256:1, 16 MSB, continuous, offset binary #define SD16CCTL1_INIT (SD16IE ) // CH1 Interrupt enabled, master of CH0, 256:1, 16 MSB, continuous, offset binary #define SD16CCTL2_INIT (SD16IE | SD16OSR0) // CH2 Interrupt enabled, 128:1, 16 MSB, continuous, offset binary #define SD16INCTL0_INIT 0x00 // CH0 on A0 #define SD16INCTL1_INIT 0x01 // CH1 on A1 #define SD16INCTL2_INIT (0x02) // CH2 on A2 --- SHORT ON A2 /* SD16Flags values */ #define CH0_F 0x01 #define CH1_F 0x02 #define CH2_1_F 0x04 #define CH2_2_F 0x08 #define SECOND_F 0x10 // New second flag #define CH2_OFFSET (32768 - 32748) /* UART Stuff, macro taken from code by: */ /** Copyright 2002, R O SoftWare * No guarantees, warrantees, or promises, implied or otherwise. * May be used for hobby or commercial purposes provided copyright * notice remains intact. */ /* uart0 1048581Hz 9602bps */ /* #define UBR00_INIT 0x6D #define UBR10_INIT 0x00 #define UMCTL0_INIT 0x44 */ #define USART0_BRCLK SMCLK // System Data Rates /////////////////////////////////////////////////////////////////////////////// // use the following macros to determine the 'baudDiv' parameter values // for usartInit0() and usartInit1() // CAUTION - 'baud' SHOULD ALWAYS BE A CONSTANT or // a lot of code will be generated. #define USART0_BAUD_DIV(baud) (uint16_t)(USART0_BRCLK / (baud)) /////////////////////////////////////////////////////////////////////////////// // the following are used to calculate the UMOD values at compile time #define CMOD_0(baud) ((USART0_BRCLK / (baud)) - USART0_BAUD_DIV(baud)) #define CMOD_1(baud) ((USART1_BRCLK / (baud)) - USART1_BAUD_DIV(baud)) #define M0_0(baud) (CMOD_0(baud) + CMOD_0(baud)) #define M0_1(baud) (CMOD_1(baud) + CMOD_1(baud)) #define M1_0(baud) (M0_0(baud) + CMOD_0(baud)) #define M1_1(baud) (M0_1(baud) + CMOD_1(baud)) #define M2_0(baud) (M1_0(baud) + CMOD_0(baud)) #define M2_1(baud) (M1_1(baud) + CMOD_1(baud)) #define M3_0(baud) (M2_0(baud) + CMOD_0(baud)) #define M3_1(baud) (M2_1(baud) + CMOD_1(baud)) #define M4_0(baud) (M3_0(baud) + CMOD_0(baud)) #define M4_1(baud) (M3_1(baud) + CMOD_1(baud)) #define M5_0(baud) (M4_0(baud) + CMOD_0(baud)) #define M5_1(baud) (M4_1(baud) + CMOD_1(baud)) #define M6_0(baud) (M5_0(baud) + CMOD_0(baud)) #define M6_1(baud) (M5_1(baud) + CMOD_1(baud)) #define M7_0(baud) (M6_0(baud) + CMOD_0(baud)) #define M7_1(baud) (M6_1(baud) + CMOD_1(baud)) #define C0_0(baud) (uint8_t)((int)M0_0(baud) ? BV(0) : 0) #define C0_1(baud) (uint8_t)((int)M0_1(baud) ? BV(0) : 0) #define C1_0(baud) (uint8_t)(((int)M1_0(baud) - (int)M0_0(baud)) ? BV(1) : 0) #define C1_1(baud) (uint8_t)(((int)M1_1(baud) - (int)M0_1(baud)) ? BV(1) : 0) #define C2_0(baud) (uint8_t)(((int)M2_0(baud) - (int)M1_0(baud)) ? BV(2) : 0) #define C2_1(baud) (uint8_t)(((int)M2_1(baud) - (int)M1_1(baud)) ? BV(2) : 0) #define C3_0(baud) (uint8_t)(((int)M3_0(baud) - (int)M2_0(baud)) ? BV(3) : 0) #define C3_1(baud) (uint8_t)(((int)M3_1(baud) - (int)M2_1(baud)) ? BV(3) : 0) #define C4_0(baud) (uint8_t)(((int)M4_0(baud) - (int)M3_0(baud)) ? BV(4) : 0) #define C4_1(baud) (uint8_t)(((int)M4_1(baud) - (int)M3_1(baud)) ? BV(4) : 0) #define C5_0(baud) (uint8_t)(((int)M5_0(baud) - (int)M4_0(baud)) ? BV(5) : 0) #define C5_1(baud) (uint8_t)(((int)M5_1(baud) - (int)M4_1(baud)) ? BV(5) : 0) #define C6_0(baud) (uint8_t)(((int)M6_0(baud) - (int)M5_0(baud)) ? BV(6) : 0) #define C6_1(baud) (uint8_t)(((int)M6_1(baud) - (int)M5_1(baud)) ? BV(6) : 0) #define C7_0(baud) (uint8_t)(((int)M7_0(baud) - (int)M6_0(baud)) ? BV(7) : 0) #define C7_1(baud) (uint8_t)(((int)M7_1(baud) - (int)M6_1(baud)) ? BV(7) : 0) /////////////////////////////////////////////////////////////////////////////// // use the following macros to determine the 'baudMod' parameter values // CAUTION - 'baud' SHOULD ALWAYS BE A CONSTANT or // a lot of code will be generated. #define USART0_BAUD_MOD(baud) (uint8_t)(C7_0(baud) + C6_0(baud) + C5_0(baud) + \ C4_0(baud) + C3_0(baud) + C2_0(baud) + \ C1_0(baud) + C0_0(baud)) /* uart0 Init parameters */ #define UBR00_INIT (uint8_t)((uint16_t)(USART0_BRCLK / (HOST_BAUD)) >> 0) #define UBR10_INIT (uint8_t)((uint16_t)(USART0_BRCLK / (HOST_BAUD)) >> 8) #define UMCTL0_INIT USART0_BAUD_MOD(HOST_BAUD) #endif //HARDWARE_H
/******************************************************************************* * Name: main.c * * Author: Tennessee Carmel-Veilleux * * Created: 05/07/2005 * * Module: USBVoltAmp mainline code * * Version: 1.1 * * Copyright: (C)2005 Tennessee Carmel-Veilleux * * Le Laboratoire de Robotique Pédagogique de l'Université de Montréal peut * * utiliser ce code ainsi que tous les fichiers et composants dérivés pour * * n'importe quel usage qui lui soit utile. * * * * Version history: * * - 1.0 (05/07/2005): Initial release * * - 1.1 (06/04/2005): All basic functions implemented * *******************************************************************************/ #include "main.h" #include <stdio.h> #include <ctype.h> #include <string.h> #include <signal.h> // Buffered UART buffers volatile unsigned char RxQueue[RX_QUEUE_SIZE]; volatile unsigned char TxQueue[TX_QUEUE_SIZE]; volatile unsigned char RxSize, RxHead, RxTail; volatile unsigned char TxSize, TxHead, TxTail; // SD16 buffers and flags volatile unsigned short SD16Results[4]; volatile unsigned long SD16Timestamps[4]; volatile unsigned char SD16Flags; // Interval clock counter volatile uint16 IntervalHi; // Interval clock high part volatile uint32 IntervalClock; // Interval clock void InitUART(void); void Initialization(void); void delay(unsigned int d); void InitUART(void) { U0CTL = SWRST; //reset UART // Set baud rate UBR00 = UBR00_INIT; UBR10 = UBR10_INIT; UMCTL0 = UMCTL0_INIT; U0CTL |= CHAR; // UART ON, 8N1, No loopback U0ME |= UTXE0 | URXE0; // Enable USART0 TX and RX (UART mode) U0TCTL = SSEL_SMCLK | TXEPT; //use SMCLK U0RCTL = 0; // Clear USART0 errors // Initialize the queue TxSize = 0; RxSize = 0; TxHead = 0; RxHead = 0; TxTail = 0; RxTail = 0; U0CTL &= ~SWRST; // Unreset UART IE1 |= UTXIE0 | URXIE0; // Enable USART interrupts } void InitSD16(void) { // See HARDWARE.H for more info about settings SD16CTL = SD16CTL_INIT; SD16CCTL0 = SD16CCTL0_INIT; SD16CCTL1 = SD16CCTL1_INIT; SD16CCTL2 = SD16CCTL2_INIT; SD16INCTL0 = SD16INCTL0_INIT; SD16INCTL1 = SD16INCTL1_INIT; SD16INCTL2 = SD16INCTL2_INIT; SD16Flags = 0; SD16CCTL1 |= SD16SC; // Start conversions on CH0/CH1 SD16CCTL2 |= SD16SC; // Start conversions on CH2 } void Initialization(void) { FLL_CTL0 = 0x90; // Set XTAL caps to 6pF and DCO_PLUS=1 WDTCTL = WDTCTL_INIT; //Init watchdog timer TAR = 0; // Init TimerA counter to 0 TACTL = TACTL_INIT; // Init TimerA P1OUT = P1OUT_INIT; //Init output data of port1 P2OUT = P2OUT_INIT; //Init output data of port2 P1SEL = P1SEL_INIT; //Select port or module -function on port1 P2SEL = P2SEL_INIT; //Select port or module -function on port2 P1DIR = P1DIR_INIT; //Init port direction register of port1 P2DIR = P2DIR_INIT; //Init port direction register of port2 P1IES = P1IES_INIT; //init port interrupts P2IES = P2IES_INIT; P1IE = P1IE_INIT; P2IE = P2IE_INIT; IE1 |= WDTIE; // Enable watchdog timer interrupt InitUART(); InitSD16(); } /** Delay function. */ void delay(unsigned int d) { int i; for (i = 0; i<d; i++) { nop(); nop(); } } void blink(int n) { int i; for (i = 0; i < n; i++) { P2OUT |= LED0; delay(0x4000); P2OUT &= ~LED0; delay(0x4000); } } /** Main function with some blinking leds */ int main(void) { unsigned short i = 0; int count[4]; unsigned int value[4]; Initialization(); eint(); delay(0x400); blink(3); while (1) { //main loop, never ends... if (SD16Flags & CH0_F) { count[0] ++; value[0] = SD16Results[0]; SD16Flags &= ~CH0_F; } if (SD16Flags & CH1_F) { count[1] ++; value[1] = SD16Results[1]; SD16Flags &= ~CH1_F; } if (SD16Flags & CH2_1_F) { count[2] ++; value[2] = SD16Results[2]; SD16Flags &= ~CH2_1_F; } if (SD16Flags & CH2_2_F) { count[3] ++; value[3] = ((SD16Results[3] + (unsigned int)CH2_OFFSET) - 0x7FFF) >> 4; SD16Flags &= ~CH2_2_F; printf("%5u,%5u,%5u,%5u\n\r",value[0],value[1],value[2],value[3]); //printf("%5u\n\r",value[3]); } if (SD16Flags & SECOND_F) { printf("%2u,%2u,%2u,%2u\n\r",count[0],count[1],count[2],count[3]); count[0] = count[1] = count[2] = count[3] = 0; SD16Flags &= ~SECOND_F; P2OUT ^= LED0; } } }
/******************************************************************************* * Name: main.h * * Author: Tennessee Carmel-Veilleux * * Created: 05/07/2005 * * Module: USBVoltAmp mainline code header * * Version: 1.1 * * Copyright: (C)2005 Tennessee Carmel-Veilleux * * Le Laboratoire de Robotique Pédagogique de l'Université de Montréal peut * * utiliser ce code ainsi que tous les fichiers et composants dérivés pour * * n'importe quel usage qui lui soit utile. * * * * Version history: * * - 1.0 (05/07/2005): Initial release * * - 1.1 (06/04/2005): All basic functions implemented * *******************************************************************************/ #include <sys/inttypes.h> #include "hardware.h" #include "asmlib.h" // Nombre de commandes #define MAX_COMMANDES 16 // Longueur max de commande #define LG_SYMB 6 // Longueur max de ligne de commande #define LG_STRING 32 // Nombre de paramètres MAX #define N_PARAM 6 #define putc(c) putchar(c) #define kbhit() (RxSize != 0) typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned long uint32; extern int parametre[N_PARAM]; // paramètres de la ligne de commande extern int code; // Code de commande extern int debug; // Flag de débug extern uint8 EEbuf[128]; // Buffer d'EEPROM (info flash) extern volatile uint16 IntervalHi; // Interval timer high part extern volatile uint32 IntervalClock; // Interval Timer // Fonctions et commandes de l'interpréteur void ResetInterval(void); void PORT(void); void ECHO(void); void WMEM(void); void RMEM(void); void MES(void); void EA(void); void RECO(void); void CHAN(void); void FILT(void); void GAIN(void); void ACQ(void); void APPLY(void); void DUMP(void); void RAW(void); void CLR(void); void CLK(void);