View previous topic :: View next topic |
Author |
Message |
kmp84
Joined: 02 Feb 2010 Posts: 368
|
txISR PCD |
Posted: Wed Jan 29, 2025 8:53 am |
|
|
Hello,
I'm trying to run "ex_stisr_pcd" but not success.
Code: |
#include <33EP512MU810.h>
#device ICSP=1
#use delay(crystal=8MHz)
#FUSES NOWDT //No Watch Dog Timer
#FUSES CKSFSM //Clock Switching is enabled, fail Safe clock monitor is enabled
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOJTAG //JTAG disabled
#define PER_EN PIN_D5
#define PER_ON() output_high(PER_EN)
#define PER_OFF() output_low(PER_EN)
/* HW UART1 */
#pin_select U1RX=PIN_E1 // Rx Com1.
#pin_select U1TX=PIN_E0 // Tx Com1.
#use rs232(UART1,baud=9600)
#define T_BUFFER_SIZE 64
byte t_buffer[T_BUFFER_SIZE];
byte t_next_in = 0;
byte t_next_out = 0;
#int_tbe
void serial_isr() {
if(t_next_in!=t_next_out)
{
putc(t_buffer[t_next_out]);
t_next_out=(t_next_out+1) % T_BUFFER_SIZE;
}
disable_interrupts(INT_TBE);
}
void bputc(char c) {
#bit U1TXIF = getenv("BIT:U1TXIF")
short restart;
int ni;
restart=t_next_in==t_next_out;
t_buffer[t_next_in]=c;
ni=(t_next_in+1) % T_BUFFER_SIZE;
while(ni==t_next_out);
t_next_in=ni;
if(restart)
U1TXIF = 1;
}
void main() {
delay_ms(100);
PER_ON();
enable_interrupts(INT_TBE);
enable_interrupts(GLOBAL);
printf(bputc,"\r\n\Running...\r\n");
do {
delay_ms(2000);
printf(bputc,"This is buffered data\r\n");
} while (TRUE);
} |
dsPic doesn't transmit anything!
CCS c v.5.115
Best Regards, |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9370 Location: Greensville,Ontario
|
|
Posted: Wed Jan 29, 2025 9:09 am |
|
|
Hmmm..
does it transmit if you just do a normal 'print to comport' ?
do those PPS pins connect to UART or I/O pins ?
does the PC terminal program work ? loopback checked OK ?
any chance TX-->TXD, RX-->RXD ?
Always wondered if anyone did a test to see IF using a TXISR is faster and by how much ? |
|
|
kmp84
Joined: 02 Feb 2010 Posts: 368
|
|
Posted: Wed Jan 29, 2025 9:45 am |
|
|
temtronic wrote: | Hmmm..
does it transmit if you just do a normal 'print to comport' ?
do those PPS pins connect to UART or I/O pins ?
does the PC terminal program work ? loopback checked OK ?
any chance TX-->TXD, RX-->RXD ?
Always wondered if anyone did a test to see IF using a TXISR is faster and by how much ? |
Normal printf function working, no problem. Just ISR doesn't fire!
Best Regards, |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19649
|
|
Posted: Wed Jan 29, 2025 10:49 am |
|
|
Aargh.....
Does the example really have this?.
disable_interrupts(INT_TBE);
Never going to work. It'll send _one_ character.
The point is you want to only disable the interrupt if the buffer is empty.
So:
Code: |
#int_tbe
void serial_isr(void)
{
if(t_next_in!=t_next_out)
{
putc(t_buffer[t_next_out]);
t_next_out=(t_next_out+1) % T_BUFFER_SIZE;
}
else
disable_interrupts(INT_TBE);
}
|
I did point this out to CCS about three years ago.
My own buffers, which are a bit more 'universal', are:
Code: |
//Buffer tests and handling
unsigned int8 btempU1RX,btempU1TX;
#define SIBUFF (64) //buffer sizes
typedef struct {
unsigned int8 in;
unsigned int8 out;
unsigned int8 buff[SIBUFF];
} buffer;
buffer U1RX,U1TX; //declare these for every buffer you want.
#define incin(buff) ((buff.in==(SIBUFF-1))?0:buff.in+1)
#define incout(buff) ((buff.out==(SIBUFF-1))?0:buff.out+1)
#define isempty(buff) (buff.in==buff.out)
#define hasdata(buff) (buff.in!=buff.out)
#define isfull(buff) ((incin(buff)==buff.out)
#define tobuff(bname,c) { bname.buff[bname.in]=c;\
bname.in=incin(bname);\
if (bname.in==bname.out) bname.out=incout(bname);\
}
#define frombuff(bname) (btemp##bname=bname.buff[bname.out],\
bname.out=incout(bname), \
btemp##bname)
#define clrbuff(buff) buff.in=buff.out=0
#define bkbhit(BUFF) hasdata(BUFF)
#define bgetc(BUFF) frombuff(BUFF);
void U1putc(int chr)
{
clear_interrupt(INT_TBE);
tobuff(U1TX,chr);
enable_interrupts(INT_TBE);
}
#INT_RDA
void uart1rx(void)
{
unsigned int8 temp;
while (kbhit(U1STREAM)) {
temp=getc();
tobuff(U1RX, temp);
};
}
#INT_TBE
void uart1tx(void)
{
unsigned int8 temp;
temp=bgetc(U1TX);
fputc(temp,U1STREAM);
if (isempty(U1TX))
disable_interrupts(INT_TBE);
}
|
These allow you to just add more buffers for different serials by adding 'buffer' declarations for them, and you handle them inside the interrupts
rather like streams, just using the buffer names to say when buffer you
are talking to.
I do also though always use ERROR interrupts for the serials. The 'ERRORS'
declaration on PIC24 and up does not work. So I use an error interrupt to
handle the errors:
Code: |
///UART ERROR HANDLING
#word U1STA=getenv("SFR:U1STA")
#word U2STA=getenv("SFR:U2STA")
#word U3STA=getenv("SFR:U3STA")
#word U4STA=getenv("SFR:U4STA")
#BIT UTXEN1=U1STA.10
#BIT UTXEN2=U2STA.10
#BIT UTXEN3=U3STA.10
#BIT UTXEN4=U4STA.10
#word U1MODE=getenv("SFR:U1MODE")
#word U2MODE=getenv("SFR:U2MODE")
#word U3MODE=getenv("SFR:U3MODE")
#word U4MODE=getenv("SFR:U4MODE")
#bit UARTEN1=U1MODE.15
#bit UARTEN2=U2MODE.15
#bit UARTEN3=U3MODE.15
#bit UARTEN4=U4MODE.15
#bit OERR1=U1STA.1
#bit FERR1=U1STA.2
#bit PERR1=U1STA.3
#bit OERR2=U2STA.1
#bit FERR2=U2STA.2
#bit PERR2=U2STA.3
#bit OERR3=U3STA.1
#bit FERR3=U3STA.2
#bit PERR3=U3STA.3
#bit OERR4=U4STA.1
#bit FERR4=U4STA.2
#bit PERR4=U4STA.3
#word U1RXREG=getenv("SFR:U1RXREG")
#word U2RXREG=getenv("SFR:U2RXREG")
#word U3RXREG=getenv("SFR:U3RXREG")
#word U4RXREG=getenv("SFR:U4RXREG")
#define CAT(x,y) x##y
#define CAT3(x,y,z) x##y##z
#define HASH_LIT #
#define HASH() HASH_LIT
#define EFUNCTION(x) void CAT(errorint, x) (void) { \
static int16 eword; \
if (CAT(OERR,x)) { CAT(OERR,x) = 0; return; } \
if (CAT(PERR,x)) { eword=CAT3(U,x,RXREG); } \
if (CAT(FERR,x)) { eword=CAT3(U,x,RXREG); } \
}
//Builds an interrupt handler to cope with UART errors.
//For parity and framing, throw the byte with the error.
#INT_UART1E LEVEL=5
EFUNCTION(1)
#INT_UART2E LEVEL=5
EFUNCTION(2)
#INT_UART3E LEVEL=5
EFUNCTION(3)
#INT_UART4E LEVEL=5
EFUNCTION(4)
//REM these out for UARTs the chip does not have
|
These then require the corresponding error interrupts are enabled.
These throw a byte when necessary to clear an error, and clear the
interrupt flags when this is needed.
With these buffers and error handling, I have had zero UART problems
on chips running all four UARTs at really high rates. |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1946 Location: Norman, OK
|
|
Posted: Wed Jan 29, 2025 1:01 pm |
|
|
Yep, the latest version compiler is still missing the else in the example... _________________ Google and Forum Search are some of your best tools!!!! |
|
|
kmp84
Joined: 02 Feb 2010 Posts: 368
|
|
Posted: Thu Jan 30, 2025 7:00 am |
|
|
Hi,
The problem are not only missing 'else' statement. With adding else statement still doesn't work. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19649
|
|
Posted: Thu Jan 30, 2025 12:25 pm |
|
|
OK. Look at Jay's questions. Have you verified the chip will transmit without
using the interrupt?. |
|
|
kmp84
Joined: 02 Feb 2010 Posts: 368
|
|
Posted: Fri Jan 31, 2025 4:57 am |
|
|
Hi mr.Tt,
I said yes at second post.
Best Regards, |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19649
|
|
Posted: Fri Jan 31, 2025 10:18 am |
|
|
OK. Lets try some routines based on the way do it. It is very worrying
that their routines have faults I pointed out a long time ago.
Looking at it, the problem is that they enable the transmit interrupt at the
start. This means the transmit routine will be immediately called and
this will then disable the interrupts.
Code: |
#include <33EP512MU810.h>
#device ICSP=1
#use delay(crystal=8MHz)
#FUSES NOWDT //No Watch Dog Timer
#FUSES CKSFSM //Clock Switching is enabled, fail Safe clock monitor is enabled
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOJTAG //JTAG disabled
#define PER_EN PIN_D5
#define PER_ON() output_high(PER_EN)
#define PER_OFF() output_low(PER_EN)
/* HW UART1 */
#pin_select U1RX=PIN_E1 // Rx Com1.
#pin_select U1TX=PIN_E0 // Tx Com1.
#use rs232(UART1,baud=9600)
#define T_BUFFER_SIZE 64
byte t_buffer[T_BUFFER_SIZE];
byte t_next_in = 0;
byte t_next_out = 0;
#int_tbe
void serial_isr()
{
putc(t_buffer[t_next_out]);
t_next_out++;
if (t_next_out>=T_BUFFER_SIZE)
t_next_out=0;
if (t_next_out==t_next_in)
disable_interrupts(INT_TBE);
}
//This puts a character to send to the TX buffer.
void bputc(uint16_t chr)
{
//interrupt driven TX
short rest; //flag to restart TX
disable_interrupts(INT_TBE);
rest=(t_next_in==t_next_out); //if buffer was empty
tbuff[t_next_in++]=chr;
if (t_next_in>=T_BUFFER_SIZE)
t_next_in=0;
if(rest)
U1TXIF = 1; //force interrupt to trigger
enable_interrupts(INT_TBE); ??this is where the interrupt gets enabled.
while(t_next_in==t_next_out) //This is buffer full
delay_cycles(4);//wait if buffer full for a character to send.
}
void main() {
delay_ms(100);
PER_ON();
//do not enable the TX interrupt here.
enable_interrupts(GLOBAL);
printf(bputc,"\r\n\Running...\r\n");
do {
delay_ms(2000);
printf(bputc,"This is buffered data\r\n");
} while (TRUE);
}
|
This should work. Sorry I did not spot their stupidity with the interrupt
enable before. It was so long ago, that I forgot how bad this was.
Mine also handles using non binary buffer sizes, and will stop and
wait if the buffer gets full. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9370 Location: Greensville,Ontario
|
|
Posted: Fri Jan 31, 2025 10:40 am |
|
|
You're forgiven.....
One day you head will explode with all the tidBITS of PIC info inside !!
That will be a very,very sad day !! |
|
|
kmp84
Joined: 02 Feb 2010 Posts: 368
|
|
Posted: Fri Jan 31, 2025 11:17 am |
|
|
Hi mr.'Tt',
Yes, now example working!
There is many identical problems like this and 'sd card' example also. They present from the beginning of the ccs compiler and still not corrected!
But this will not be CCS if not present!
Working Example Code:
Code: |
#include <33EP512MU810.h>
#device ICSP=1
#use delay(crystal=8MHz)
#FUSES NOWDT //No Watch Dog Timer
#FUSES CKSFSM //Clock Switching is enabled, fail Safe clock monitor is enabled
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOJTAG //JTAG disabled
#define PER_EN PIN_D5
#define PER_ON() output_high(PER_EN)
#define PER_OFF() output_low(PER_EN)
/* HW UART1 */
#pin_select U1RX=PIN_E1 // Rx Com1.
#pin_select U1TX=PIN_E0 // Tx Com1.
#use rs232(UART1,baud=9600)
#define T_BUFFER_SIZE 64
byte t_buffer[T_BUFFER_SIZE];
byte t_next_in = 0;
byte t_next_out = 0;
#int_tbe
void serial_isr()
{
putc(t_buffer[t_next_out]);
t_next_out++;
if (t_next_out>=T_BUFFER_SIZE)
t_next_out=0;
if (t_next_out==t_next_in)
disable_interrupts(INT_TBE);
}
//This puts a character to send to the TX buffer.
void bputc(unsigned int16 chr)
{
#bit U1TXIF = getenv("BIT:U1TXIF")
//interrupt driven TX
short rest; //flag to restart TX
disable_interrupts(INT_TBE);
rest=(t_next_in==t_next_out); //if buffer was empty
t_buffer[t_next_in++]=chr;
if (t_next_in>=T_BUFFER_SIZE)
t_next_in=0;
if(rest)
U1TXIF = 1; //force interrupt to trigger
enable_interrupts(INT_TBE); //??this is where the interrupt gets enabled.
while(t_next_in==t_next_out) //This is buffer full
delay_cycles(4);//wait if buffer full for a character to send.
}
void main() {
delay_ms(100);
PER_ON();
//do not enable the TX interrupt here.
enable_interrupts(GLOBAL);
printf(bputc,"\r\n\Running...\r\n");
do {
delay_ms(2000);
printf(bputc,"This is buffered data\r\n");
} while (TRUE);
}
|
Best Regards! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19649
|
|
Posted: Fri Jan 31, 2025 12:50 pm |
|
|
I have pointed it out to CCS again. Touch wood, this time they update their
examples.
Think I'lll add this thread to the 'known faults' page.
I think I'll stick my versions in the code library.
The SD card code does actually work. Problem is, only with old sub 2GB
SD;s formatted FAT16, and without an MBR. They have never done properly
updated examples that suit modern cards. The same really on the TCP/IP
stack as well. Ten years ago, their examples were good. Now they are
becoming annoying at times.
The code library is becoming more and more important as fixes like this
get added. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19649
|
|
Posted: Sat Feb 01, 2025 12:16 pm |
|
|
CCS have replied that the IsR example will be fixed in the next release. |
|
|
|