Long time loops in PIC Micro - Page 1
Forum section: electronics / general

author: ed_reardon
author_rank: Regular Contributor
timestamp: October 19, 2016, 07:16:53 am
content: Hi all,I want to know if I'm about to embark on the futile here, I'm very fresh at this, I'm after pointers but I'm happy to go away and do the work. I'm just finding very conflicting things online though.I am fixed to a PIC18F1330.My aim is to produce the following:- Output A to run at a certain frequency for 5 minutes.- Output A to then run at a different frequency indefinitely.- Output A to run at a different speed if it is interrupted by input A.I'm fine with everything except this annoying five minute delay which I read conflicting things about whether it is possible to do or not. I've read that using a for loop with a define second then nesting it with minutes is possible, some saying no matter what you do the watchdog will take precedence.This delay can be woefully inaccurate, as much as a minute either way presents no problem.I'll tell you how fresh to this I am, if a for loop is interupted does it reset or does it carry on when it resumes? Do I need to add code to clear the loop every time it is quit (forcibly?)Am I attempting the impossible here? Any pointers as to how such a thing might be done if it is possible? I'm not asking for chunks of code but a hint on the rough concept would be ideal?Cheers,Ed.

author: obiwanjacobi
author_rank: Super Contributor
timestamp: October 19, 2016, 07:35:03 am
content: It all starts with a time base. So setup a timer (overflow interrupt?) that is the basis of your counting. Use prescalers to make the time-out as long as possible.Then divide the 'ticks' you get from the timer further down by counting...You can generate the 'specific frequency' with another timer.The rest is simple after that.[I do not know PIC but these general concepts should be available in your MCU]

author: ed_reardon
author_rank: Regular Contributor
timestamp: October 19, 2016, 07:39:30 am
content: Quote from: obiwanjacobi on October 19, 2016, 07:35:03 amThank you for that obiwanjocbi that's very helpful. I'm currently researching prescaling.However this leaves me with another dumb question, if I prescale the timer this will only affect a loop where I call it? Not the whole program as I need very fast switching for the frequency output.I'm probably malformed that question, but basically if I prescale for the loop this won't affect my __delay_us elsewhere in the program?

author: Howardlong
author_rank: Super Contributor
timestamp: October 19, 2016, 07:57:51 am
content: I would approach this as follows:O use a timer to create a tick every millisecond or soO use an interrupt on the timer to count up a word of memory every tickO use the PWM peripheral to generate your Output AO use either an INT interrupt pin for your input AO run the device in a low power mode waiting for interruptsO in the super loop, check the INT pin's flag and ticker count

author: ed_reardon
author_rank: Regular Contributor
timestamp: October 19, 2016, 08:03:48 am
content: Cheers Howardlong!Much to go away and research here! I'll get there in the end.A week ago I was convinced I'd never get a pin to flash on and off, so it's just a matter of chipping away until I get there!Would I have enough memory to count say five minutes in milliseconds?

author: obiwanjacobi
author_rank: Super Contributor
timestamp: October 19, 2016, 08:08:15 am
content: Quote from: ed_reardon on October 19, 2016, 07:39:30 amThere are (probably) lots of prescalers. There is probably also one for the central clock, so that is NOT the one you need. You need to look for a prescaler that clocks the timer/counter (hardware) in your PIC. Reading the datasheet for your specific device may help a lot getting this clear. I know its intimidating at first, just start with the section about timers and go from there. If you read something you don't know or understand, try to look it up in other chapters of the datasheet. That way, you slowly acquaint yourself with your device.Start simple with just a small part/component of what you're trying to do, for instance, setup the timer (with its prescaler) and let the main-loop dump out the counter value (dump text to the PC or just make a pin toggle and attach a led/scope on that). See how the value-increments change as you change the prescaler. Then try to attach an overflow-interrupt to the timer, etc. Small steps.

author: Ian.M
author_rank: Super Contributor
timestamp: October 19, 2016, 09:05:44 am
content: Your chosen PIC has a motor control PWM module with only ONE timebase. It is capable of generating a squarewave in the background, and as the timebase is a 12 bit counter, it has fairly fine control of the output frequency, but as its only got a single timebase it cant output two different frequencies at the same time. Also its restricted to six specific pins that the module can control.If those restrictions are compatible with your requirements, you can follow Howard's suggestion to use it for the output A, and use the 16 bit Timers 0 or 1 for all other timing.They have /2Nprescalers, and work from a base frequency of Fosc/4. Timer 0 prescaler can do up to /256 but Timer 1 prescaler only goes up to /8. If you are using their prescalers, its better to use their natural rollover period as the timebase as every time they are written to the prescaler gets cleared, so you loose a fraction of a tick with every write, and the exact number of Fosc/4 cycles lost depends on the number of instruction cycles since the last increment - very awkward for precision timing.If you use a slow 'tick' timebase you'll need the frequency change input A to generate an interrupt so that the output frequency can be changed quickly, rather than on the next timebase 'tick'. If you use a much higher 'tick' rate, greater than the max delay you can tolerate responding to input A you can poll it.For us to give better advice, you'd need to put some approximate numbers on the frequencies and the max delay responding to input A.

author: 22swg
author_rank: Frequent Contributor
timestamp: October 19, 2016, 09:31:17 am
content: Run the pic at 32,768 Hz , timer will give you an rtc count .

author: Ian.M
author_rank: Super Contributor
timestamp: October 19, 2016, 10:03:01 am
content: *Dont* do that unless your output frequencies are well under 100Hz as the system clock controls the temporal resolution of the output frequencies you can generate and a 32768 Hz Fosc clock will make it impossible to generate frequencies above about 80Hz with even 10% accuracy apart from a limited set of 'spot' frequencies below approx 2 KHz which are exact divisors of Fosc/4

author: ed_reardon
author_rank: Regular Contributor
timestamp: October 19, 2016, 10:15:14 am
content: Cheers all, thank you all so much for your help and input.Fortunately I only require one input pin and one output pin, that is the sum total of the device. It's to control a stepper driver so one PWM pin is ideal.I require frequencies of aprox 1kHz, 2kHz and 7kHz (none of which are desired to be very accurate) so as I understand that bit is covered.Much to learn, I've got about 14 days at two hours a day to try and come up with something so wish me luck. I'm very new to this but I'm trying to learn as much as I can!Thanks again,Ed

author: dannyf
author_rank: Super Contributor
timestamp: October 19, 2016, 10:22:05 am
content: QuoteYou are attempting more than you are capable of at this point. Itself not a bad thing but it does make your life easier if you start with the basic.In this case, try to code a long delay and see if you can do it. there are numerous ways of doing it, each with its advantages and shortcomings. if you can master a few, it will lay a solid ground for your future.

author: ed_reardon
author_rank: Regular Contributor
timestamp: October 19, 2016, 10:29:45 am
content: Quote from: dannyf on October 19, 2016, 10:22:05 amOh I agree Danny!Only way is to suck it up and learn it!I shall start 'fiddling!'

author: Ian.M
author_rank: Super Contributor
timestamp: October 19, 2016, 10:34:02 am
content: I'd start by confirming you can program the PWM module to generate each of the frequencies. You'll want a function to set it up then one to change it to each of the frequencies. Beware of glitches when changing the frequency, especially when going to a higher frequency as you need to tweak the duty cycle registers to keep it at 50% (or whatever duty cycle you need) - see the UDIS bit (datasheet section 14.13 PWM Update Lockout) for how to prevent incomplete updates.Then try to do something simple with an external interrupt for input A e.g. light a LED on another pin, and figure out how to act on both edges. An IOC (interrupt on change) pin may be easier - as it inherently triggers on both edges.Then all you've got left to do is the timing. Remember that if you use a long _delay_ms(), once its started you are committed to it. Yes an interrupt can go off and do something else, but there is no way to cut short the _delay_ms() once its started. Also _delay_ms() has severe limitations on the maximum time it can handle. IIRC 179200 instruction cycles, which is only 22.4ms at the maximum Fosc your chip can run at, so there is a strong incentive to learn timer interrupts so you can set up a more reasonable tick rate, and not have your timing distorted by loop overhead.If you give your word of honour this is not an academic assignment for credit in a MCU course, we can point you at specific code that can ease your timing problems. However if you are going to be marked on the algorithm you've chosen and its implementation, we have to take a step back and can only point you to general resources, or help you debug code you have written yourself.

author: dannyf
author_rank: Super Contributor
timestamp: October 19, 2016, 11:27:22 am
content: "Only way is to suck it up and learn it!"Yeah.At this point, don't worry about the hardware as that's easy to deal with later. Think about instead the logic and basic approach you needTwo typical approached exist and multiple variations of them.1. Have a timer that generate a signal when the duration is up. The timer can be a hardware one or a software one or a hybrid.Your code will set, and start the timer and then check for its signal when the desired duration has elapsed.2. Loop around and count the number of cycled. If the loop is of a known duration, you know the number of cycles you will need to run to waste your desired time duration.Obviously, you can implement them however you want but that's the gist of it.

author: ed_reardon
author_rank: Regular Contributor
timestamp: October 19, 2016, 11:28:25 am
content: You can have my word and I'll gladly affirm this is for no academic pursuit whatsoever.However at the moment I need to try and learn this stuff, all I'd ask is that if I posted up some code you'd tell me what I'd got wrong.I'm trying to avoid bolting together bits of code (although that'd make my life easier!) and try and have a better understanding.Time to get learning.Cheers,Ed

author: Ian.M
author_rank: Super Contributor
timestamp: October 19, 2016, 12:02:53 pm
content: I'll chuck a code snippet at you that will let you do longer software delays than the native delay macros can handle. Its good out to over a minute.Code://Just a simple delay, tuned for accuracy//XC8 v1.35 Free mode @30MHz on PIC18#define DELTUNE 1.2#define DELTUNE1 2.666void DelayMs(unsigned int ms) {if(!ms) return; //Handle zero case__delay_us(1000-DELTUNE1);while(--ms)__delay_us(1000-DELTUNE); // Tuning breakpoint here}DELTUNE compensates for loop overhead and DELTUNE1 for function entry/exit overhead. They will need tweaking if you want accuracy. seehttp://www.microchip.com/forums/m946599.aspxHere's another snippet for an ISR to implement a 1/10 second 'tick' counter that's as accurate as the crystal over long periods. Individual ticks jitter about a bit by up to one tick period, but the correction is carried forward from tick to tick. It rolls over after about 13 1/2 YEARS.. A 16 bit version has a 109 minute rollover. Bump up the tick rate to 100 per second if you need better accuracy for short periods.The natural timer rollover rate must be between the tick rate and half the tick rate .Code:#include <stdint.h>Code:volatile uint32_t ticks=0; // tick count in 1/10 s units#define COUNT100MS 62500UL // for 10Hz tick rate#define T1ROLLOVER 0x10000UL#define SECONDS *10#define MINUTES *600#define HOURS *36000//ISRvoid interrupt ISR(void) {static uint16_t excess=0;if(PIE1bits.TMR1IE && PIR1bits.TMR1IF) {PIR1bits.TMR1IF=0;ticks++;excess+=T1ROLLOVER-COUNT100MS;if(excess>=COUNT100MS) {excess-=COUNT100MS;ticks++;}}}It was written for a PIC16 so will need some tweaking for a PIC18. COUNT100MS is the number of timer increments per tick. It should be between 32768 and 65535. N.B. when the correction is applied 'ticks' double increments so never test if it is exactly equal to some number, only use inequaities.You would have to set up Timer1 and enable its interrupt yourself as the PIC18 version differs too much from the PIC16 version for it to directly help you.Also you need to disable interrupts while reading 'ticks' in the main program so you don't get it while its being changed. e.g.:Code:di();t=ticks; //Read ticks with interrupts disabledei();if(t>5 MINUTES){//do whatever here}I prefer a macro 'ATOMIC' to handle the di()/ei() so I can simply do:Code:ATOMIC t=ticks;Seehttp://www.microchip.com/forums/m839163.aspxfor details. and reasons why you need to disable the interrupts while manipulating a multibyte variable shared with an ISR.

author: Howardlong
author_rank: Super Contributor
timestamp: October 19, 2016, 01:52:55 pm
content: Quote from: Ian.M on October 19, 2016, 12:02:53 pmNice! I've not convinced myself I prefer it over an explicit GIE=0/GIE=1, but it's very neat nevertheless.

author: dannyf
author_rank: Super Contributor
timestamp: October 19, 2016, 02:00:27 pm
content: It is a very risky piece of code. I would consider it s bug.

author: Ian.M
author_rank: Super Contributor
timestamp: October 19, 2016, 02:08:37 pm
content: Quote from: dannyf on October 19, 2016, 02:00:27 pmIts documented, so its a FEATURE.Sure its risky - if you misuse it. So are ei() and di(). Any time you interact with the hardware at a lower level than the C language model, bad things can happen if you are careless. I wrote it to provide a di() ... ei() wrapper for small critical sections. If you wrap a function call or anything else that could conceal another di() ... ei() pair with it or use it from an ISR or before setting up and enabling the interrupts, you are too moronic to be developing for the 8 bit PICs.How it helps me: I can easily see which statements or small blocks are critical sections. Before I wrote it, I found ei() and di() just get lost in the forest when reading through code, and its all too easy to keep interrupts disabled for longer than is strictly necessary then a few edits later end up with an execution path that fails to reenable them..

author: SteveyG
author_rank: Unknown
timestamp: October 19, 2016, 02:37:05 pm
content: Quote from: Ian.M on October 19, 2016, 09:05:44 amThere are multiple separate timers though, each with prescalers and postscalers. Unless there needs to be any synchronisation with the motor PWM, it shouldn't be difficult.

author: Ian.M
author_rank: Super Contributor
timestamp: October 19, 2016, 02:55:29 pm
content: Yes, (although only the PWM module has a postscaler) and its not particularly difficult. Most of us who are familiar with the toolchain and the PIC18 range could knock it out in an afternoon.However my point was that it can only generate ONE frequency at a time autonomously, so if the project is going to suffer from feeping creaturitis and need another output, then the simple approach of using the PWM is no longer viable. You can generate extra frequencies using a timer and a pin toggle and timer reload ISR hung off the high priority vector, and for one more output that's not too bad, but it then gets fuglier for multiple outputs and if they aren't harmonically related, you'll be so far down the rabbit hole it would be better to start over with a chip with enough standard (E)CCP modules.

author: ed_reardon
author_rank: Regular Contributor
timestamp: October 19, 2016, 03:45:20 pm
content: All good points taken on board.This is a modification to an existing system, basically it's to save me a bit of faff at work! This fortunately can't creep any more.The timer can be crude (to the extent of a minute each way) but I'm going to try to learnt how to do it 'properly' so that the next project where I need critical timing will hopefully be easier!Thanks again for all the help, much to go away and research!Cheers,Ed

author: Ian.M
author_rank: Super Contributor
timestamp: October 19, 2016, 03:57:06 pm
content: That may make it harder if you are stuck with the input and output pins of the existing design.If you are unlucky, the output pin isn't PWM capable and maybe the input pin isn't interrupt capable either. You'd have to toggle an arbitrary output pin in the PWM timebase interrupt, and run it at double the frequency you want, polling the input pin in the same ISR. Still easily doable - just a bit more of a PITA to get working.

author: NivagSwerdna
author_rank: Super Contributor
timestamp: October 19, 2016, 04:11:31 pm
content: Quote from: ed_reardon on October 19, 2016, 07:16:53 amRather than having a for loop or even a while loop it might be worth rethinking your application and thinking more in terms of the hardware.As has been pointed out there is a timer from which you can generate an interrupt and use pre-scaling to make that overflow interrupt occur at not too frequent intervals. Your main program can be as simple aswhile (true) {}and then put the logic in the interrupt routines... e.g. on overflow then increment a timer and if that has reached a certain value change state and behaviour a different way until some other condition has been reached.The prettiest solution will probably have some very simple logic in the main loop but a good chunk of the logic in the interrupt routines.Each peripheral will have different nuances and generate different interrupts each... read each section of the datasheet at a time and see what you can get them to do. The power of the controller is the hardware bits and pieces.Have fun!

author: NivagSwerdna
author_rank: Super Contributor
timestamp: October 19, 2016, 04:45:10 pm
content: Quote from: ed_reardon on October 19, 2016, 07:16:53 amCan you be a bit more specific? What is your clock frequency? What frequency do you want to generate? What sort of wave? Looks like the PWM module, although complex, should make your application very simple.Try and draw a finite state machine diagram of the modes your application will have and the transitions between each mode.

author: cv007
author_rank: Frequent Contributor
timestamp: October 19, 2016, 05:13:32 pm
content: Don't overthink. Keep it simple until simple no longer works.main(){//setup for Output_A freq1//wait 5 minutesuint32_t ms = 1000*60*5;for( ; ms; ms-- ){//check for inputif( check_input_A ) break;__delay_ms(1);}//setup for Output A freq2for( ;; );}I do like my for loops self contained when possiblemain(){//setup for Output_A freq1//wait 5 minutesfor( uint32_t ms = 1000*60*5;ms && !Input_A;__delay_ms(1), ms-- );//setup for Output A freq2for( ;; );}

author: ed_reardon
author_rank: Regular Contributor
timestamp: October 19, 2016, 06:31:15 pm
content: Thanks again all.All great suggestions thankfully I'm left with the PWM pin as the unit is already controlled on this.Baby-steps I think, let me get to grips with simple PWM setup and I'll worry about the rest later. I'm grasping the data sheet slowly and once I've figured out the PWM stuff I'll start on bolting it together.I got 'v1' with the two speeds in delay_us, I thought my next brainwave would be relatively easy but alas I have much to get to grips with.Thanks for helping dullard here. I shall go and have a crack at it once I've finished this pintCheers again,Ed

author: dannyf
author_rank: Super Contributor
timestamp: October 19, 2016, 10:22:09 pm
content: QuoteI would take a similar approach as well:Code:do {OutputA_at_Initial_Freq();} while (elapsed_time<5 min);while (1) {if(!interrupted_by_A()) OutputA_at_another_Freq();else OutputA_at_different_Freq();}depending on your hardware implementation approach, each of the modules could be different but gist is the same.Whether you need fancy hardware pwm will be dependent on your frequency requirements.

author: Ian.M
author_rank: Super Contributor
timestamp: October 19, 2016, 10:33:53 pm
content: Quote from: ed_reardon on October 19, 2016, 10:15:14 amSo he could bit-bang the output, but doing so while handling software timekeeping would be a PITA.If short of time once the PWM is up and running, there's no problem with simply using delay_ms() in a superloop for the 5 minute timing, polling the input in the same loop.Personally, I'd use Timer 0 in 8 bit mode to implement a sandwich delay so I don't have to worry about the loop overhead, but I'm fussy that way as the tolerance on the 5 minutes certainly doesn't demand it.The more advanced techniques aren't actually needed for the simple 1 input 1 output case. They become valuable when the number of inputs and outputs goes up and you need to run independent processes sharing the hardware resources.

author: ed_reardon
author_rank: Regular Contributor
timestamp: October 20, 2016, 07:12:13 am
content: Quote from: dannyf on October 19, 2016, 10:22:09 pmThis is precisely what I want, as I've stressed a few times it doesn't even need to be accurate in terms of timing, frequencies can drift 10% without issue and the timing can go a full minute either side.Basically it's just to trip a motor/pump to pump a little bit quicker to purge the air when it's turned on, the pump isn't a controlled dose in a critical application.The 7kHz frequency is just controlled on a button to run the pump even quicker whilst pressed when changing the pumped solution to prime it through.Thank you all for your input, I'm quite touched so many have taken time to reply with such in-depth and insightful posts, I certainly do have a lot to learn!Cheers,Ed.

author: ed_reardon
author_rank: Regular Contributor
timestamp: October 22, 2016, 08:26:17 pm
content: Sorry it's Ed again.Right I've had a play with setting up hardware PWM and I think I've got to grips with it, however I think I've dropped a clacker here.Can RA0/CMP0 be set to deliver a PWM output? I was convinced I had an PWM pin to play with (long and short, although my 'scope output looks PWM, it's not a PWM pin.)Can the Comparitor 0 be used to drive a PWM output or am I talking rubbish here?Cheers, as always,Ed.

author: Ian.M
author_rank: Super Contributor
timestamp: October 22, 2016, 09:20:34 pm
content: No. Your proverbial pooch is screwed and you will have to resort to toggling that pin in software. The PIC18F1330 comparator module is input only, so even if you added a link to tie a PWM output to a comparator input, the resulting toggling comparator output is only a bit in a SFR, not a signal on a pin.However all is not lost. If you write an ISR that simply toggles the pin:Code:void interrupt high_priority HighISR(void){LATA^=0x01; //toggle RA0PIR3bits.PTIF=0; //Ctear PWM interrupt}you can get it to trigger once every PWM cycle giving you half the PWM frequency on RA0.You don't actually need to enable any of the PWM pins to do this - just set up the timebase and its interrupt:Code://Set up pinADCON1=7; //No analog pins for ADCCMCON1=7; //No analog pins for ComparatorLATAbits.LATA0=0; //RA0 is output//Set up interruptPTCON0bits.PTOPS=0; //No postscalerRCONbits.IPEN=1; //Enable interrupt prioritiesIPR3bits.PTIP=1; //Assign PWM interrupt to high priority vectorPIE3bits.PTIE=1; //Enable PWM interruptINTCONbits.GIEH=1; //Master interrupt enableThat will leave the low priority vector free for your timer ISR for implimenting a tick counter. However instead of using ei() or di() you must now set/clear INTCONbits.GIEL to enable/disable the low priority interrupts without affecting the squarewave from RA0 being generated by the high priority ISR.If you need to stop the pin toggling, simply disable PIE3bits.PTIE, then set LATAbits.LATA0 to the desired pin level. Re-enable PIE3bits.PTIE to resume toggling.

author: Ian.M
author_rank: Super Contributor
timestamp: October 22, 2016, 09:53:48 pm
content: bump: more code for Ed!I'd like to know what the original designer was smoking when they selected the PIC18F1330 - a chip specialised for motor control PWM - then failed to hook up the circuit's output to any PWM capable pin!Whatever it was, it must have been the good stuff . . .

author: dannyf
author_rank: Super Contributor
timestamp: October 22, 2016, 11:23:06 pm
content: QuoteFor things like that you should do it before finalizing the hardware design - unless the mcu supports pin remapping.QuoteYes and no. If the mcu supports interrupt on compare match, and you are not looking for really fast pwm frequencies, it can be done: basically, you set up two compares, and at the first compare, you set the pin and at the 2nd compare, you reset the pin.

author: Ian.M
author_rank: Super Contributor
timestamp: October 23, 2016, 12:19:51 am
content: Quote from: dannyf on October 22, 2016, 11:23:06 pmIt doesn't. Microchip PWM modules on the older 8 bit chips only permit interrupting on the period timer reload, not on the duty cycle compare*. Its possible to use an (E)CCP module to interrupt on compare match when it isn't configured for PWM, but this chip doesn't have any ECCP or CCP modules, only PWM modules.Hence my recommendation to use the period timer reload interrupt to get half the PWM frequency out.* You can fake it on PPS capable chips, by internally routing the PWM output to an external interrupt input.

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: October 23, 2016, 03:01:31 am
content: Quote from: ed_reardon on October 22, 2016, 08:26:17 pmThe 18F1330 has 6 pins that can output PWM. Why do you have to use RA0?

author: Ian.M
author_rank: Super Contributor
timestamp: October 23, 2016, 04:07:50 am
content: Quote from: Bruce Abbott on October 23, 2016, 03:01:31 amQuote from: ed_reardon on October 19, 2016, 03:45:20 pmSo he's stuck with the original chip and pinout unless he wants to rework every unit.

author: dannyf
author_rank: Super Contributor
timestamp: October 23, 2016, 01:38:27 pm
content: I took a look at the 18f1330 datasheet and it doesn't have a compare module.But it does have an interrupt-on-period functionality. So you can use the pwm module as a timer: load the period register alternately with the duty cycle count and period - duty cycle count.Essentially what this module does:Code://my pwm handlervoid mypwm(void) {if (_pwmdc++ & 0x01) {//test for lsb//lsb = 1 -> resetPTPER = PWM_PR - PWM_DC;//reset periodPWM_RESET();//reset pin} else {PTPER = PWM_DC;//load dcPWM_SET();//set pin}}Now set up the timer to run periodically:Code:ptmr_init(PWM_PS16x | PWM_PEIODIC);//periodic + prescalerptmr_setpr(PWM_DC);//initial period is dcptmr_act(mypwm);//install user handlerei();//enable global interruptsThe code above sets up the pwm module to run in periodic + 16:1 prescaler mode. load the pwm period register with the duty cycle count and install the mypwm routine as the isr handler once the period is reached.The output waveform, for PWM_PR = 100 and PWM_DC = PWM_PR / 3:

author: dannyf
author_rank: Super Contributor
timestamp: October 23, 2016, 01:40:11 pm
content: the downside with this approach is that since it is done via the isr, you cannot generate fast pwm. 20 - 30 ticks to be your minimum resolution.BTW, it can be used to generate complimentary output too - not shown here.

author: dannyf
author_rank: Super Contributor
timestamp: October 23, 2016, 01:47:40 pm
content: here is the same code producing complimentary output: positive polarity on RA0 and negative polarity and RA1/RA2.

author: Ian.M
author_rank: Super Contributor
timestamp: October 23, 2016, 02:10:33 pm
content: @Dannyf,What compiler or library is that for?The O.P.'s using Microchip XC8 (or a very late version of its predecessor HiTech C for PIC18) and the calls you are using don't correspond to anything in their standard libraries or the C18 compatibility PLIB. Microchip Code Configurator doesn't support the PIC18F1330 so it cant be that

author: dannyf
author_rank: Super Contributor
timestamp: October 23, 2016, 04:38:30 pm
content: since the pwm module here is used as a timer, the same can be done easily via a regular timer, with or without compare math.Here is an example of doing it on the good old TIMER0:Code:ptmr0_init(PWM_PS16x | PWM_PEIODIC);//periodic + prescalerptmr0_setpr(PWM_DC);//initial period is dcptmr0_act(mypwm);//install user handlerei();//enable global interruptsidentical output.As the whole thing is implemented via the interrupt, the timing is repeatable and the while loop is empty. Once set, the operation is fully transparent to the code and the programmer.

author: ed_reardon
author_rank: Regular Contributor
timestamp: October 23, 2016, 06:19:54 pm
content: Cheers all,As said I'm 'upgrading' an existing system with a good few thousand units to look after customer won't allow a new board per unit to make my day a bit smoother!I'll look at this in the week but thank you all so much for your input.I guess there is no such thing as an adaptor socket to make a physical pin reconfiguration?I have motor pulse on RA0, direction on RA1 and speed control on RB0.

author: ed_reardon
author_rank: Regular Contributor
timestamp: October 23, 2016, 06:32:48 pm
content: If RA0 was set to high-impedance is there any penalty for making a bodge wire on the PIC socket underside from a PWM pin to RA0.I know it's a bit 'how ya doin' as Dave would say but it's plausable from my cost/time angle?

author: Ian.M
author_rank: Super Contributor
timestamp: October 23, 2016, 06:57:25 pm
content: Quote from: ed_reardon on October 23, 2016, 06:19:54 pmI suspected that was the case.QuoteIf you were going down that road, you'd use a QFN package part on a DIL footprint adapter board. However the board would be entirely custom.Quote from: ed_reardon on October 23, 2016, 06:32:48 pmA bodge wire would let you re-route the real PWM but would be extra work per unit. Assuming RB4 isn't in use, running it diagonally across the socket would be the simplest option. (or if access to the underside of the board is poor, directly across the top of the chip soldered to the base of its pins). However there is absolutely no point in changing hardware*for >2K units if it can be done in software, and so far it looks like it can. Things that could change that would be if the PIC has to simultaneously perform other time-critical functions you haven't mentioned.I would personally be entirely satisfied with the toggle arbitrary pin in a high priority PTI ISR approach if all you need is a 50% duty cycle variable frequency squarewave. Once set up its nearly as 'fire & forget' as using a PWM pin. The pin output will be jitter free and as accurate as the PIC's clock source and 16 bit period timer allow, and its effect on timekeeping will be negligible amount of extra jitter on the timer interrupt (maybe 20 to 30 Tcy additional latency).* 2000 x 5 minutes per unit is a month of normal working hours. The software solution should only take a few hours extra to develop ==> a hardware mod just to relocate one PWM doesn't pay for >50 units.

author: ed_reardon
author_rank: Regular Contributor
timestamp: October 23, 2016, 07:37:45 pm
content: That's most helpful, cheers Ian M.The board (for the PIC element) consists of a PIC looking for the pins I've mentioned above, that's the sum total of its connections - fortunately it's through-hole and easy to remove (90s?)At the moment it bit-bangs a controller with two speeds either the looped "slow" or when the user presses a button it runs faster until they release.That's the whole shebang!It drives an off-the-shelf Stepper driver.

author: dannyf
author_rank: Super Contributor
timestamp: October 23, 2016, 09:59:30 pm
content: with moderate speeds, it is easier to just use an interrupt to flip RA0. By loading different offsets, you can control the frequency of the pulse train.