Author Topic: delay argument too long  (Read 11672 times)

0 Members and 1 Guest are viewing this topic.

Offline ect_09Topic starter

  • Contributor
  • Posts: 17
delay argument too long
« on: October 23, 2014, 06:32:58 am »
Code: [Select]
#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 4000000

void 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: [Select]
__delay_ms(1000);
 

error showing that this delay argument is too long...
when i write
Code: [Select]
__delay_ms(100);its build up successfully .....
but i need 1s delay....with this function

am using Hi-Tech compiler with MPLAB..
Regards,
 

Offline Torrentula

  • Regular Contributor
  • *
  • Posts: 91
  • Country: de
    • My blog
Re: delay argument too long
« Reply #1 on: October 23, 2014, 07:46:22 am »
I'll bite. The simple workaround would be:

Code: [Select]
void _delay_100ms(int n)
{
    while(n--)
    {
        _delay_ms(100);
    }
}

int main(void)
{
    // 1000 ms delay
    _delay_100ms(10);
}
 

Offline tggzzz

  • Super Contributor
  • ***
  • Posts: 19488
  • Country: gb
  • Numbers, not adjectives
    • Having fun doing more, with less
Re: delay argument too long
« Reply #2 on: October 23, 2014, 08:42:19 am »
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?
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Offline glatocha

  • Regular Contributor
  • *
  • Posts: 114
Re: delay argument too long
« Reply #3 on: October 23, 2014, 09:29:26 am »
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
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: delay argument too long
« Reply #4 on: October 23, 2014, 10:27:36 am »
Quote
error showing that this delay argument is too long...

fixing the problem is far less important than understanding why it is a problem.
================================
https://dannyelectronics.wordpress.com/
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 9939
  • Country: nz
Re: delay argument too long
« Reply #5 on: October 23, 2014, 10:57:21 am »
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 here
Repeating_Code_Using_Timer_Overflow_Interrupts
« Last Edit: October 23, 2014, 10:59:42 am by Psi »
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline con-f-use

  • Supporter
  • ****
  • Posts: 807
  • Country: at
Re: delay argument too long
« Reply #6 on: October 23, 2014, 11:46:10 am »
Just forget the delay functions altogether, its bad practice to use them. They block the MCU from doing anything else while its waiting.
If 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.
 

Offline glatocha

  • Regular Contributor
  • *
  • Posts: 114
Re: delay argument too long
« Reply #7 on: October 23, 2014, 01:08:31 pm »
from the XC8 compiler docu:
Quote
An error will result if the delay period requested is too large (approximately 50,659,000
instructions). For very large delays, call this function multiple times.

How exactly the ms or us are calculated I didn't find
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: delay argument too long
« Reply #8 on: October 23, 2014, 05:57:48 pm »
Does it really use a double?

http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__util__delay_1gad22e7a36b80e2f917324dc43a425e9d3.html

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

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: delay argument too long
« Reply #9 on: October 24, 2014, 02:31:09 am »
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 :-(
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4078
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: delay argument too long
« Reply #10 on: October 24, 2014, 05:31:53 am »
Just forget the delay functions altogether, its bad practice to use them. They block the MCU from doing anything else while its waiting.
This.
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.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: delay argument too long
« Reply #11 on: October 24, 2014, 08:03:50 am »
Quote
it's bad practice to use [delay functions]
Yes, 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...

 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: delay argument too long
« Reply #12 on: October 24, 2014, 11:14:28 am »
Quote
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.

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

================================
https://dannyelectronics.wordpress.com/
 

Offline glatocha

  • Regular Contributor
  • *
  • Posts: 114
Re: delay argument too long
« Reply #13 on: October 24, 2014, 11:24:03 am »
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.
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4078
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: delay argument too long
« Reply #14 on: October 24, 2014, 11:59:48 am »
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.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: delay argument too long
« Reply #15 on: October 24, 2014, 01:04:58 pm »
: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
================================
https://dannyelectronics.wordpress.com/
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: delay argument too long
« Reply #16 on: October 25, 2014, 06:05:53 am »
My XC8 manual says this for delay() (and delay_ms() is supposed to invoke delay()):
Quote
An error will result if the delay period requested is not a constant expression or is too large (approximately 179,200 for PIC18 devices, and 50,659,000 instructions for other 8-bit PIC devices).
100ms 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.
 

Offline glatocha

  • Regular Contributor
  • *
  • Posts: 114
Re: delay argument too long
« Reply #17 on: October 25, 2014, 09:58:52 am »
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.
 

Offline gnif

  • Administrator
  • *****
  • Posts: 1676
  • Country: au
Re: delay argument too long
« Reply #18 on: October 25, 2014, 10:15:29 am »
Just forget the delay functions altogether, its bad practice to use them. They block the MCU from doing anything else while its waiting.
This.
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.

1) 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.
« Last Edit: October 25, 2014, 10:20:54 am by gnif »
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: delay argument too long
« Reply #19 on: October 26, 2014, 12:08:58 am »
Quote
Which version/revision of the User Guide do you have?
DS50002053D from 10/2013, installed with xc8 v1.3 in/from early 2014.

Quote
That's very interesting
Indeed.   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...
 

Offline glatocha

  • Regular Contributor
  • *
  • Posts: 114
Re: delay argument too long
« Reply #20 on: October 26, 2014, 10:34:51 am »
OK, I have made some testing, using compiler XC8 v1.31
compiling for PIC16F88 and PIC18F26K20

1ms loop for PIC18
Code: [Select]
  1048                           ;main.c: 65: _delay((unsigned long)((1)*(16000000L/4000.0)));
  1049                           
  1050                           ;incstack = 0
  1051  001AB2  0E06                movlw 6
  1052  001AB4  0100                movlb 0 ; () banked
  1053  001AB6  6FD9                movwf ??_main& (0+255),b
  1054  001AB8  0E30                movlw 48
  1055  001ABA                     u6247:
  1056  001ABA  2EE8                decfsz wreg,f,c
  1057  001ABC  D7FE                goto u6247
  1058  001ABE  2FD9                decfsz ??_main& (0+255),f,b
  1059  001AC0  D7FC                goto u6247
  1060  001AC2  D000                nop2

1ms loop for PIC16
Code: [Select]
  1448                           ;main.c: 89: _delay((unsigned long)((1)*(16000000L/4000.0)));
  1449                           
  1450                           ;incstack = 0
  1451                           ; Regs used in _main: [wreg]
  1452  0678  3006                movlw 6
  1453  0679  1683                bsf 3,5 ;RP0=1, select bank1
  1454  067A  1303                bcf 3,6 ;RP1=0, select bank1
  1455  067B  00D3                movwf (??_main^(0+128)+1)
  1456  067C  3030                movlw 48
  1457  067D  00D2                movwf ??_main^(0+128)
  1458  067E                     u3287:
  1459  067E  0BD2                decfsz ??_main^(0+128),f
  1460  067F  2E7E                goto u3287
  1461  0680  0BD3                decfsz (??_main^(0+128)+1),f
  1462  0681  2E7E                goto u3287
  1463  0682  0000                nop

1000ms loop for PIC16
Code: [Select]
    1448                           ;main.c: 89: _delay((unsigned long)((1000)*(16000000L/4000.0)));
  1449                           
  1450                           ;incstack = 0
  1451                           ; Regs used in _main: [wreg]
  1452  0667  3015                movlw 21
  1453  0668  1683                bsf 3,5 ;RP0=1, select bank1
  1454  0669  1303                bcf 3,6 ;RP1=0, select bank1
  1455  066A  00D4                movwf (??_main^(0+128)+2)
  1456  066B  304B                movlw 75
  1457  066C  00D3                movwf (??_main^(0+128)+1)
  1458  066D  30D1                movlw 209
  1459  066E  00D2                movwf ??_main^(0+128)
  1460  066F                     u3287:
  1461  066F  0BD2                decfsz ??_main^(0+128),f
  1462  0670  2E6F                goto u3287
  1463  0671  0BD3                decfsz (??_main^(0+128)+1),f
  1464  0672  2E6F                goto u3287
  1465  0673  0BD4                decfsz (??_main^(0+128)+2),f
  1466  0674  2E6F                goto u3287
  1467  0675  0000                nop

1000ms for PIC18 was not possible, so I did 40ms almost the maximum possible
Code: [Select]
  1048                           ;main.c: 65: _delay((unsigned long)((40)*(16000000L/4000.0)));
  1049                           
  1050                           ;incstack = 0
  1051  001AB2  0ED0                movlw 208
  1052  001AB4  0100                movlb 0 ; () banked
  1053  001AB6  6FD9                movwf ??_main& (0+255),b
  1054  001AB8  0ECA                movlw 202
  1055  001ABA                     u6247:
  1056  001ABA  2EE8                decfsz wreg,f,c
  1057  001ABC  D7FE                goto u6247
  1058  001ABE  2FD9                decfsz ??_main& (0+255),f,b
  1059  001AC0  D7FC                goto u6247

Summarizing:
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 states

I did one more try with the pure _delay() function, that counts the given number of cycles.
I was able to successfully compile 197120 cycles delay
Code: [Select]
  1048                           ;main.c: 65: _delay(197120);
  1049                           
  1050                           ;incstack = 0
  1051  001AB2  0E00                movlw 0
  1052  001AB4  0100                movlb 0 ; () banked
  1053  001AB6  6FD9                movwf ??_main& (0+255),b
  1054  001AB8  0EFF                movlw 255
  1055  001ABA                     u6247:
  1056  001ABA  2EE8                decfsz wreg,f,c
  1057  001ABC  D7FE                goto u6247
  1058  001ABE  2FD9                decfsz ??_main& (0+255),f,b
  1059  001AC0  D7FC                goto u6247
  1060  001AC2  F000                nop

When I increased the number I've got the compilation error:
Quote
main.c:65: error: (1274) delay exceeds maximum limit of 197120 cycles

So, the compiler knows the limit. I think there's an error in the documentation

Sorry for such a long post :)
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: delay argument too long
« Reply #21 on: October 26, 2014, 11:24:06 am »
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.
================================
https://dannyelectronics.wordpress.com/
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf