Hi,
I must create a programm that generate signal from bus CAN data with timer interrupt (ECT). But when I send frame (in debug) I have Illegal_bp in command windows.
I don't know how to correct this error. Can you help me ? If you have any question ask me.
I programm this:
void timer_counter () {
TIOS = 0xFF; // timer output compare register
TCNT = 0x0000; //timer count register
TSCR1 = 0x80; //timer system control register
TSCR2 = 0x05; //timer system control register 2
// TCTL1 = 0x55; //timer control register output mode
TCTL2 = 0x55;
TIE = 0x0F; //timer interupt enable
TFLG1 = 0x0F; //main timer interrupt flag
}
void interrupt 8 TOC0_ISR () {
DisableInterrupts;
TFLG1 = TFLG1_C0F_MASK ; // rabaisse le flag de l'interruption
buffer_empty1 = buffer_lenght - buffer_full1;
if (buffer_empty1 == buffer_lenght) {
PORTB =0b00000100 ;
sendOnCanEmpty () ;
}
if ( read_buffer_wheel1 < buffer_lenght ){ //test taille de la memoire
TC0 = TC0 + wheel1[read_buffer_wheel1] ; //lecture des donnees
read_buffer_wheel1 ++ ; //incrementation compteur lecture
} else{
read_buffer_wheel1 = 0 ; //rebouclage memoire .
TC0 = TC0 + wheel1[read_buffer_wheel1] ; //lecture des donnees
}
EnableInterrupts ;
}
Thank you !!
已解决! 转到解答。
This way:
#pragma CODE_SEG NON_BANKED
void interrupt 8 TOC0_ISR () {
…
}
#pragma CODE_SEG DEFAULT
These commands are dedicated for linker. This way linker know where you want place your code. There are different ways how to do it, but this is simply and comfortable.
Similar commands:
#pragma DATA_SEG – for variables
#pragma CONST_SEG – for constants
Illegal_bp could means almost anything (any unexpected behaviour), but in most of the cases it presents unexpected interrupt.
I have for you few tips for you:
volatile unsigned int number_of_ISR = 0;
volatile unsigned char sc0_data_in;
void Unimplemented_ISR(void)
{
asm nop; //insert breakpoint here. If the code stops here, check the "number_of_ISR"
}
#pragma CODE_SEG NON_BANKED
interrupt 1 void ISR_1 (void) {number_of_ISR = 1 ; Unimplemented_ISR();}
interrupt 2 void ISR_2 (void) {number_of_ISR = 2 ; Unimplemented_ISR();}
…//please fill
interrupt 19 void ISR_19 (void) {number_of_ISR = 19 ; Unimplemented_ISR();}
//interrupt 20 void ISR_20 (void) {number_of_ISR = 20 ; Unimplemented_ISR();}
interrupt 21 void ISR_21 (void) {number_of_ISR = 21 ; Unimplemented_ISR();}
…//please fill
interrupt 119 void ISR_119 (void) {number_of_ISR = 119 ; Unimplemented_ISR();}
#pragma CODE_SEG DEFAULT
//==============================================================================
//Example of SCI0 Interrupt routine
//==============================================================================
#pragma CODE_SEG NON_BANKED
interrupt 20 void SCI0_Isr(void)
{
//your SCI routine
}
#pragma CODE_SEG DEFAULT
//==============================================================================
ok I try.
For the CAN I programm this :
//---------initMSCAN------------------------------------------------------
void initMSCAN () {
int c2=0;
int c1=0;
while (!CAN2CTL1_INITAK) { // tant que le module ne confirme pas le mode init
c1++;
}
CAN2CTL1 |= CAN2CTL1_CANE_MASK; // activation du module CAN (inactif par défaut)
CAN2CTL1 &= (~CAN2CTL1_LISTEN_MASK); // Désactivation du mode lecture seule
CAN2BTR0 = 0x40; // Prescaler = 1 et Synchronisation jump width = 2
CAN2BTR1 = 0xA3; // TSEG1=4tq er TSEG2=3tq (voir calcul doc calcul_bit_rate.pdf v3.1)
//Bit 7 SAMP = 1 3 échantillon par bit
CAN2IDMR0 = 0xFF; //accepte tous les messages
CAN2IDMR1 = 0xFF;
CAN2IDMR2 = 0xFF;
CAN2IDMR3 = 0xFF;
CAN2IDMR4 = 0xFF;
CAN2IDMR5 = 0xFF;
CAN2IDMR6 = 0xFF;
CAN2IDMR7 = 0xFF;
CAN2CTL0 &= (~CAN2CTL0_INITRQ_MASK); // demande de sortie du mode initialization
while (CAN2CTL1_INITAK) { //test sortie d'init
c2++;
}
}
//---------------SendOnCan-------------------------------------------------
void sendOnCan (){
unsigned char txbuffer;
while (!CAN2TFLG){ //test tampon de libre
;
}
CAN2TBSEL=CAN2TFLG; //selection du buffer ayant la plus petite adresse
txbuffer = CAN2TBSEL;
CAN2TXDLR = 0x04 ; //Détermine la lenght de la trame de donnée.
CAN2TXIDR0 = 0xD3; //IDE = Détermine l’identificateur du message ID recu 69E
CAN2TXIDR1 = 0xC0;
CAN2TXDSR0 = buffer_full1; // Insertion des données que l’on souhaite transmettre.
CAN2TXDSR1 = buffer_empty1 ;
CAN2TXDSR2 = write_buffer_wheel1;
CAN2TXDSR3 = read_buffer_wheel1;
//CAN2TXDSR7 = 0xFF;
CAN2TFLG = txbuffer;
while ((CAN2TFLG & txbuffer) != txbuffer) { //attendre la fin de la transmissin
;
}
}
//------receiveOnCan-----------------------------------------
void receiveOnCan (){
unsigned char lenght, index;
DisableInterrupts;
if (CAN2RFLG & CAN2RFLG_RXF_MASK) { //message disponible
lenght = ( CAN2RXDLR & 0x0F); //prend en compte la taille max du message (message = 8 octets max)
PORTB = 0b00001000;
for (index = 1 ; index < lenght; index++) {
receive_data [index] = *(&CAN2RXDSR0 + index); // Transfert du message vers un tampon
}
buffer1 = write_buffer_wheel1 - read_buffer_wheel1 ;
buffer2 = buffer_lenght + buffer1 ;
buffer_full1 = buffer2 % buffer_lenght;
//ecriture memoire roue 1 et test memoire pleine wheel1 ------------------
if (buffer_full1 == 0) {
PORTB =0b00000001 ;
sendOnCanFull () ;
}
if (write_buffer_wheel1< buffer_lenght) { //test de la taille de la memoire
wheel1 [write_buffer_wheel1]= receive_data[1] + (256*receive_data[0]) ; //ecriture dans la memoire
write_buffer_wheel1 ++; //incrementation du compteur ecriture
} else {
write_buffer_wheel1 = 0; //rebouclage de la memoire
wheel1 [write_buffer_wheel1]= receive_data[1] + (256*receive_data[0]) ;
}
sendOnCan();
CAN2RFLG = 0x01; //flag lors de la reception d'un message
EnableInterrupts;
}
I suppose I have a problem in CAN config because now I have no Illegal_bp but my programm don't exit of Interrupt.
I think it's more easier if you see all the programm but I don't know how to join document.
void interrupt 8 TOC0_ISR () {
TFLG1 = TFLG1_C0F_MASK ; // rabaisse le flag de l'interruption
...
void interrupt 9 TOC1_ISR () { //adresse de la deuxième interruption périodique
TFLG1 = TFLG1_C1F_MASK ; // rabaisse le flag de l'interruption
void interrupt 10 TOC2_ISR () { //adresse de la troisième interruption périodique
TFLG1 = TFLG1_C3F_MASK ; // rabaisse le flag de l'interruption
void interrupt 11 TOC3_ISR () { //adresse de la quatrième interruption périodique
TFLG1 = TFLG1_C4F_MASK ; // rabaisse le flag de l'interruption
...
C2F flag is never serviced, TOC2_ISR exits and immediately reenters until COP reset occurs and you see ILLEGAL_BP
Please, instead of using "magic" numbers 8, 9, etc, open header file for your derivative and use instead defines like VectorNumber_Vtimch0, VectorNumber_Vtimch1 etc.
claire delange wrote:
And for the header file what is signification of VectorNumber_Vtimch0. I write just like that writing 8 but I don't know his signification.
It is bad coding practice to use weird numbers you know today and forget tomorrow. How do I know that 8 in your case is right number for timer channel 0 vector number? I don't remember this number to find a clue why your code isn't working, I would need to open datasheet or other document to verify that your 8 is right. VectorNumber_Vtimch0 would save me some work, also will save you the same work later, when you cam back to your code few years later.
It is similar with code like TIE = 0x0F;. OK if you know perfectly that 0xF stands for bits 0,1,2 and 3 set. But you could write the same like this
TIE = (1<<3) | (1<<2) | (1<<1) | (1<<0);
, which compiles the same like TIE = 0x0F;
I don't say this ^^ is much better, but for more hard bit patterns like 0xDB, it would be much much easier to decifier what bits did you want to set. Though it doesn't matter when compiler supports binary patterns like 0b00001111, if you do smth like this
#define CHARGE_CHANNEL 2
#define DISCHARGE_CHANNEL 4
TIE = (1<<CHARGE_CHANNEL) | (1<<DISCHARGE_CHANNEL);
.. then later you will say yourself a lot of "thank you" in case you need to swap some timer channels or do something like this. With good coding it is very easy to do such tasks. It is nightmare to do the same with code full of 0x45 0x0F 0xF0...
Interruptions don't accept VectorNumber_Vtimch0. I think (if I remenber correctly) The number decide where I save interruption.
And I prefere stay in hexa for my regsister It's easier for me. If I will must return on my programm I will must read the doc an other time.
Now I replay my programm and I have many problem. One time I see Illegal_bp, an other time the interrpution aren't activate and an other time I stay in interruption. For the same programm. :smileycry:
I shortly look at your code and I have for you few points:
You say, for one interruption : I must do this ? What is signification of #pragma CODE_SEG DEFAULT and #pragma CODE_SEG NON_BANKED ?
void interrupt 8 TOC0_ISR () {
#pragma CODE_SEG NON_BANKED
TFLG1 = TFLG1_C0F_MASK ; // rabaisse le flag de l'interruption
buffer_empty1 = buffer_lenght - buffer_full1;
if (buffer_empty1 == buffer_lenght) {
PORTB =0b00000100 ;
sendOnCanEmpty () ;
}
if ( read_buffer_wheel1 < buffer_lenght ){ //test taille de la memoire
TC0 = TC0 + wheel1[read_buffer_wheel1] ; //lecture des donnees
read_buffer_wheel1 ++ ; //incrementation compteur lecture
} else{
read_buffer_wheel1 = 0 ; //rebouclage memoire .
TC0 = TC0 + wheel1[read_buffer_wheel1] ; //lecture des donnees
}
#pragma CODE_SEG DEFAULT
}
This way:
#pragma CODE_SEG NON_BANKED
void interrupt 8 TOC0_ISR () {
…
}
#pragma CODE_SEG DEFAULT
These commands are dedicated for linker. This way linker know where you want place your code. There are different ways how to do it, but this is simply and comfortable.
Similar commands:
#pragma DATA_SEG – for variables
#pragma CONST_SEG – for constants
I don't see (again) I 'm not comment this line "CAN2RIER = 0x01;" in receive on CAN. This line create en error.
Now It's OK my program run !!
I just have last question : the message "illegal_bp" is corrected by #pragma CODE_SEG NON_BANKED and #pragma CODE_SEG DEFAULT ? Why ?
(if I encounter this error again I want to be able to fix it without help)
Don't ignore linker warnings and you will be warned about missing __NON_BANKED.
These #pragma CODE_SEG are required to place interrupt handlers in non banked memory. On interrupts page isn't switched, vector table entry is nonbanked address, so you need to force interrupt handlers to non banked memory.