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 support@ccsinfo.com

PWM and RS232 conflict

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



Joined: 13 Jan 2021
Posts: 7

View user's profile Send private message

PWM and RS232 conflict
PostPosted: Fri Apr 23, 2021 2:00 pm     Reply with quote

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: 9104
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Apr 23, 2021 2:17 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Apr 23, 2021 5:40 pm     Reply with quote

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: 19221

View user's profile Send private message

PostPosted: Sat Apr 24, 2021 7:22 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Apr 24, 2021 9:05 pm     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Sat Apr 24, 2021 9:32 pm     Reply with quote

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: 19221

View user's profile Send private message

PostPosted: Sun Apr 25, 2021 9:32 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Apr 26, 2021 7:27 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Apr 26, 2021 8:59 am     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Mon Apr 26, 2021 9:09 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Apr 26, 2021 9:37 am     Reply with quote

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 Razz

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

View user's profile Send private message Visit poster's website

PostPosted: Mon Apr 26, 2021 9:43 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Apr 26, 2021 10:53 am     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Mon Apr 26, 2021 10:55 am     Reply with quote

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.
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