|
|
View previous topic :: View next topic |
Author |
Message |
bcptdtptp
Joined: 13 Jan 2021 Posts: 7
|
PWM and RS232 conflict |
Posted: Fri Apr 23, 2021 2:00 pm |
|
|
Hi all,
I'm using PIC18F57K42 and CCS compiler 5.101.
I was trying to setup pwm and serial port. What I found was if I enable the INT_TIMER2, then the pwm works but the serial port not. Seems it got into the interrupt routine when I sent a character because it executed the code "fprintf (PC, "get ")", but it didn't execute the code "fputc(k,PC)".
If I disable the INT_TIMER2, then the pwm doesn't work but the serial port works.
Thank you!
Here's my code:
Code: |
#include <18F57K42.h>
#define RS232_TIMEOUT 100
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, NOLVP, NOPUT
#use delay(clock=12000000)
#pin_select TX1 = PIN_C6
#pin_select RX1 = PIN_C7
#pin_select TX2 = pin_B6
#pin_select RX2 = pin_B7
#use rs232(UART1,baud=9600,stream=PC,bits=8,errors, timeout=RS232_TIMEOUT)
#use pwm(CCP1, output=PIN_C2, TIMER=2, FREQUENCY=100, DUTY=50, STREAM=PWM_V1)
#define RX_BUFFER_SIZE 32 // buffer size for the USART
#define TX_BUFFER_SIZE 8
#define PUMP_RX_BUFFER_SIZE 8 // buffer size for the USART
// variables for HOSTPC ISR
char RX_Buffer[RX_BUFFER_SIZE + 1]; // character array for the receive buffer for host pc.
char RX_Wr_Index = 0; // index of next char to put into the buffer
char RX_Rd_Index = 0; // index of next char to fetch from buffer
char RX_Counter = 0; // total count of characters in the buffer
short RX_Buffer_Overflow = 0; // Flag set on UART, receiver buffer overflow
char TX_Buffer[RX_BUFFER_SIZE + 1]; // character array for the buffer
char TX_Wr_Index = 0; // index of next char to put into the buffer
char TX_Rd_Index = 0; // index of next char to fetch from buffer
char TX_Counter = 0;
char bkgetc(void);
void main()
{
char k;
fprintf(PC,"\r\nEX_RS232_BUFFER.c\r\n");
enable_interrupts(INT_RDA);
enable_interrupts(INT_TIMER0);
//enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
setup_timer_2(T2_DIV_BY_16,249,1);
setup_ccp1(CCP_PWM);
setup_ccp2(CCP_PWM);
setup_ccp3(CCP_PWM);
setup_ccp4(CCP_PWM);
//set_pwm4_duty(25);
//pwm_set_duty_percent(PWM_V4,25);
while(TRUE)
{
if (RX_counter > 0) // buffer contains character
{
k = bkgetc() ;
delay_ms(10);
fputc(k,PC);
}
}
}
// total count of characters in the buffer
// ============ USART Receiver interrupt service routine for PC ==============
#int_rda // preprocessor directive identifying the following as an interrupt routine
void serial_rx_isr ( )
{
// put char received from the HOST in buffer
RX_Buffer[RX_Wr_Index] = fgetc(PC);
fprintf (PC, "get ");
if (++RX_Wr_Index > RX_BUFFER_SIZE) // wrap the pointer
RX_Wr_Index = 0;
if (++ RX_Counter >RX_BUFFER_SIZE) // if too many chars come in before sent
{
RX_Counter = RX_BUFFER_SIZE;
RX_Buffer_Overflow =1; // set the receive buffer overflow flag
}
}
// character from the UART Receiver buffer
char bkgetc(void)
{
char c;
while (RX_Counter == 0) // wait for a character
;
c = Rx_Buffer[RX_Rd_Index]; // get one character from the buffer
if (++RX_Rd_Index > RX_BUFFER_SIZE) // wrap the pointer
RX_Rd_Index = 0;
if(RX_Counter)
RX_Counter --; // count down by 1
return c;
}
|
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9220 Location: Greensville,Ontario
|
|
Posted: Fri Apr 23, 2021 2:17 pm |
|
|
quick comment.
rule #1. Never print or do 'math , inside an ISR. ISRs need to be very short and QUICK. Set flags and exit. Have main() look at flags and do as required.
rule #2. Never enable an interrupt without having a 'handler' (an ISR ) for it. Sooner or later the PIC WILL do 'weird things or freeze'...... |
|
|
bcptdtptp
Joined: 13 Jan 2021 Posts: 7
|
|
Posted: Fri Apr 23, 2021 5:40 pm |
|
|
Hi temtronic, thank you so much for your comments. I actually got this ISR from a sample code long time ago. I will rework on the code next week according to your comments. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19488
|
|
Posted: Sat Apr 24, 2021 7:22 am |
|
|
Also, when using a hardware UART, unless you add your own error handling
you should always have 'ERRORS' in your #USE RS232., This is vital
particularly in this case.
Why?. If the UART receives more than two characters and they are not
'handled' (by a getc), the UART will become hung. ERRORS will clear this.
Now in this case, having the four character print inside the receive ISR,
will result in this happening if characters are sent 'flat out'. What it posted
would work OK, if characters were just being hand typed, but if they were
sent by code, the result would be a disaster... |
|
|
bcptdtptp
Joined: 13 Jan 2021 Posts: 7
|
|
Posted: Sat Apr 24, 2021 9:05 pm |
|
|
Hi Ttelmah, thanks for the detailed explanation about the errors, I will add it to the code.
I came across a post from you several years ago stating timer2 not needed for the own, but it does seem to be needed in my case. Could you please take a look and see what else I should do besides setting the isr handler? Thank you!
Last edited by bcptdtptp on Sat Apr 24, 2021 10:08 pm; edited 1 time in total |
|
|
dluu13
Joined: 28 Sep 2018 Posts: 395 Location: Toronto, ON
|
|
Posted: Sat Apr 24, 2021 9:32 pm |
|
|
I haven't used this chip but I have a couple of comments:
Generally when I use the UART and #use rs232, I use the "receive buffer" option so that the compiler automatically generates the ISR and creates a circular buffer to stick the incoming chars in. That way I don't have to write my own and I use kbhit() in order to see if there are characters to retrieve from the circular buffer.
If you're writing your own UART isr, imo it shouldn't contain much more than a getc(), flag=1 and maybe throw in a ++counter.
Regarding #use pwm, after specifying that I want to use TIMER=2 for example, I don't use setup_timer_2 or setup_ccpx, etc in my initialization. I also don't see that you used #pin_select for any CCP pins. Typically, I need to set those when I #use pwm. According to your header file, you can choose these as outputs:
CCP1OUT,CCP2OUT,CCP3OUT,CCP4OUT,PWM5OUT,PWM6OUT,PWM7OUT,PWM8OUT
In that case I'd try something like this:
Code: |
#pin_select CCP1OUT=PIN_C2
#use pwm(CCP1, TIMER=2, FREQUENCY=100, DUTY=50, PWM_ON, STREAM=PWM_V1)
|
I put the PWM_ON option in there just to be explicit about it... I think it's the default anyway. The compiler should map the pin automatically since you specified it anyway, but you never know...
Furthermore, when you say that when you enable INT_TIMER2 then the pwm works, how are you testing it? A lot of times when I have enabled an interrupt but don't have an ISR, I get a trap error and my PIC resets. Are you sure that when you enable the TIMER2 interrupt that you aren't continually resetting the PIC? If you are not using an oscilloscope but are just looking at an LED or something that might give you a wrong indication. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19488
|
|
Posted: Sun Apr 25, 2021 9:32 am |
|
|
Big critical thing.
You must _never_ enable an interrupt without having an interrupt handler
in the code.
What you post does not have a handler for the timer2 interrupt. Enabling
without the hander will result in the code jumping to the wrong location
and crashing or hanging. Fits what you describe.
Same applies to timer0.
The PWM does not need or use the interrupt. It should run fine without it.
I agree with diuu13. You are probably seeing incorrect operation that
gives a pulse on the PWM pin, rather than actual PWM operation. |
|
|
bcptdtptp
Joined: 13 Jan 2021 Posts: 7
|
|
Posted: Mon Apr 26, 2021 7:27 am |
|
|
Hi dluu13 and Ttelmah,
Thank you so much for the comments and generous help! Today I'll modify the code and add interrupt handler for timer 2 as well as the RS232 error.
For PWM, I actually had 4 pwm channels and I was using an oscilloscope to monitor the outputs. All the 4 channels gave me correct output (frequency and duty cycle) if I enable the timer 2 interrupt. |
|
|
bcptdtptp
Joined: 13 Jan 2021 Posts: 7
|
|
Posted: Mon Apr 26, 2021 8:59 am |
|
|
Ttelmah wrote: | Also, when using a hardware UART, unless you add your own error handling
you should always have 'ERRORS' in your #USE RS232., This is vital
particularly in this case.
Why?. If the UART receives more than two characters and they are not
'handled' (by a getc), the UART will become hung. ERRORS will clear this.
Now in this case, having the four character print inside the receive ISR,
will result in this happening if characters are sent 'flat out'. What it posted
would work OK, if characters were just being hand typed, but if they were
sent by code, the result would be a disaster... |
I realized that there actually IS "ERRORS" in the code. I also took out the "fprintf" code in the ISR, and added the timer2 handler. But the result is the same:
with enable_interrupts(INT_TIMER2), the PWM worked, RS232 didn't work.
comment out enable_interrupts(INT_TIMER2), PWM didn't work, RS232 worked. |
|
|
dluu13
Joined: 28 Sep 2018 Posts: 395 Location: Toronto, ON
|
|
Posted: Mon Apr 26, 2021 9:09 am |
|
|
Are you still doing setup_timer_2?
I've never had to do that to make #use pwm work |
|
|
bcptdtptp
Joined: 13 Jan 2021 Posts: 7
|
|
Posted: Mon Apr 26, 2021 9:37 am |
|
|
dluu13 wrote: | Are you still doing setup_timer_2?
I've never had to do that to make #use pwm work |
I took out the "setup_timer_2" and now both PWM and RS232 worked!!!!!!!
Thank you
BTW, regarding the pin select for PWM, I put it in the #use line, output=PIN_C2 |
|
|
dluu13
Joined: 28 Sep 2018 Posts: 395 Location: Toronto, ON
|
|
Posted: Mon Apr 26, 2021 9:43 am |
|
|
Glad it worked!
I actually expressed some concern about that line in the original post haha.
I was concerned that there will be conflicts between using the #use statements and the setup_timer_2 and setup_ccp calls in your initialization. |
|
|
bcptdtptp
Joined: 13 Jan 2021 Posts: 7
|
|
Posted: Mon Apr 26, 2021 10:53 am |
|
|
dluu13 wrote: | Glad it worked!
I actually expressed some concern about that line in the original post haha.
I was concerned that there will be conflicts between using the #use statements and the setup_timer_2 and setup_ccp calls in your initialization. |
Still don't understand why "setup_timer_2" caused the problem. |
|
|
dluu13
Joined: 28 Sep 2018 Posts: 395 Location: Toronto, ON
|
|
Posted: Mon Apr 26, 2021 10:55 am |
|
|
I'm not sure either but I suspect that your extra call to setup_timer_2 interfered with the code that #use pwm created to set up the timer in the first place. |
|
|
|
|
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
|