How to use MSP430 DriverLib ROM
Steps to utilize DriverLib in ROM from a user
application
- Please locate rom_driverlib.h. A copy can be found inside
driverlib/{FAMILY}
- Optional but recommended step: Please
locate rom_map_driverlib.h. A copy can be found inside
driverlib/{FAMILY}
- Please locate rom_headers/ directory. A copy can be found
inside driverlib/{FAMILY}
- By default, the rom_driverlib.h you use must be at same
directory level as rom_headers/
- Make sure #include "driverlib.h" is present in the application code
- By default, driverlib.h includes the necessary rom_headers on applicable device families
- rom_driverlib.h
- rom_driverlib.h will automatically map you to the
specific ROM
header file for the
device you are using inside rom_headers/.
- The device specific ROM header file defines ROM_
functions and allows them for use.
- The source code is in the device's ROM whether used or
not, but using ROM_ functions will tell your application where in
memory to find the function.
- rom_map_driverlib.h
- This step is technically
optional, but highly
recommended. Without this file, MAP_ functions will not be available.
- Using MAP_{API_NAME} will use ROM_{API_NAME} when
possible, and {API_NAME} from a linked source/library out of flash/FRAM
when not.
- This will create a seamless functional experience for the
user application.
- You may use ROM_ functions directly to force a call into
ROM for the function, but keep in mind not every DriverLib API has a
ROM equivalent.
- MAP_ functions provide all the benefits of ROM_ functions
while abstracting the need to know which specific ROM_ functions exist.
- Using MAP_ functions also keeps your application code
portable across devices in the same family.
Details about MSP430 DriverLib ROM feature
- Not every device has MSP430 DriverLib in ROM. Please
consult device's datasheet to see if it is available.
- Not every device's ROM holds the same subset of DriverLib.
- DriverLib in ROM is tested to work with both CCS and IAR
compilers.
- Because the calling conventions between the two compilers
are slightly different, the ROM image must adhere to a certain __cc_rom
convention that
both compilers can agree upon. As such, there are certain limitations
on a user application using ROM.
- #include "rom_driverlib.h" will continue to provide
helpful hints at build time until the user application adheres to __cc_rom
- For more information, please consult the MSP430 IAR
or
CCS compiler User's Guide on the __cc_rom
calling convention.
- For example, IAR has options to reserve R4/R5 for
global variables. CCS has no such option. Therefore on common ground,
an IAR user
application must declare R4/R5 to be free and not reserved in order to
utilize ROM.
- There may also be certain limitations to user application
based off device-specific ROM designs.
- For example, if the DriverLib ROM image lives above 64k
memory addresses, it would make sense that the user application must be
large code model (20-bit address pointer rather than 16-bit).
Benefits of using MSP430 DriverLib ROM
- Code execution is faster out of ROM than flash/FRAM.
Without flash/FRAM wait states, code execution performance is only
limited by your processor clock, which is generally faster than other
subsystems. Executing your code out of RAM would give comparable
performance, but the available RAM size is typically more limited.
- Leaves more nonvolatile storage (flash/FRAM) available in
your device for application code rather than software libraries.
Code example using ROM
Taken from MSP430FR2xx_4xx DriverLib example: adc_ex1_avccRef.c.
#include "driverlib.h"
#include "Board.h"
void main (void)
{
//Stop Watchdog Timer
//NOTE: Example of what to do if you need to execute from ROM; use ROM_ prefix
//NOTE: You may get a build error if particular function is not in ROM
ROM_WDT_A_hold(WDT_A_BASE);
//Set A7 as an input pin.
//Set appropriate module function
//NOTE: Example of what to do if you need to execute from FRAM; leave out ROM_ and MAP_ prefix
//NOTE: You will need to provide DriverLib source for this function
GPIO_setAsPeripheralModuleFunctionInputPin(
GPIO_PORT_ADC7,
GPIO_PIN_ADC7,
GPIO_FUNCTION_ADC7);
//Set LED1 as an output pin.
//NOTE: Using MAP_ will execute from ROM if available, FRAM if not available
MAP_GPIO_setAsOutputPin(
GPIO_PORT_LED1,
GPIO_PIN_LED1);
//Set LED2 as an output pin.
MAP_GPIO_setAsOutputPin(
GPIO_PORT_LED2,
GPIO_PIN_LED2);
/*
* Disable the GPIO power-on default high-impedance mode to activate
* previously configured port settings
*/
MAP_PMM_unlockLPM5();
//Initialize the ADC Module
/*
* Base Address for the ADC Module
* Use internal ADC bit as sample/hold signal to start conversion
* USE MODOSC 5MHZ Digital Oscillator as clock source
* Use default clock divider of 1
*/
MAP_ADC_init(ADC_BASE,
ADC_SAMPLEHOLDSOURCE_SC,
ADC_CLOCKSOURCE_ADCOSC,
ADC_CLOCKDIVIDER_1);
MAP_ADC_enable(ADC_BASE);
/*
* Base Address for the ADC Module
* Sample/hold for 16 clock cycles
* Do not enable Multiple Sampling
*/
MAP_ADC_setupSamplingTimer(ADC_BASE,
ADC_CYCLEHOLD_16_CYCLES,
ADC_MULTIPLESAMPLESDISABLE);
//Configure Memory Buffer
/*
* Base Address for the ADC Module
* Use input A7
* Use positive reference of AVcc
* Use negative reference of AVss
*/
MAP_ADC_configureMemory(ADC_BASE,
ADC_INPUT_A7,
ADC_VREFPOS_AVCC,
ADC_VREFNEG_AVSS);
MAP_ADC_clearInterrupt(ADC_BASE,
ADC_COMPLETED_INTERRUPT);
//Enable Memory Buffer interrupt
MAP_ADC_enableInterrupt(ADC_BASE,
ADC_COMPLETED_INTERRUPT);
for (;;)
{
//Delay between conversions
__delay_cycles(5000);
//Enable and Start the conversion
//in Single-Channel, Single Conversion Mode
MAP_ADC_startConversion(ADC_BASE,
ADC_SINGLECHANNEL);
//LPM0, ADC10_ISR will force exit
__bis_SR_register(CPUOFF + GIE);
//For debug only
__no_operation();
}
}
//ADC10 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=ADC_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(ADC_VECTOR)))
#endif
void ADC_ISR (void)
{
switch (__even_in_range(ADCIV,12)){
case 0: break; //No interrupt
case 2: break; //conversion result overflow
case 4: break; //conversion time overflow
case 6: break; //ADC10HI
case 8: break; //ADC10LO
case 10: break; //ADC10IN
case 12: //ADC10IFG0
//(Automatically clears ADC10IFG0 by reading memory buffer)
if (MAP_ADC_getResults(ADC_BASE) < 0x1FF){
//Turn LED1 off
MAP_GPIO_setOutputLowOnPin(
GPIO_PORT_LED1,
GPIO_PIN_LED1
);
//Turn LED2 off
MAP_GPIO_setOutputLowOnPin(
GPIO_PORT_LED2,
GPIO_PIN_LED2
);
}
else {
//Turn LED1 on
MAP_GPIO_setOutputHighOnPin(
GPIO_PORT_LED1,
GPIO_PIN_LED1
);
//Turn LED2 on
MAP_GPIO_setOutputHighOnPin(
GPIO_PORT_LED2,
GPIO_PIN_LED2
);
}
//Clear CPUOFF bit from 0(SR)
//Breakpoint here and watch ADC_Result
__bic_SR_register_on_exit(CPUOFF);
break;
default: break;
}
}