delay argument too long - Page 1
Forum section: electronics / general

author: ect_09
author_rank: Contributor
timestamp: October 23, 2014, 06:32:58 am
content: Code:#include<htc.h>__CONFIG(1, OSCSDIS & HSPLL);__CONFIG(2, BORDIS & PWRTDIS & WDTDIS);__CONFIG(3, CCP2RC1);__CONFIG(4, LVPEN & STVREN);__CONFIG(5, UNPROTECT);__CONFIG(6, WRTEN);__CONFIG(7, TRU);#define _XTAL_FREQ 4000000void sevenseg(char ch);void main(){char ch;TRISB=0;PORTB=0x00;while (1){ch = (++ch) % 10;sevenseg(ch);__delay_ms(1000);}}void sevenseg(char ch){switch(ch){case 0: PORTB=0x3F; break;case 1: PORTB=0x06; break;case 2: PORTB=0x5B; break;case 3: PORTB=0x4F; break;case 4: PORTB=0x66; break;case 5: PORTB=0x6D; break;case 6: PORTB=0x7D; break;case 7: PORTB=0x07; break;case 8: PORTB=0x7F; break;case 9 : PORTB=0x6F; break;default: PORTB=0x3F;}}Code:__delay_ms(1000);error showing that this delay argument is too long...when i writeCode:__delay_ms(100);its build up successfully .....but i need 1s delay....with this functionam using Hi-Tech compiler with MPLAB..Regards,

author: Torrentula
author_rank: Regular Contributor
timestamp: October 23, 2014, 07:46:22 am
content: I'll bite. The simple workaround would be:Code:void _delay_100ms(int n){while(n--){_delay_ms(100);}}int main(void){// 1000 ms delay_delay_100ms(10);}

author: tggzzz
author_rank: Super Contributor
timestamp: October 23, 2014, 08:42:19 am
content: What does the specification for the delay function state the range is?Are there any other delay functions with a different range?In other words, have you RTFM?

author: glatocha
author_rank: Regular Contributor
timestamp: October 23, 2014, 09:29:26 am
content: the delay function in XC compilers have a limitation of the number of cycles to count.So the limitation with vary together with your XTAL_FREQ setting.It is written somewhere in the XC8 compiler manual/user guide how the counter is calculated and how big it can be.I usually do just 100ms and then have my own small routines for 500ms, and 1s, which simply executes the build in x times.If 1000 is too big and you are just starting, use two times 500 or so

author: dannyf
author_rank: Super Contributor
timestamp: October 23, 2014, 10:27:36 am
content: Quotefixing the problem is far less important than understanding why it is a problem.

author: Psi
author_rank: Super Contributor
timestamp: October 23, 2014, 10:57:21 am
content: Just forget the delay functions altogether, its bad practice to use them. They block the MCU from doing anything else while its waiting.Setup a hardware timer interrupt to set flags after X timer overflows, check those flags in your main loop and take appropriate action (your event code) then clear the flags so they can be set again.Take a look hereRepeating_Code_Using_Timer_Overflow_Interrupts

author: con-f-use
author_rank: Unknown
timestamp: October 23, 2014, 11:46:10 am
content: Quote from: Psi on October 23, 2014, 10:57:21 amIf the mcu wouldn't do anything either way and it isn't batty powered why not use delay. It's much easier to program then looking up register values for a timer and putting the controller to sleep. Its not that the RAM is gonna wear out. I wouldn't say its bad practise, it's just that there are better ways for a busy or energy sensitive microcontroller.

author: glatocha
author_rank: Regular Contributor
timestamp: October 23, 2014, 01:08:31 pm
content: from the XC8 compiler docu:QuoteHow exactly the ms or us are calculated I didn't find

author: miguelvp
author_rank: Super Contributor
timestamp: October 23, 2014, 05:57:48 pm
content: Does it really use a double?http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__util__delay_1gad22e7a36b80e2f917324dc43a425e9d3.htmlThen again I haven't even looked if this is the actual function the OP is using or even if it's the same toolchain and/or chip.

author: westfw
author_rank: Super Contributor
timestamp: October 24, 2014, 02:31:09 am
content: The avr-libc _delay_ms() function really uses a floating point argument ("double"), and it REQUIRES that compiler optimization and compile-time calculations reduce that to integer values used to build busy loops. All sorts of bad things (wrong times, bloated code, perhaps warning messages) happen if you don't turn on the optimization file, or use an argument that isn't a constant, or otherwise defeat the assumption. It's an interesting strategy.In this case, the OP is talking about a Microchip PIC compiler function - entirely different.It's somewhat humbling how many times you have to loop on a modern microcontroller to get human-scale delay times :-(

author: Jeroen3
author_rank: Super Contributor
timestamp: October 24, 2014, 05:31:53 am
content: Quote from: Psi on October 23, 2014, 10:57:21 amThis.Put a 16 bit timer on a millisecond per tick (never reset), then wait until the timer compare flag is true, or the counter value >= calculated point. Don't exceed 65 seconds.This is how operating systems perform delays, using system ticks.

author: westfw
author_rank: Super Contributor
timestamp: October 24, 2014, 08:03:50 am
content: QuoteYes, probably. But the Arduino delay() function isn't much better than the PIC delay loop being described, just because it uses a timer and an interrupt and a clock tick counter (in a loop) instead of a simple instruction loop. You shouldn't need to implement an operating system just to do simple timing hacks...

author: dannyf
author_rank: Super Contributor
timestamp: October 24, 2014, 11:14:28 am
content: QuoteFirst of all, it doesn't need to be on millisecond interrupt for the timing to work, even down to sub-us resolution;2ndly, it may not be possible to get to 1 millisecond interrupt - sometimes the hardware may not support it;3rdly, it takes away one timer - often a precious resource for low-end chips.The aversion to software delay is overblown. They have their downside, so does the hardware timer approach. Sometimes, you don't need precision delays and you just want to be roughly right - software delays come in handy in those situations.

author: glatocha
author_rank: Regular Contributor
timestamp: October 24, 2014, 11:24:03 am
content: Not to mention when you want to make your very first "Hello world!" blinking LED and the advises you get is to use Timer with interrupt.

author: Jeroen3
author_rank: Super Contributor
timestamp: October 24, 2014, 11:59:48 am
content: I never said anything regarding an actual interrupt. You can read the flags and timer value by software, using while(!(reg&flag)) is way more accurate than using while(--i). Also, your software is still able to do other stuff if you design in a superloop and perform your delays with an if block, which it won't when you're using inline delay().It also saves you a ton of wasted cpu cycles, which will be really scarce when you're updating your product for the who-knows time.Please note that any interrupt will delay your inline delay even more.

author: dannyf
author_rank: Super Contributor
timestamp: October 24, 2014, 01:04:58 pm
content: :You can read the flags and timer value by software, using while(!(reg&flag)) is way more accurate than using while(--i). :it depends. I can certainly construct a scenario where it is less accurate with your approach.:, your software is still able to do other stuff if you design in a superloop and perform your delays with an if block, which it won't when you're using inline delay().:you can certainly structure a delay loop to do that.as to wasted CPU cycles, sometimes it is the goal to waste CPU cycles.the whole point is that just like timer based delays, software delays have their pros and cons. It is naive to say which is good or bad. It is application specific

author: westfw
author_rank: Super Contributor
timestamp: October 25, 2014, 06:05:53 am
content: My XC8 manual says this for delay() (and delay_ms() is supposed to invoke delay()):Quote100ms at 4MHz is well within the 50M cycle limit, but the 179K cycle limit for PIC18 is only about 44ms.Why there is a difference, and why it's such a large difference... interesting questions.

author: glatocha
author_rank: Regular Contributor
timestamp: October 25, 2014, 09:58:52 am
content: That's very interesting what you are quoting.Which version/revision of the User Guide do you have? I was quoting revision B few posts earlier, when the PIC18 exception was not mentioned.

author: gnif
author_rank: Unknown
timestamp: October 25, 2014, 10:15:29 am
content: Quote from: Jeroen3 on October 24, 2014, 05:31:53 am1) No, they dont anymore where possible AFAIK, look up HPET. Ticks are usually determined by the CPU core and may very based on dynamic clock speed, SMP systems may have clocks that are out of sync with each other..2) What about overflow? Say your counter is at 60 seconds and you want to sleep for 10... 60+10 = 70, your comparison will never be ture.

author: westfw
author_rank: Super Contributor
timestamp: October 26, 2014, 12:08:58 am
content: QuoteDS50002053D from 10/2013, installed with xc8 v1.3 in/from early 2014.QuoteIndeed. Much more interesting that simply telling the OP to go read the manual.The 50M number is very close to 24bits worth of three-cycle loops (three nested 8bit loops, probably.) (but... the minimum instruction is 4 cycles, isn't it?)The 179k number is NOT that close to two nested 8bit loops.I guess someone should actually make some test programs and look at the code produced...

author: glatocha
author_rank: Regular Contributor
timestamp: October 26, 2014, 10:34:51 am
content: OK, I have made some testing, using compiler XC8 v1.31compiling for PIC16F88 and PIC18F26K201ms loop for PIC18Code:1048 ;main.c: 65: _delay((unsigned long)((1)*(16000000L/4000.0)));10491050 ;incstack = 01051 001AB2 0E06movlw61052 001AB4 0100movlb0; () banked1053 001AB6 6FD9movwf??_main& (0+255),b1054 001AB8 0E30movlw481055 001ABA u6247:1056 001ABA 2EE8decfszwreg,f,c1057 001ABC D7FEgotou62471058 001ABE 2FD9decfsz??_main& (0+255),f,b1059 001AC0 D7FCgotou62471060 001AC2 D000nop21ms loop for PIC16Code:1448 ;main.c: 89: _delay((unsigned long)((1)*(16000000L/4000.0)));14491450 ;incstack = 01451 ; Regs used in _main: 1452 0678 3006movlw61453 0679 1683bsf3,5;RP0=1, select bank11454 067A 1303bcf3,6;RP1=0, select bank11455 067B 00D3movwf(??_main^(0+128)+1)1456 067C 3030movlw481457 067D 00D2movwf??_main^(0+128)1458 067E u3287:1459 067E 0BD2decfsz??_main^(0+128),f1460 067F 2E7Egotou32871461 0680 0BD3decfsz(??_main^(0+128)+1),f1462 0681 2E7Egotou32871463 0682 0000nop1000ms loop for PIC16Code:1448 ;main.c: 89: _delay((unsigned long)((1000)*(16000000L/4000.0)));14491450 ;incstack = 01451 ; Regs used in _main: 1452 0667 3015movlw211453 0668 1683bsf3,5;RP0=1, select bank11454 0669 1303bcf3,6;RP1=0, select bank11455 066A 00D4movwf(??_main^(0+128)+2)1456 066B 304Bmovlw751457 066C 00D3movwf(??_main^(0+128)+1)1458 066D 30D1movlw2091459 066E 00D2movwf??_main^(0+128)1460 066F u3287:1461 066F 0BD2decfsz??_main^(0+128),f1462 0670 2E6Fgotou32871463 0671 0BD3decfsz(??_main^(0+128)+1),f1464 0672 2E6Fgotou32871465 0673 0BD4decfsz(??_main^(0+128)+2),f1466 0674 2E6Fgotou32871467 0675 0000nop1000ms for PIC18 was not possible, so I did 40ms almost the maximum possibleCode:1048 ;main.c: 65: _delay((unsigned long)((40)*(16000000L/4000.0)));10491050 ;incstack = 01051 001AB2 0ED0movlw2081052 001AB4 0100movlb0; () banked1053 001AB6 6FD9movwf??_main& (0+255),b1054 001AB8 0ECAmovlw2021055 001ABA u6247:1056 001ABA 2EE8decfszwreg,f,c1057 001ABC D7FEgotou62471058 001ABE 2FD9decfsz??_main& (0+255),f,b1059 001AC0 D7FCgotou6247Summarizing:for larger numbers for PIC16 the compiler is adding one more loop and one more memory byte for storing loop counter.Looks like the PIC18 is limited for the two stage loops with one memory and W register.One inner loop takes 3 cycles so (255*3)*255 = ~195000 cycles. A bit more then the documentation statesI did one more try with the pure _delay() function, that counts the given number of cycles.I was able to successfully compile 197120 cycles delayCode:1048 ;main.c: 65: _delay(197120);10491050 ;incstack = 01051 001AB2 0E00movlw01052 001AB4 0100movlb0; () banked1053 001AB6 6FD9movwf??_main& (0+255),b1054 001AB8 0EFFmovlw2551055 001ABA u6247:1056 001ABA 2EE8decfszwreg,f,c1057 001ABC D7FEgotou62471058 001ABE 2FD9decfsz??_main& (0+255),f,b1059 001AC0 D7FCgotou62471060 001AC2 F000nopWhen I increased the number I've got the compilation error:QuoteSo, the compiler knows the limit. I think there's an error in the documentationSorry for such a long post

author: dannyf
author_rank: Super Contributor
timestamp: October 26, 2014, 11:24:06 am
content: That's the Hi-Tech delay() routines. delay_ms() and delay_us() are done via two macros. You may be able to find the documentation in the PICC compiler.