CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

write flash memory in bootloader
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
naughty_mark



Joined: 29 Aug 2012
Posts: 97

View user's profile Send private message

write flash memory in bootloader
PostPosted: Thu Sep 06, 2012 12:11 am     Reply with quote

Hi, there

I am coming back with some questions about writting flash memory in bootloader Embarassed

I use dsPIC33EP256MU814 with ccs compiler v4.133

I can't understand how to write to "write latches", I reused microchip example, but it has microchip built in function named "__builtin_tblwtl(0, writeData.word.LW)" and "__builtin_tblwth(1, writeData.word.HW)",
I am wondering what it is done in it.

with ASM, it is
Load_Write_Latch_Word:
; W2 points to the address of
; Set up a pointer to the fir
MOV #0xFA,W0
MOV W0,TBLPAG
MOV #0,W1
; Perform the TBLWT instructi
TBLWTL [W2++],[W1]
TBLWTH [W2++],[W1++]
TBLWTL [W2++],[W1]
TBLWTH [W2++],[W1++]

I can not figure out how to the instruction "TBLWTL" and "TBLWTH" , what's the two paras w1 and w2 means? where can I put the value that I want to load to relevant write latches? Anyone can help? Thanks a lot!

Regards
Mark
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Thu Sep 06, 2012 12:26 am     Reply with quote

CCS C has built-in function write_program_memory() for flash programming. Please refer to the
PCD bootloader examples.

Of course you can code everything in assembler if you like to. In this case you should read the dsPIC family
reference manual section about flash programming. Your post seems to suggest that you don't actually want to.
naughty_mark



Joined: 29 Aug 2012
Posts: 97

View user's profile Send private message

PostPosted: Thu Sep 06, 2012 12:52 am     Reply with quote

Sorry, I lost one piece of information
"W2 points to the address of the data to write to the latches"

I guess W1 means the offset of TBLPAG (the start address of write latch), and W2 is the pointer to the address of the value that I want to put it into the flash? Am I correct?
Thanks
naughty_mark



Joined: 29 Aug 2012
Posts: 97

View user's profile Send private message

PostPosted: Thu Sep 06, 2012 1:00 am     Reply with quote

FvM wrote:
CCS C has built-in function write_program_memory() for flash programming. Please refer to the
PCD bootloader examples.

Of course you can code everything in assembler if you like to. In this case you should read the dsPIC family
reference manual section about flash programming. Your post seems to suggest that you don't actually want to.


Laughing Thanks FvM, you know I searched the PCD manual but just see read_flash_memory, and didn't see write_flash_memory even it is just in front of me!! maybe too tiered today.
One more question about write_flash_memory function.
write_program_memory(address, dataptr, count);
The "address" is the flash memory address I want to write in, such as 0x4000, not the write latch address, because that will not make sense for this function. am I right?
And if I use this function, the ccs will do everything for me such as disable global interrupt, then send 0x55 and 0xAA to NVMCON register, and balabala, what I need to do is just use it and check the WR bit in NVMCON to see if the program finish, am I right?

Thanks a lot!
jeremiah



Joined: 20 Jul 2010
Posts: 1342

View user's profile Send private message

PostPosted: Thu Sep 06, 2012 6:37 am     Reply with quote

There is no write latch address in reality. The way it works is each time is something like this:

W2 stores the RAM address of the data you wish to write
W1 stores the ROM (flash) address you which to write to.

*NOTE: this is using your code example values. W2 and W1 could be any working registers.

Each call to TBLWTL and TBLWTH takes those values and puts them in the appropriate "write latch" area. This should be done until the whole "write latch" area is full. This is usually an entire row for dsPIC33, or around 256 bytes/128 words/64 instructions typically. Once all of those are written to, toggling the appropriate bits in NVMCON will initiate the write process which takes the data from the write latch area and moves it all into flash. When it is done, a bit changes state to indicate it.

The write_program_memory() method does all of this for you, plus puts interrupt disables around critical parts, and even erases the page first (which must be done before writing to any part of the page) if the address given is the start of the page.

This is something important to note: You must erase a section before it can be written to, otherwise the write won't be permanent. dsPIC33's erase in pages (0x0400 words) and write in rows (0x0080), so it usually looks something like this in general:
Code:

addr = page_addr;
write_program_memory(addr,data);
addr+=0x0080;
write_program_memory(addr,data);
addr+=0x0080;
etc.

where data is 256 bytes.

That said, you can use write_program_memory() to write less than 256 bytes, but whatever you write has to be a multiple of 4 bytes (or 2 words or 1 instruction). The write_program_memory() will fill in the rest of the row for you without overwriting other values already there.
naughty_mark



Joined: 29 Aug 2012
Posts: 97

View user's profile Send private message

PostPosted: Thu Sep 06, 2012 4:00 pm     Reply with quote

jeremiah wrote:
There is no write latch address in reality. The way it works is each time is something like this:

W2 stores the RAM address of the data you wish to write
W1 stores the ROM (flash) address you which to write to.

*NOTE: this is using your code example values. W2 and W1 could be any working registers.


Thanks for your great help, Jeremiah. I will be aware what you mentioned, and hope my code can run today~ Wink
Thank you again.
naughty_mark



Joined: 29 Aug 2012
Posts: 97

View user's profile Send private message

PostPosted: Thu Sep 06, 2012 4:53 pm     Reply with quote

Hi, guys,

I come back with some new questions.

Because I use ccs compiler, it is not like MPLAB compiler that have a .gld file (like link file), so my question is how can I tell the ccs compiler that I want to compile my bootloader file from address 0x7FC000 to 0x7FFFF8 (Auxiliary program flash memory)?
and because I use uart1 to receive my main program hex file, and it will have uart1 interrupt under bootloader code, so do I need to relocate the uart1 interrupt address? if yes, how?

So far, what I tried is add "#include <pcd_bootloader.h>" the ccs header file into my program and write "#org LOADER_ADDR, LOADER_END auto=0 default" and at the end of line of main.c, I write "#org default"
Code:

#if defined(__PCD__)
#include <33EP256MU814.h>
//#include <i2c.h>
#fuses HS,PR,NOWDT,ICSP2
//#build(reset = 0x7FFFFFE, interrupt = 0x7FFFFFA)
//CKSFSM -enable oscillator clock switching mode when a OSC failure has occurred.
//#build (stack=256)
//#build (stack=0x1E00:0x1FFF)
#device ADC=12
#use delay(clock=20000000) // Actual crystal is 20M
#pin_select U1TX = PIN_D0
#pin_select U1RX = PIN_D1
#pin_select U2TX = PIN_D2
#pin_select U2RX = PIN_D3
#use RS232(UART1, STREAM = GSM, BAUD=9600, XMIT = PIN_D0 , RCV = PIN_D1 ,  BITS = 8, STOP = 1, PARITY = N, ERRORS) // Actual Baud is 38400 due to clock (10M not 20M)
#use RS232(UART2, STREAM = MODBUS, BAUD=9600, XMIT = PIN_D2 , RCV = PIN_D3 ,  BITS = 8, STOP = 1, PARITY = N, ERRORS) // Actual Baud is 38400 due to clock (10M not 20M)
//#use spi(MASTER, DO = PIN_G8, CLK = PIN_G6, mode = 3, stream=SPI_STREAM)
#use i2c(MASTER, I2C1,SCL = PIN_D10, SDA = PIN_D9 , FORCE_SW)
#pin_select IC1=PIN_F0
#pin_select C1TX = PIN_D6
#pin_select C1RX = PIN_D5
#include <pcd_bootloader.h>
#endif

#org LOADER_ADDR, LOADER_END auto=0 default

//my main function and other definitions here

#org default


then I compiled, the error message is
Executing: "C:\Program files\Picc\CCSC.exe" +FD "AU360_UNIT_TEST.C" +DF +LN +T +A +M +Z +Y=9 +EA
--- Info 300 "AU360_UNIT_TEST.c" Line 28(30,31): More info: Segment at 00000-0FFFE (0000 used)
--- Info 300 "AU360_UNIT_TEST.c" Line 28(30,31): More info: Segment at 10000-1FFFE (0000 used)
--- Info 300 "AU360_UNIT_TEST.c" Line 28(30,31): More info: Segment at 20000-2A7FE (0000 used)
--- Info 300 "AU360_UNIT_TEST.c" Line 28(30,31): More info: Segment at 2A800-2ABFE (0000 used) Priv
--- Info 300 "AU360_UNIT_TEST.c" Line 28(30,31): More info: Attempted to create: 2A800-2ABFE for #org
*** Error 126 "AU360_UNIT_TEST.c" Line 28(30,31): Invalid ORG range
1 Errors, 0 Warnings.

Any ideas? Thanks a lot
jeremiah



Joined: 20 Jul 2010
Posts: 1342

View user's profile Send private message

PostPosted: Thu Sep 06, 2012 6:38 pm     Reply with quote

I usually get that message when one of my #org statements crosses a 16 bit boundary. The compiler can't seem to handle that situation, so I have to break it up into separate #org statements

What are your values for LOADER_ADDR and LOADER_END? EDIT: I know what you said you wanted them to be in your paragraph, but I am interested in seeing the code that sets them, so I can reproduce the problem.

EDIT:
This is a generic simple empty project that compiles correctly with 4.135. It uses your fuses and chip. Be aware that if the rs232 and i2c are going to be used only in your bootloader, that you place them and call them within the #org statements or the compiler might place them at 0x200 instead. I would start with this and add in things until the error occurs to help identify it.

Code:

#case
#include <33EP256MU814.h>

#fuses HS,PR,NOWDT,ICSP2


//Chip Program Memory Defines
#define PM_END       (getenv("PROGRAM_MEMORY")-1)      //in words
#define PM_PAGE_SIZE (getenv("FLASH_ERASE_SIZE")/2)    //in words
#define PM_ROW_SIZE  (getenv("FLASH_WRITE_SIZE")/2)    //in words
#define PM_NUM_PAGES (PM_END/PM_PAGE_SIZE)
#define PM_FUSE_PAGE (PM_NUM_PAGES*PM_PAGE_SIZE)


//Just for convenience
#define LOADER_ADDR PM_FUSE_PAGE
//#define LOADER_ADDR (PM_FUSE_PAGE-(1*PM_PAGE_SIZE))  //for larger area, change multiplier
#define LOADER_END  PM_END

#ORG LOADER_ADDR, LOADER_END auto=0 default
void main()
{
 
}
#ORG default
jeremiah



Joined: 20 Jul 2010
Posts: 1342

View user's profile Send private message

PostPosted: Thu Sep 06, 2012 7:24 pm     Reply with quote

Hmm, so I tried supplying the auxiliary flash memory address to the #org and it generated an internal compiler error. So I can see where you are having trouble, though the compiler error is different for you than it is me.
naughty_mark



Joined: 29 Aug 2012
Posts: 97

View user's profile Send private message

PostPosted: Thu Sep 06, 2012 7:29 pm     Reply with quote

jeremiah wrote:
Hmm, so I tried supplying the auxiliary flash memory address to the #org and it generated an internal compiler error. So I can see where you are having trouble, though the compiler error is different for you than it is me.


Thanks Jeremiah,

some updates
I can know get most of compiling work by using the code
Code:

#if defined(__PCD__)
#include <33EP256MU814.h>
//#include <i2c.h>
#fuses HS,PR,NOWDT,ICSP2
//#build(reset = 0x7FFFFFE, interrupt = 0x7FFFFFA)
//CKSFSM -enable oscillator clock switching mode when a OSC failure has occurred.
//#build (stack=256)
//#build (stack=0x1E00:0x1FFF)
#device ADC=12
#use delay(clock=20000000) // Actual crystal is 20M
#pin_select U1TX = PIN_D0
#pin_select U1RX = PIN_D1
#pin_select U2TX = PIN_D2
#pin_select U2RX = PIN_D3
#use RS232(UART1, STREAM = GSM, BAUD=9600, XMIT = PIN_D0 , RCV = PIN_D1 ,  BITS = 8, STOP = 1, PARITY = N, ERRORS) // Actual Baud is 38400 due to clock (10M not 20M)
#use RS232(UART2, STREAM = MODBUS, BAUD=9600, XMIT = PIN_D2 , RCV = PIN_D3 ,  BITS = 8, STOP = 1, PARITY = N, ERRORS) // Actual Baud is 38400 due to clock (10M not 20M)
//#use spi(MASTER, DO = PIN_G8, CLK = PIN_G6, mode = 3, stream=SPI_STREAM)
#use i2c(MASTER, I2C1,SCL = PIN_D10, SDA = PIN_D9 , FORCE_SW)
#pin_select IC1=PIN_F0
#pin_select C1TX = PIN_D6
#pin_select C1RX = PIN_D5
//#include <pcd_bootloader.h>
#endif

#define LOADER_ADDR            (0x7FC000)
#define LOADER_END            (0x7FFFFF)

#org LOADER_ADDR, LOADER_END auto=0 default

//my main function here

#org default

The compiling error I got is out of ROM, segament or program or vars too big! I tried to delete some unrelevant code, actually not much help, because if the function or vars not used in the program, it won't be compiled in (that's my guess, because when I deleted some unused code, the left space showed by compiler is same).
And I tried to delete #org statement and compiled, it passed and I check the .STA file which contains code usage info, it only takes 7010 instructions in the main flash, and Auxiliary flash has 16376 indeed. I got confused why if I add #org back, it told me some part of the code too big?
Any ideas? Thanks
naughty_mark



Joined: 29 Aug 2012
Posts: 97

View user's profile Send private message

PostPosted: Thu Sep 06, 2012 7:35 pm     Reply with quote

jeremiah wrote:
I usually get that message when one of my #org statements crosses a 16 bit boundary. The compiler can't seem to handle that situation, so I have to break it up into separate #org statements

What are your values for LOADER_ADDR and LOADER_END? EDIT: I know what you said you wanted them to be in your paragraph, but I am interested in seeing the code that sets them, so I can reproduce the problem.

EDIT:
This is a generic simple empty project that compiles correctly with 4.135. It uses your fuses and chip. Be aware that if the rs232 and i2c are going to be used only in your bootloader, that you place them and call them within the #org statements or the compiler might place them at 0x200 instead. I would start with this and add in things until the error occurs to help identify it.

Code:

#case
#include <33EP256MU814.h>

#fuses HS,PR,NOWDT,ICSP2


//Chip Program Memory Defines
#define PM_END       (getenv("PROGRAM_MEMORY")-1)      //in words
#define PM_PAGE_SIZE (getenv("FLASH_ERASE_SIZE")/2)    //in words
#define PM_ROW_SIZE  (getenv("FLASH_WRITE_SIZE")/2)    //in words
#define PM_NUM_PAGES (PM_END/PM_PAGE_SIZE)
#define PM_FUSE_PAGE (PM_NUM_PAGES*PM_PAGE_SIZE)


//Just for convenience
#define LOADER_ADDR PM_FUSE_PAGE
//#define LOADER_ADDR (PM_FUSE_PAGE-(1*PM_PAGE_SIZE))  //for larger area, change multiplier
#define LOADER_END  PM_END

#ORG LOADER_ADDR, LOADER_END auto=0 default
void main()
{
 
}
#ORG default


Hi, Jeremiah, your information is important!, thanks.
Firstly, I defined bootloader address as
#define LOADER_ADDR (0x7FC000)
#define LOADER_END (0x7FFFF8)
and now my compiling error is what I mentioned above, is "code too big"

Secondly, I noticed you said in bootloader code, or say the code put into auxiliary flash address can only use rs232 and i2c, am I right? because in my bootloader program, I also need to use CAN bus and CAN interrupt, as well as Input capture interrupt, is that allowed in bootloader?
Thanks a lot!
jeremiah



Joined: 20 Jul 2010
Posts: 1342

View user's profile Send private message

PostPosted: Thu Sep 06, 2012 7:36 pm     Reply with quote

If you comment out all of your code and just use a blank main with no other functions, does it still give those errors?

My first guess is that the compiler doesn't like memory addresses outside of the normal FUSE page. That's just a guess though. I'm going through the manual to see.

EDIT: Also note that your addresses overlap the auxiliary IVT space. That could cause the code to big error in some cases. You can't put code in the IVT space unless you use the #build directive to move the IVT elsewhere. That applies to the auxiliary reset vector and goto address I think as well.


Last edited by jeremiah on Thu Sep 06, 2012 7:43 pm; edited 3 times in total
jeremiah



Joined: 20 Jul 2010
Posts: 1342

View user's profile Send private message

PostPosted: Thu Sep 06, 2012 7:40 pm     Reply with quote

naughty_mark wrote:

Secondly, I noticed you said in bootloader code, or say the code put into auxiliary flash address can only use rs232 and i2c, am I right? because in my bootloader program, I also need to use CAN bus and CAN interrupt, as well as Input capture interrupt, is that allowed in bootloader?
Thanks a lot!


As a note, I am not experienced with auxiliary flash, but in general, you can do any of those in a bootloader. I am just trying to impress on you that you need to be careful where you place your #use statements sometimes. I've had instances where I didn't place them in the #org statements and the code generated was placed at early memory.

So once you get the auxilliary code error figured out, you need to make sure anything you are using in the bootloader is placed in the bootloader space. They way you have it organized right now, some of those peripherals could be placed in early memory.
naughty_mark



Joined: 29 Aug 2012
Posts: 97

View user's profile Send private message

PostPosted: Thu Sep 06, 2012 7:48 pm     Reply with quote

jeremiah wrote:
If you comment out all of your code and just use a blank main with no other functions, does it still give those errors?

My first guess is that the compiler doesn't like memory addresses outside of the normal FUSE page. That's just a guess though. I'm going through the manual to see.

EDIT: Also note that your addresses overlap the auxiliary IVT space. That could cause the code to big error in some cases. You can't put code in the IVT space unless you use the #build directive to move the IVT elsewhere. That applies to the auxiliary reset vector and goto address I think as well.


Hi, Jeremiah
I just tried your advice, I commented out the header files in main.c file which may cause compiling errors described above, and also use a blank main()function.
Then I got this compiling error
--- Info 300 "UNIT_TEST.c" Line 238(0,7): More info: * Access violation at address 018798E7 in module 'PCD.dll'. Read of address 84CE9E0E
*** Error 44 "UNIT_TEST.c" Line 238(0,7): Internal Error - Contact CCS OUTPUT FILE O
1 Errors, 28 Warnings.
Build Failed.

I don't know what does it mean? Confused
Thanks mate
naughty_mark



Joined: 29 Aug 2012
Posts: 97

View user's profile Send private message

PostPosted: Thu Sep 06, 2012 7:49 pm     Reply with quote

jeremiah wrote:
naughty_mark wrote:

Secondly, I noticed you said in bootloader code, or say the code put into auxiliary flash address can only use rs232 and i2c, am I right? because in my bootloader program, I also need to use CAN bus and CAN interrupt, as well as Input capture interrupt, is that allowed in bootloader?
Thanks a lot!


As a note, I am not experienced with auxiliary flash, but in general, you can do any of those in a bootloader. I am just trying to impress on you that you need to be careful where you place your #use statements sometimes. I've had instances where I didn't place them in the #org statements and the code generated was placed at early memory.

So once you get the auxilliary code error figured out, you need to make sure anything you are using in the bootloader is placed in the bootloader space. They way you have it organized right now, some of those peripherals could be placed in early memory.

Ok, I got your point on this issue ~Thanks
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group