View previous topic :: View next topic |
Author |
Message |
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Thu Jul 02, 2020 7:29 am |
|
|
If there is a CCSC.INI file, the compiler will read options from this. If this
exists it could be overriding the default, which is +O8hex
Now if this setting is wrong, most programmers will still accept the file
(they have a lot more code, and support for multiple formats), but the
bootloader won't.
So look if there is a ccsc.ini file.
If there is, see what it says (text editor).
The other possibility is your linux code is not sending the LSB. |
|
|
bastirn
Joined: 08 Jan 2020 Posts: 17
|
|
Posted: Thu Jul 02, 2020 7:47 am |
|
|
I don't have any CCSC.INI file so it should use the default config as you said.
About the i2c, I use linux bash command (i2cset / i2cget). |
|
|
bastirn
Joined: 08 Jan 2020 Posts: 17
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Thu Jul 02, 2020 9:39 am |
|
|
So, what options have you got in your I2Cset command?.
This affects massively how the output data is configured. |
|
|
bastirn
Joined: 08 Jan 2020 Posts: 17
|
|
Posted: Thu Jul 02, 2020 9:52 am |
|
|
Those command are provided in linux:
https://manpages.debian.org/buster/i2c-tools/i2cset.8.en.html
https://manpages.debian.org/buster/i2c-tools/i2cget.8.en.html
I have checked those commands with an oscilloscope and they look as it is indicated in the i2c_bootloader.h file:
Code: |
//// +---+------+------+-------------+---+ ////
//// | S | ADDY | CMD | Payload | P | ////
//// +---+------+------+-------------+---+ ////
//// | S | 0xA0 | 0x04 | 0x55 | 0xAA | P | ////
//// +---+------+------+-------------+---+ ////
//// ////
//// +---+------+------+-------------+---+ ////
//// | S | ADDY | CMD | Payload | P | ////
//// +---+------+------+-------------+---+ ////
//// | S | 0xA1 | 0x04 | 0x55 | 0xAA | P | ////
//// +---+------+------+-------------+---+ ////
//// ////
//// Write 0x00 0x01 0x02 0x03 to address 0x1122: ////
//// ////
//// +---+------+------+---------------------------+---+ ////
//// | S | ADDY | CMD | Payload | P | ////
//// +---+------+------+---------------------------+---+ ////
//// | S | 0xA0 | 0x01 | 0x22 | 0x11 | 0x00 | 0x00 | P | ////
//// +---+------+------+---------------------------+---+ ////
//// ////
//// +---+------+------+---------------------------+---+ ////
//// | S | ADDY | CMD | Payload | P | ////
//// +---+------+------+---------------------------+---+ ////
//// | S | 0xA0 | 0x02 | 0x00 | 0x01 | 0x02 | 0x03 | P | ////
//// +---+------+------+---------------------------+---+ ////
|
But i can read only 2 bytes with i2cget. I wanted to verify that the bootloader is working fine before going any further.
Function to place pointer and to write data:
i2cset -y 1 0x50 0x01 0x22 0x11 0x00 0x00 i
i2cset -y 1 0x50 0x02 0x0FFF w
Function to read data:
i2cget -y 1 0x50 0x02 w
return : 0x0F02
I believe that the problem can be in the i2c protocol to drive the bootloader that i didn't well understand. Maybe you have other documentation / example than the short summary given in the .h file. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Fri Jul 03, 2020 1:09 am |
|
|
OK.
First before you call your 'get', you need to set the address to be used back
to where the data is written. It carries on incrementing.
Then I'd use the byte packet mode for all transmissions.
So:
i2cset -y 1 0x50 0x01 0x22 0x11 0x00 0x00 i
i2cset -y 1 0x50 0x02 0xFF 0x0F i
i2cset -y 1 0x50 0x01 0x22 0x11 0x00 0x00 i
i2cget -y 1 0x50 0x02 w
I'd probably suggest using i2Cdump to actually load a block of addresses
rather than working on single words like this. |
|
|
bastirn
Joined: 08 Jan 2020 Posts: 17
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Fri Jul 03, 2020 1:31 am |
|
|
Why are you using -y?.
This overrides the bus synchronisation. Needed for EEPROM access..... |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Fri Jul 03, 2020 1:40 am |
|
|
I'd suspect you may have an issue with the turn round timing.
Now this driver is written to talk to things like chips, that can turn round
from a write transaction to a read transaction 'immediately'.
However on the PIC, the controller has to exit the interrupt and then get
back into the interrupt and load the byte before the next transaction can
occur. This is why when using a slave and master PIC together, it is vital
that the slave is running at least as fast as the master, or it cannot
load the byte in time for the master transaction.
Now the problem is that the I2Cget command loads the address byte,
command byte, and then automatically issues the bus restart, read
controller address, and starts to read. Your chip will need a pause of perhaps
20uSec between the read address, and actually being ready to send data.
Depending on the speed of your Linux system, this just won't be happening...
Result the address byte that is already in the control register on the
PIC gets sent back before a new byte is loaded... :( |
|
|
bastirn
Joined: 08 Jan 2020 Posts: 17
|
|
Posted: Fri Jul 03, 2020 2:12 am |
|
|
The i2cget isn't the most important problem i have. It is the i2cset because i need to see that the program memory of the PIC is modified to validate that the bootloader is working fine. I will try to replace the bash command by a c pre-compiled program.
Can you affirm that the file "rom_write.c" is compatible with a PIC 16LF1829 ? |
|
|
bastirn
Joined: 08 Jan 2020 Posts: 17
|
|
Posted: Tue Jul 07, 2020 10:07 am |
|
|
Hello,
I need some explanation about how work the command "write_program_memory" and what is needed to make it fully work for my PIC16LF1829.
I read the ccs manual carefully and i see a function "write_program_memory8" which only writes the LSB of the opcode. It perfectly describe my problem, i can't write the upper part of the opcode. I try this command, and, indeed it only modify the LSB. As the manual say:
"This function only writes the least significant byte
to each address in program memory. See write_program_memory() for a function that
can write all the data to each address in program memory."
I assume that I'm not using the function "write_program_memory" well.
Is there any particular config or way to use it.
Here is what i tried :
Code: |
char val[2];
val[0]=0x31;
val[1]=0x32;
write_program_memory(0x00001122, &val, 2);
// also tried : write_program_memory(0x00001122, &val, 1);
// also tried : write_program_memory8(0x00001122, &val, 1);
// also tried : write_program_memory8(0x00001122, &val, 2);
|
Thank you for any answer,
Best regards,
Bastien |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Wed Jul 08, 2020 1:23 am |
|
|
Using the block based 'write_program_memory' function to just transfer
two bytes at a time, is a terrifyingly inefficient way of working. I'm perhaps
not surprised it has issues when used this way.
To write just two bytes, is handled much 'better' by the write_program_eeprom
function. On most chips I'd simply say 'use this'. However for some
(unknown)
reason, on your chip the erase_program_eeprom function is not present.
Now normally to use the write_program_eeprom, you need to erase every
64 bytes, and then use the write through this block. Then when you get to
the end of the block erase again. So the sequence is:
Code: |
if (address%64==0)
erase_program_eeprom(address);
write_program_eeprom(address, int16_val_to_write);
|
Now given the compiler is missing the erase function, I've simply generated
one:
Code: |
#word EEADR=getenv("SFR:EEADRL")
#word EEDAT=getenv("SFR:EEDATL")
#byte EECON1=getenv("SFR:EECON1")
#byte EECON2=getenv("SFR:EECON2")
#bit EEPGD=getenv("BIT:EEPGD")
#bit FREE=getenv("BIT:FREE")
#bit CFGS=getenv("BIT:CFGS")
#bit WREN=getenv("BIT:WREN")
#bit WR=getenv("BIT:WR")
void erase_program_eeprom(unsigned int16 address)
{
//erase an EEPROM page
EEADR=address;
disable_interrupts(GLOBAL); //ensure interrupts disabled for write
CFGS=FALSE;
EEPGD=TRUE;
FREE=TRUE;
WREN=TRUE; //setup transaction
EECON2=0x55;
EECON2=0xAA; //unlock
WR=TRUE; //trigger operation
delay_cycles(1); //ignored instructions
delay_cycles(1);
WREN=FALSE;
enable_interrupts(GLOBAL); //re-enable interrupts
}
|
Then a quick test using:
Code: |
unsigned int16 val=0x4241;
erase_program_eeprom(0x1100); //erase the page containing the target
write_program_eeprom(0x1122, val);
|
Merrily works, and results in the word at 0x1122 containing 0x0241, which
given the program memory is only 14bits wide, is exactly what would be
expected. |
|
|
|