- FAE/Client Login
- product registration
- > Download <
- Our products
- Support
- FAQs
- technical support
- Application Notes
- Device List
- Hints and Tips
- Product-specific Notes
- Resources
- Articles on embedded topics
- An introduction to USB and C, with sample code.
- A way to prove C compilers can match and beat macro assembly
- Embedded programming, C standards, and our contribution.
- Exceptional Programming
- Fixed-point math
- Fuzzy Logic adds new design options for embedded programming.
- Linking C functions to eTPU channel functions
- Moving from C6805 to C6808
- Something SPECIAL
- Touch sensitive switch
- C Language Resources
- eTPU_C Glossary
- Glossary of Embedded Systems Terminology
- Product-Specific Resources
- Articles on embedded topics
- Fuzzy Logic
- Publishing
- What's New
- About Us
- more information
Something SPECIAL: put variables anywhere
Byte Craft Limited's compilers support SPECIAL memory: user-declared memory blocks accessed (read and written) by software. The compiler manages allocation for SPECIAL memory similarly to system RAM and ROM. The result is a seamless integration of off-chip or on-chip memory resources into C language programs. Even persistent memory can host C language variables.
This is an example showing two different ways to access EEPROM: by library functions and through SPECIAL memory variables. Both methods ultimately use the same library functions.
First, we declare the library routines and related macros that drive the EEPROM in both cases:
//EEPROM functionality
000C #define Enable_EE_WR EECON1.WREN = 1
000D #define Disable_EE_WR EECON1.WREN = 0
000E #define EEProm_Rd EECON1.EERD = 1
000F #define Do_EE_Write #asm( BSF 0x08,1)
0010 #define EEProm_Writing EECON1.EEWR
//EEPROM API
int Read_EEProm(registerw addr);
void Write_EEProm(registerx addr, registerw data);
Next, we link the compiler's variable allocation system with the library routines through a SPECIAL declaration. SPECIAL expects two routines to be declared with names based on the "eeprom" area name.
//SPECIAL MEMORY DECLARATION
0000 003F #pragma memory SPECIAL eeprom [0x3F] @ 0x00;
//required identifier to point to API functions
0011 #define eeprom_r Read_EEProm
//recreates write described below
0012 #define eeprom_w(addr,data) \
{Write_EEProm(addr,data); while(EEProm_Writing); Disable_EE_WR;}
//SPECIAL VARIABLE DECLARATIONS
0000 0001 char eeprom a,b;
The program begins with traditional, function-based access:
void main()
{
004F 004E unsigned int addr, data;
0005 3018 MOVLW 18h data = 0x18; // Data to be written/read
0006 00CE MOVWF 4E
0007 01CF CLRF 4F addr = 0x00; // Address to write to
//-------------- EEPROM WRITE ----------------
0008 084F MOVF 4F,W Write_EEProm(addr,data);
0009 0084 MOVWF FSR
000A 084E MOVF 4E,W
000B 2037 CALL 0037h
000C 1683 BSF STATUS,RP0 while(EEProm_Writing); // Wait till data written
000D 1888 BTFSC 88,1
000E 280C GOTO 000Ch
000F 1108 BCF 88,2 Disable_EE_WR; // Good practice if no more writes
//--------------- EEPROM READ -----------------
0010 084F MOVF 4F,W data = Read_EEProm(addr); // Read data back from EEPROM
0011 2030 CALL 0030h
0012 00CE MOVWF 4E
0013 1683 BSF STATUS,RP0 TRISB = 0x00;
0014 0186 CLRF 86
0015 1283 BCF STATUS,RP0 PORTB = data; // Port B is connected to LEDs
0016 0086 MOVWF PORTB
Compare this with access through SPECIAL variables, declared above:
//------------- EEPROM READ through SPECIAL ---
0017 3000 MOVLW 00h PORTB = a;
0018 2030 CALL 0030h
0019 1283 BCF STATUS,RP0
001A 0086 MOVWF PORTB
001B 3001 MOVLW 01h PORTB = b;
001C 2030 CALL 0030h
001D 1283 BCF STATUS,RP0
001E 0086 MOVWF PORTB
//------------- EEPROM WRITE through SPECIAL --
001F 0184 CLRF FSR a = 23;
0020 3017 MOVLW 17h
0021 2037 CALL 0037h
0022 1683 BSF STATUS,RP0
0023 1888 BTFSC 88,1
0024 2822 GOTO 0022h
0025 1108 BCF 88,2
0026 3001 MOVLW 01h b = PORTB;
0027 0084 MOVWF FSR
0028 1283 BCF STATUS,RP0
0029 0806 MOVF PORTB,W
002A 2037 CALL 0037h
002B 1683 BSF STATUS,RP0
002C 1888 BTFSC 88,1
002D 282B GOTO 002Bh
002E 1108 BCF 88,2
} // main()
And finally, the EEPROM library routines themselves:
///////////////////////////////////////////////////
int Read_EEProm(registerw addr)
0000 {
0030 1283 BCF STATUS,RP0 EEADR = addr;
0031 0089 MOVWF EEADR
0032 1683 BSF STATUS,RP0 EEProm_Rd;
0033 1408 BSF 88,0
0034 1283 BCF STATUS,RP0 return(EEDATA);
0035 0808 MOVF EEDATA,W
0036 0008 RETURN
}
///////////////////////////////////////////////////
void Write_EEProm(registerx addr, registerw data)
0000 0000 {
0037 1683 BSF STATUS,RP0 Enable_EE_WR;
0038 1508 BSF 88,2
0039 1283 BCF STATUS,RP0 EEDATA = data;
003A 0088 MOVWF EEDATA
003B 0804 MOVF FSR,W EEADR = addr;
003C 0089 MOVWF EEADR
003D 1683 BSF STATUS,RP0 STATUS.RP0 = 1;
003E 138B BCF INTCON,GIE INTCON.GIE=0;
#asm
003F 3055 MOVLW 55H ;Sequence must be coded exactly
0040 0089 MOVWF 09 ;as shown according to data book.
0041 30AA MOVLW 0AAh
0042 0089 MOVWF 09
#endasm
0043 1488 BSF EEDATA,1 Do_EE_Write;
0044 178B BSF INTCON,GIE INTCON.GIE = 1;
0045 0008 RETURN }
The SPECIAL variables even show up in the symbol table; when you have a lot of them, this information helps in debugging.
SYMBOL TABLE LABEL VALUE LABEL VALUE a 0000 | b 0001
SPECIAL memory makes for cleaner, more intuitive code. After the read and write driver routines are added, each new variable requires only a declaration.
SPECIAL memory will in time give way to _Access memory. Byte Craft Limited participates in ISO/IEC WG 14, the group responsible for evolving the C language international standard. Our experience with SPECIAL helped inform ISO/IEC TR 18037, the technical report that extends C with embedded-specific functionality. _Access declarations are similar to SPECIAL in almost all respects.

New: