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

#INT_TBE on a 18F26Q83

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Torello



Joined: 29 Sep 2006
Posts: 123

View user's profile Send private message

#INT_TBE on a 18F26Q83
PostPosted: Fri Jan 03, 2025 9:42 am     Reply with quote

Hi,

I start writing a DMX controller and I'm running into a problem when doing the actual byte writes in an ISR.

In the code below, the ISR is never executed, i can see that on my oscilloscope. As the code executes "enable_interrupts(global)" I think it jumps to a wrong ISRvector where it finds nothing.
The Pic then restarts after a second due to the WDT.

So do I need to code more ISR setup/initialisation?

Code:
#include <test.h>

int8 TxBuf[60];
int8 TxIdx,TxLen;

#int_tbe
void Tbe_handler() {
  bScope0=1;
  if (interrupt_active(INT_TBE2)) {
    U2TXB = TxBuf[TxIdx++];                                 //load TXB, increment index
    if (TxIdx==TxLen) disable_interrupts(INT_TBE2);         //T: last load of TXB; disable interrupt             
  }
  bScope0=0;
}


void main(){
  int8 Tic100ms=0;
  int8 i=0;
  int16 i160;
  int16 RstCause;
 
  setup_oscillator(OSC_HFINTRC_64MHZ);
  setup_wdt( WDT_1S);
 
  //------ setup IO
  output_drive(pScope0);    output_low(pScope0);                                           
  output_drive(RS_Tx);
  output_drive(DMX_Tx);     

  //------ Modify the #use RS232(stream=DMX...) to really become DMX
  U2CON0&=0b11000000;  //clear bits TxEn/RxEn/mode others untouched
  U2CON0|=0b00101010;  //TxEn=1 and Mode=DMX
  U2CON2&=0b11111011;  //TxPol=0 other untouched
 
  //----- Setup Timer0 raise Tmr0IF every 100ms
  setup_timer_0(T0_INTERNAL|T0_DIV_1024|T0_OUTPS_11|T0_8_BIT); TMR0H=142;                         
 
  delay_ms(20);
  fprintf(Debug, "Program start, cause: ");
 
  RstCause=restart_cause();
  Switch (RstCause) {
    case RESTART_NONE:
      break;
    case NORMAL_POWER_UP:
      fprintf(Debug, "Normal PowerUp\n");
      break;
    case WDT_TIMEOUT:
      fprintf(Debug, "WDT-Timeout\n");
      break;
    case WDT_WINDOW_VIOLATION:
      fprintf(Debug, "WDT_window violation\n");
      break;
    case RESET_INSTRUCTION:
      fprintf(Debug, "RST instruction\n");
      break;
    case MCLR_FROM_RUN:
      fprintf(Debug, "MCLR from Run\n");
      break;
    case BROWNOUT_RESTART:
      fprintf(Debug, "BrownOut\n");
      break;
    default:
      fprintf(Debug, "other %Lx\n",RstCause);
  }   
 
  //----- Main Loop, Task schedular
  while(true) {
    restart_wdt();
    if (Tmr0IF) {
      Tmr0IF=0;
      Tic100ms++; if (Tic100ms>=10) Tic100ms=0;   
      switch (Tic100ms) {
        case 1:                                     
          //bScope0=1; delay_ms(10); bScope0=0;
          break;
        case 2:
           if (!U2TXIE && U2TXTMIF ) {             //interrupt not enabled -AND-! the transmit register is also empty
             //bScope0=1;
             TxBuf[0]=0;                           //load buffer
             TxBuf[1]=0xAA;
             TxBuf[2]=0x55;
             TxIdx=0; TxLen=3;                     //reset index count, load number of bytes to send
             U2P1H=0; U2P1l=TxLen-2;               //set bytes "amount" for autobreak (=number of DATA bytes minus 1 EXcluding the StartCode)
             enable_interrupts(INT_TBE2);          //this will fire the ISR as the transmit register is empty 
             enable_interrupts(global);
             //bScope0=0;
           }
           
             /*below 3 byte DMX send works as should
             U2P1H=0; U2P1l=1;                    // 1U2P1= total bytes to send - 2 !!  (Startcode + n-bytes; startcode=universum number)
             U2TXB=0x00;
             While(!U2TXIF);                      //wait till byte has been send
             U2TXB=0xAA;
             While(!U2TXIF);         
             U2TXB=0x55;
             While(!U2TXIF);         
             */
           
           
          break;
        Case 3:
          for(i160=0x49E; i160<=0x04AD; i160++) {   //show me all the PIE content
            fprintf(Debug,"Adr: %Lx, byte: %x\n",i160, (*i160));
          }
          fprintf(Debug,"-----\n");
          break;
      }             
    } 
  } 
}

Code:
#ifndef test_H
#define test_H

#include <18F26Q83.h>
#device ADC=12

#use fast_io(B)
#use fast_io(C)
#FUSES WDTCLK_LFINTRC,NOEXTOSC, RSTOSC_HFINTRC_1MHZ, PUT_64MS, NOLVP, Nobrownout, NoPPS1Way

#use delay(internal=64000000)

//#define An0             PIN_A0
//#define An1             PIN_A1
//#define An2             PIN_A2
//#define An3             PIN_A3
//#define An4             PIN_A4
//#define An5             PIN_A5
//#define An6             PIN_A6
//#define An7             PIN_A7

#define nop(x) Delay_cycles(x)

#define pScope0         PIN_B0
#bit    bScope0=getenv("SFR:PORTB").0

#define pFree_B1        PIN_B1
#define pFree_B2        PIN_B2
#define pFree_B3        PIN_B3
#define pFree_B4        PIN_B4
#define pFree_B5        PIN_B5
#define RS_Tx           PIN_B6
#define RS_Rx           PIN_B7

#define pFree_C0        PIN_C0
#define pFree_C1        PIN_C1
#define pFree_C2        PIN_C2
#define pFree_C3        PIN_C3
#define DMX_Tx          PIN_C4
#define DMX_Rx          PIN_C5
#define pFree_C6        PIN_C6
#define pFree_C7        PIN_C7

#define Mclr            PIN_E3

//--- ADC-----------------------------------
#bit  ADCBUSY = getenv("SFR:ADCON0").0    //busy bit is called "GO"

//--- IO -----------------------------------
#byte PortA = getenv("SFR:PORTA")
#byte PortB = getenv("SFR:PORTB")
#byte PortC = getenv("SFR:PORTC")

//--- Timer -----------------------------------
#define T0_OUTPS_01     0x0000    //Postscale 1:1
#define T0_OUTPS_02     0x0100
#define T0_OUTPS_03     0x0200
#define T0_OUTPS_04     0x0300
#define T0_OUTPS_05     0x0400
#define T0_OUTPS_06     0x0500
#define T0_OUTPS_07     0x0600
#define T0_OUTPS_08     0x0700
#define T0_OUTPS_09     0x0800
#define T0_OUTPS_10     0x0900
#define T0_OUTPS_11     0x0A00                     
#define T0_OUTPS_12     0x0B00
#define T0_OUTPS_13     0x0C00
#define T0_OUTPS_14     0x0D00
#define T0_OUTPS_15     0x0E00
#define T0_OUTPS_16     0x0F00     //PostScale 1:16

#byte TMR0L=0x318
#byte TMR0H=0x319
#byte T0CON0=0x31A
#byte T0CON1=0x31B
#bit  TMR0IF = getenv("BIT:TMR0IF")       //PIR3.7
#bit  TMR0EN = getenv("BIT:T0CON0.T0EN")
#bit  TMR0ASYNC = T0CON1.4

//--- NCO -----------------------------------
#bit  NCO1EN = getenv("SFR:NCO1CON").7    //Enable bit of the NCO0

//--- RS232 ---------------------------------
#PIN_SELECT U1RX=RS_Rx                     //must be on port B or C !       
#PIN_SELECT U1TX=RS_Tx                     //must be on port B or C !
#use RS232(stream=debug, UART1, Baud=38400, ERRORS)

//--- UART / DMX ----------------------------
#PIN_SELECT U2RX=DMX_Rx
#PIN_SELECT U2TX=DMX_Tx
#byte U2CON0=getenv("SFR:U2CON0")    //(oa. TxEn/RxEn/Mode)
#byte U2CON1=getenv("SFR:U2CON1")
#byte U2CON2=getenv("SFR:U2CON2")    //(oa. RxPol/TxPol
#byte U2P1H=getenv("SFR:U2P1H")
#byte U2P1L=getenv("SFR:U2P1L")
#byte U2TXB=getenv("SFR:U2TXB")                           //transmit byte register
#bit  U2TXEn=getenv("BIT:U2CON0.U2TXEN")
#bit  U2TXIF=getenv("BIT:PIR8.U2TXIF")                    //'1' transmit reg empty
#bit  U2RXIF=getenv("BIT:PIR8.U2RXIF")                    //'1' byte received
#bit  U2TXIE=getenv("BIT:PIE8.U2TXIE")                    //'1' enable TXIF interrupt
#bit  U2RXIE=getenv("BIT:PIE8.U2RXIE")                    //'1' enable RXIF interrupt
#bit  U2TXTMIF=getenv("BIT:U2ERRIR.U2TXMTIF")             //'1' transmit -SHIFT- reg empty flag, '0' transmit is busy
#bit  U2TXTMIE=getenv("BIT:U2ERRIE.U2TXMTIE")             //'1' enable above as interrupt

#use RS232(stream=DMX, UART2, Baud=250000,BITS=8,PARITY=N,STOP=2, ERRORS)

//---- I2C ----------------------------------
#bit FME=getenv("BIT:FME")                //'0'= (postscale5, only 10x or 2c PU-currents) '1'= (postscale4, 20, 10, 5x PU-currents)
#bit WPUC3=getenv("BIT:WPUC3")            //'1'=weak pull-up enabled
#bit WPUC4=getenv("BIT:WPUC4")
#byte WPUC=getenv("SFR:WPUC")
#byte RC4I2C=getenv("SFR:RC4I2C")
#byte RC3I2C=getenv("SFR:RC3I2C")
#byte I2C1BAUD = getenv("SFR:I2C1BAUD")
//#pin_select SCL1OUT = pSCL
//#pin_select SCL1IN  = pSCL
//#pin_select SDA1OUT = pSDA
//#pin_select SDA1IN  = pSDA
//#use i2c(Master, stream=MCP9808_Stream, I2C1, CLOCK_SOURCE=HFINTOSC, CLOCK_DIVISOR=4)

Typedef union { // This union typedef can be used for easy acces
int8 B[2]; // of bytes in integers
long int W;
} btwd;

Typedef union { // This union typedef can be used for easy acces
signed int8 B[2]; // of bytes in integers
signed int16 W;
} sbtwd;

Typedef union { // This union typedef can be used for easy acces
int8 B[4]; // of bytes and words in a long int
int16 W[2];
int32 L;
} bwl;

Typedef Union {
  int8 byt;
  int1 bit[8];
  int1 b7,b6,b5,b4,b3,b2,b1,b0;
} bytbit;


#endif

_________________
Regards, Edwin. PCWHD v5.114
Ttelmah



Joined: 11 Mar 2010
Posts: 19589

View user's profile Send private message

PostPosted: Fri Jan 03, 2025 10:35 am     Reply with quote

INT_TBE2
INT_TBE

Not the same thing.......

You are adding a handler for UART1 TBE, but then enabling UART2 TBE
interrupt,

Also a comment, a signed int16, only has a sign on the high byte. Using two
signed int8's to access it is a problem.....
Torello



Joined: 29 Sep 2006
Posts: 123

View user's profile Send private message

PostPosted: Sat Jan 04, 2025 6:58 am     Reply with quote

Thanx, so obvoius Embarassed And this works.
I first tried #INT_TBE1 as I thought that #INT_TBE would be for UART1 and thus #INT_TBE1 for UART2.
But #INT_TBE1 does not compile and raises an error "Invalid Pre-Processor directive". Then I didn't try TBE2 anymore, because I read something about this Pic using just one "main" TBE interrupt and with the interrupt_active(INT_TBE2) command you need to test which TBE number it actally is. And then I got stuck.

But it still confuses me that #INT_TBE1 does not compile and seems to be missing in the 18F26Q83.h header file.
Any thoughts why?

And now with #INT_TBE2 I guess I can leave out the testing on TBE2..


Yes, you are right about the union!
_________________
Regards, Edwin. PCWHD v5.114
temtronic



Joined: 01 Jul 2010
Posts: 9269
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Jan 04, 2025 7:08 am     Reply with quote

possibly......

in the beginning,
there was but ONE UART in a PIC, so 'TBE' was chosen
later, when there were TWO UARTS. 'TBE2' was added...

'TBE1' SHOULD be added into the header as it would be 'logical'

Now I'm curious if PICs with 4 UARTS have 'TBE1' ?
Ttelmah



Joined: 11 Mar 2010
Posts: 19589

View user's profile Send private message

PostPosted: Sat Jan 04, 2025 7:38 am     Reply with quote

With the compiler, there is a text file. ints.txt. Contains the names of
all the interrupts and what they do.
There is TBE, TBE1, TBE2, TBE3 & TBE4.
The chips with more than one UART accept the numeric forms for all of
the UARTs.
The key point tis that TBE, is not a 'global' TBE flag, it only applies to the
first UART.
Microchip did the same. Sp originally there was TBE, but when they added
the multiple UARTs, you got TBE1, TBE2 etc.. CCS allow TBE to still be used
for the first UART for reverse compatibility.
Torello



Joined: 29 Sep 2006
Posts: 123

View user's profile Send private message

PostPosted: Sat Jan 04, 2025 9:33 am     Reply with quote

Ah, reading you last reply just now Smile
I was already experimenting with my code and found out the same.
TBE = TBE1.

In code below I also can see that Uart1 has priority over Uart2.
Running on 64Mhz the latency is 1.8us. The ISR self is just below 1us

The first service of TBE2 is after 2 services of TBE1. That makes sense as the transmit-, and buffer register are both empty when starting the sendtrain.

Thanx for the extensive help!


Code:

#include <test.h>

int8 TxBuf[60];
int8 TxIdx,TxLen;

int8 Hlo[6]={'H','a','l','l','o','\n'};
int8 Hidx=0;


#int_tbe2
void Tbe2_handler() {
  bScope0=1;
    U2TXB = TxBuf[TxIdx++];                                 //load TXB, increment index
    if (TxIdx==TxLen) disable_interrupts(INT_TBE2);         //T: last load of TXB; disable interrupt             
  bScope0=0;
}

#int_tbe
void Tbe1_handler() {
  bScope1=1;
    U1TXB = Hlo[Hidx++];
    if (Hidx==6) { Hidx=0; disable_interrupts(INT_TBE);}
  bScope1=0;
}
 

void main(){
  int8 Tic100ms=0;
  int8 i=0;
  int16 i160;
  int16 RstCause;
 
  setup_oscillator(OSC_HFINTRC_64MHZ);
  setup_wdt( WDT_1S);
 
  //------ setup IO
  output_drive(pScope0);    output_low(pScope0);                                           
  output_drive(pScope1);    output_low(pScope1);                                           
  output_drive(RS_Tx);
  output_drive(DMX_Tx);     

  //------ Modify the #use RS232(stream=DMX...) to really become DMX
  U2CON0&=0b11000000;  //clear bits TxEn/RxEn/mode others untouched
  U2CON0|=0b00101010;  //TxEn=1 and Mode=DMX
  U2CON2&=0b11111011;  //TxPol=0 other untouched
 
  //----- Setup Timer0 raise Tmr0IF every 100ms
  setup_timer_0(T0_INTERNAL|T0_DIV_1024|T0_OUTPS_11|T0_8_BIT); TMR0H=142;                         
 
  delay_ms(20);
  fprintf(Debug, "Program start, cause: ");
 
  RstCause=restart_cause();
  Switch (RstCause) {
    case RESTART_NONE:
      break;
    case NORMAL_POWER_UP:
      fprintf(Debug, "Normal PowerUp\n");
      break;
    case WDT_TIMEOUT:
      fprintf(Debug, "WDT-Timeout\n");
      break;
    case WDT_WINDOW_VIOLATION:
      fprintf(Debug, "WDT_window violation\n");
      break;
    case RESET_INSTRUCTION:
      fprintf(Debug, "RST instruction\n");
      break;
    case MCLR_FROM_RUN:
      fprintf(Debug, "MCLR from Run\n");
      break;
    case BROWNOUT_RESTART:
      fprintf(Debug, "BrownOut\n");
      break;
    default:
      fprintf(Debug, "other %Lx\n",RstCause);
  }   
 
  //----- Main Loop, Task schedular
  while(true) {
    restart_wdt();
    if (Tmr0IF) {
      Tmr0IF=0;
      Tic100ms++; if (Tic100ms>=10) Tic100ms=0;   
      switch (Tic100ms) {
        case 1:                                     
          //bScope0=1; delay_ms(10); bScope0=0;
          break;
        case 2:
           if (!U2TXIE && U2TXTMIF ) {             //interrupt not enabled -AND-! the transmit register is also empty
             TxBuf[0]=0;                           //load buffer
             TxBuf[1]=0xAA;
             TxBuf[2]=0x55;
             TxIdx=0; TxLen=3;                     //reset index count, load number of bytes to send
             U2P1H=0; U2P1l=TxLen-2;               //set bytes "amount" for autobreak (=number of DATA bytes minus 1 EXcluding the StartCode)
             
             disable_interrupts(global);
             enable_interrupts(INT_TBE2);          //this will enable the TBE2 ISR as the transmit register is empty 
             enable_interrupts(INT_TBE);           //this will enable the TBE (=Uart1) ISR and  1 send of "Hallo"
             
             bScope0=1;
             delay_us(10);                         //scope-bit 'mark' bigger than ISR time..
             bScope0=0;                            //to measure i'rupt latency
             
             enable_interrupts(global);            //both interrupts now get fired....
           }
          break;
        Case 3:
          break;
      }             
    } 
  } 
}




_________________
Regards, Edwin. PCWHD v5.114
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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