Jump to content
 
KM1

RTCOUNTER example - (solved) Caused by Silicon Errata

Recommended Posts

Hello,

I have run into a strange (for me) issue with the rtcounter module as provided by MCC and shown by the example program in the blog area of this site. I am using MPLabX and XC8, both up-to-date versions and I am trying the example on a pic18F47k40 xpress board. The issue is I set an output (RA4) in main after initializing the pic and then enter the while(1) loop where the rtcount_callNextCallback(); is called. The output now is turning on and off. The off duration is typically ~60u seconds, and on time can be varied with changes to the timer interrupt settings (I use a 1mS timer0 in 16 bit mode) and the number sent to the callback. Approximately every 3mS, the off time increases such that that cycle (only) is approx 50% duty cycle.

Turning the output on or off in the callback routine has no effect - I initially wanted to toggle on and off at a speed visible to the eye. Commenting out the callback in the main loop stops the output from going low.

I have checked errata and used the data sheet to confirm register settings, I tried moving the current-limited LED from RA4 to RA2, and I have studied the example program looking for obvious differences that may cause this behaviour.

I would appreciate thoughts and/or suggestions.

Keith
   

Share this post


Link to post
Share on other sites

Can you please post some code? Or even better the entire project (you can turn your project in to a zip file using the "Package" option when you right-click on the project name in MPLAB-X.)

I am not sure I understand the problem yet.

Share this post


Link to post
Share on other sites

The problem is the output is set high but goes low without a command saying to do so. I have zipped the project and have added it to the file download area

 

Share this post


Link to post
Share on other sites

Oh my, I have run it in the simulator and this is definitely broken. Let me debug it and I will get back to you with a clear answer on how to fix this and what is going on.

EDIT: OK. RTCOUNTER is designed for the timer to represent the bottom bits of a concatenated timer value. This ONLY works if the timer runs from 0 and overflows at FFFF. This means that you cannot set the timer period to 1ms the way that you did there, you can ONLY set the timer period to MAXIMUM which means the timer will run from 0x0000 to 0xFFFF, forming the bottom 16 bits of the concatenated timer.

I cannot test the code with TMR0 in the simulator as the simulator has a bug which does not allow TMR0 to work in 16-bit mode, and I do not have a 47K40 on me to test it on the actual hardware 😞

What you should see is this:

1. TMR0L and TMR0H should count upwards from 0x0000. 
2. When you call create timer it should take the current value of (TMR0H << 8 + TMR0L) and add 1000 to this, that should give you something like 1222 the first cycle.
3. At this point every time you call rtcount_callNextCallback() it should compare the current timer value obtained by ReadTimer() to 1222, it should do nothing until the timer exceeds 1222, then it should call the callback once and add 1000 to the timer absoluteltimeout, which should now be 2222, and the cycle should repeat.

Please check if this is what you see on the hardware, we can fix the period when this is working correctly. This should have a period of 8ms per tick, so 1000 should go about 8 seconds ...

What happened in your case in 16-bit mode with the period set to 1ms is that the rtcount_callNextCallback() routine ALWAYS thought that there was a timeout as it sets the timeout to be at something like 222, but because you reload the timer with a value much larger than this the routine always thinks the timer has timed out and it toggles the i/o pin on every pass through the while(1)

Share this post


Link to post
Share on other sites

To confirm above I changed your code to use TMR0 in 8-bit mode so that I can test it in the simulator. With the prescaler I set the period to 1.024ms, so it is not quite perfect, but close enough for a test (2.4% error).

I attach the project with these settings, this works fine in the simulator.

xpress1.zip

Share this post


Link to post
Share on other sites
Quote

scope.jpg

Ok now I am quite stumped. Is the time period there around 1ms per pulse?

Is it possible for you to single step (instruction step) the code in the debugger and see when the line toggles?

 

Share this post


Link to post
Share on other sites

Hi,

I am seeing the issue if  " rtcount_callNextCallback();" is called in While loop.

while (1)
    {
        // Add your application code
       //IO_RA1_SetLow();
        // Check if the next timer has expired, call its callback from here if it did
        rtcount_callNextCallback();
    }

I tested through debugger as well and see that after 5 round inside " rtcount_callNextCallback();" it Resets.

I wanted to attach the RA4 output signal but I am not able to figure it out how.

By default Stack Overflow is enabled,

#pragma config STVREN = ON    // Stack Full/Underflow Reset Enable bit->Stack full/underflow will cause Reset

If I disable it then RA4 output is "Low". I am not able to pinpoint to the exact line which is causing the issue. however, I will continue on this and update. 

 

 

 

Share this post


Link to post
Share on other sites

Hey Prasad, that should use almost no stack space? Very strange. Can you check the reset bits to see if it really is a stack overflow?

 

 

Share this post


Link to post
Share on other sites
30 minutes ago, Orunmila said:

Hey Prasad, that should use almost no stack space? Very strange. Can you check the reset bits to see if it really is a stack overflow?

 

 

I checked the "PCON0" register There was no Stack Over/Underflow but the "nRMLR" bit was low which means MCLR Reset. Default value as per datasheet should be PCON0 = 0011110x, the obtained value was 0011010x (STKOVF  STKUNF  WDTWV RWDT  RMCLR  RI  POR  BOR)

Even with STVEN enabled if we comment " rtcount_callNextCallback();"  device doesn't Reset.  We need to test " rtcount_callNextCallback();" function completely.

 

Share this post


Link to post
Share on other sites

Hi KM1,

If we load RTCOUNTER is loads the "Timer0 without interrupt" but, i see that the interrupt is enabled in the code. 

Could you please give some details on why Interrupt is enabled.

Also, I see EUSART and SPI-MASTER code in it if you share some details on this then it may be helpful.

  • Like 1

Share this post


Link to post
Share on other sites

Hmmm, that is very interesting. If it resets on the hardware due to a MCLR reset, and not in the simulator it is probably nothing to do with the software!

Share this post


Link to post
Share on other sites
11 hours ago, Prasad said:

Hi KM1,

If we load RTCOUNTER is loads the "Timer0 without interrupt" but, i see that the interrupt is enabled in the code. 

Could you please give some details on why Interrupt is enabled.

Also, I see EUSART and SPI-MASTER code in it if you share some details on this then it may be helpful.

I enabled the timer0 interrupt because it appeared to be a requirement to run the rtcount example. I don't understand how the callback would use the interrupt routine without my enabling the interrupts?

The eusart is to be used for debugging and the spi code is to allow the use of an ethernet interface module which is the primary goal for this project. I have not done anything with either as I was testing the rtcount module first. I very much like the approach used in the recount example.

Keith

Share this post


Link to post
Share on other sites

The full errata can be downloaded here : http://ww1.microchip.com/downloads/en/DeviceDoc/PIC18F27-47K40-Silicon-Errata-and-Data-Sheet-Clarification-80000713E.pdf

If this is the problem then this is quite a serious problem as everyone using C with those boards will be caught by this! It would mean that they ran a production batch of those boards with rev A2 silicon!

C

Share this post


Link to post
Share on other sites
I narrow down the issue. The controller is restarting due to "Stack Overflow".
 
line number 220 code is causing the issue,
      reschedule = timer->callbackPtr(timer->payload);
 
It looks like its a recursive which causing the issue but, I was not able to understand the part of the code how it works in a given time.
 
We tried by adding "NULL" pointer check to that line that worked but, I feel like as an application or function of API it may not but, it just saves from restarting the controller.
       if(timer->callbackPtr != NULL)
                reschedule = timer->callbackPtr(timer->payload);
 
I have attached the snapshot of the StackOverflow Flag setting.  
 
BTW. looks like its a simulator bug on showing nMLCR bit has low every time. I tested the voltage on the nMLCR it's not low nor dropping while executing the program.

line220 causing StackOV.jpg

  • Helpful 1

Share this post


Link to post
Share on other sites

Thank you  both for your very helpful suggestions and the time you are putting in to sort out this issue. I will be out of the office today and tomorrow, but will have time at the end of the week to do some more investigating at my end.

Keith

Share this post


Link to post
Share on other sites

@Prasad, that pointer cannot be null according to the C code, it is initialized at startup. I think you just found the problem! Good detective work!

Of course if you check for null there and it is indeed null then the device will not reset but also the callback will never be called so the problem is not yet solved...

Let’s try out that errata, I think that will fix it. If not let’s keep investigating how it is possible for this pointer to be null. It is either not initialized (the errata could cause this) or it is overwritten woth null at some point. Which one is it?

 

Share this post


Link to post
Share on other sites
4 hours ago, ric said:

You don't need to edit powerup.as if you tell the compiler about the " NVMREG" errata.

https://www.microchip.com/forums/m969418.aspx

 

 

Oh wow I did not realize this was implemented as an errata! That would by far be the best option! I am going to try it out and upload the project here, then KM1 should be able to test when he gets back!

 

Share this post


Link to post
Share on other sites

Here you go - I have compiled this with the +NVMREG option, and confirmed that this writes the appropriate bits before doing initialization of the function pointers through the TBLRD instruction.

KM1, I will leave this here for you to test. Uploading the project zip as well as the HEX I compiled.

I did find a host of bugs in the RTCOUNTER when you are using TIMER0 in 8-bit mode! It is clear this combination needs some work. 

1. The left shift in readTimer was still <<16 even if the timer was 8-bit causing all kinds of havoc
2. The definition of the global variable g_rtcounterH was 16-bit limiting us to 24bit range, but RTCOUNTER_CONCATENATE_TIMER_TICKS was defined specifying a 16-bit range so the math was all wonky

I set the timer to have a tick of 1us which makes the math easy, and then got 1s by setting the timer reschedule value to 1,000,000, which should make the output toggle every 1s, or come on every 2s ...

For the blog post we used TIMER1 and for that implementation everything seemed to be correct.

Also I did not run it long enough to rebase (wrap) so that may also have issues, that should happen after 4000 seconds, which is longer than it sounds ...

 

 

xpress1.zip

Share this post


Link to post
Share on other sites

Good job tracking this down folks.  It sounds like the templates need a little help for the 8-bit case and probably for the 32-bit case (running this on a PIC32).  Is there any news on getting the templates on a public repository (GITHUB) so we can contribute fixes and help out?

  • Haha 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


 


  • Popular Contributors

    Nobody has received reputation this week.

  • Similar Content

    • By burkart
      Hello All,
      I am working on a project (in MPLAB v5.10) with a PIC18F27K40 (PIC18 library v1.77.0) and I'm using the MCC (v3.85.1) generated I2C drivers, I2CSIMPLE from the Foundation Services. I can read from and write successfully to devices on the I2C bus. The problem comes when I try to communicate with a device that's not on the bus, the micro goes into an endless loop waiting for i2c_status to not be busy. My knowledge of programming in C is about 6 on a scale of 10, and for programming for embedded purposes, about 5 out of 10. I would like to have it so that I can check if a specific device is present on the I2C bus, and also be able to recover from errors on the bus without it going into a loop indefinitely.

      This I2C driver is pretty complex, and I am having difficulties wrapping my head around it. How would I make it so that the driver just returns an error or something I can check for status, rather than loop endlessly until the operation completes, which it never will?

      I have not edited any of the MCC generated code. This includes leaving the IRQ enable line commented in the i2c_master.c file, so instead it polls instead of using an interrupt to check if the i2c operation has completed.
      // uncomment the IRQ enable for an interrupt driven driver. // mssp1_enableIRQ(); Following is an example of how I am calling the i2c driver.
      i2c_write1ByteRegister(address, 0x0D, 0x07); // GPPUB pull-ups on pins 0-2 I am attempting to initialize a port extender, MCP23018, specifically enabling some pull-up resistors. I would like to issue this command, and if the extender is not present, then the micro will perform some tasks differently. With the port extender present the write operation works as expected and everything is fine. Of course the problem is when the extender is NOT on the bus to acknowledge.
      I have another question as well. This driver seems to operate a little slow. When watching the bus with a logic analyzer I noticed a rather long pause between bytes. I went looking through the i2c driver and in i2c1_driver.c I found the following code which I suspect is the cause.
      inline void mssp1_waitForEvent(uint16_t *timeout) { // uint16_t to = (timeout!=NULL)?*timeout:100; // to <<= 8; if(PIR3bits.SSP1IF == 0) { while(1)// to--) { if(PIR3bits.SSP1IF) break; __delay_us(100); } } } What is the purpose of the 100 us delay in the while loop? Reducing or eliminating the delay results in reducing or removing the pause between byte transactions, but I don't know enough to know how else this edit will effect the driver. Also, what is the commented out code at the top of the function used for? Is this part of the infinite loop problem I mentioned above?

       
      --
      James Burkart
    • By Orunmila
      error: variable has incomplete type 'void'
      If you are getting this error message trying to compile code that used to work or from some example code you found somewhere it is very likely because of the changes in the XC8 interrupt syntax introduced with V2.0 of XC8.
      Specifically I am getting this today for my interrupt service routine definition. I used to use the age-old way of doing this in XC8 as follows:
      // Old way to do this void interrupt myISR(void) { // Old way Interrupt code here } After the changes to the XC8 compiler which were mostly motivated to get better C standard compliance, particularly with C99, the syntax for that function should now use the commonly adopted concept of function declaration-specifier attributes, which traditionally start with 2 underscores and contains either a list of parameters in brackets or have empty brackets if no parameters are present. 
      // New and improved and C99 compliant way to specify an interrupt service routine in XC8 void __interrupt() myISR(void) { // New and improved interrupt code here } This syntax is now also consistent between XC8, XC16 and XC32
      Please see this post for more information on how to either work around this or change to the new syntax.
      https://www.microforum.cc/topic/5-i-used-to-use-to-locate-variables-but-since-xc8-20-this-is-no-longer-working/
    • By Orunmila
      I just downloaded XC32 V2.15, I was using V2.10 before. I find that some of my projects no longer compile. On my first check I noticed that the problems seem to occur when inline functions are used and the same header where the inline implementation is done is included in more than one compilation unit?
      Has any of you seen similar issues?
      I will investigate further and post here if I arrive at an answer.
       
      UPDATE: Ok, I managed to make a small test project to replicate the problem. I am attaching it here. 
      TestInlineXC32_2.15.zip
       
      Next I am going to test this on some other compilers to see what the deal is. I have confirmed that with that project when you switch it to V2.10 or older it all compiles just fine, but if you use V2.15 it failes to link with the following error:
      "/Applications/microchip/xc32/v2.15/bin/xc32-gcc"   -mprocessor=32MZ2048EFM100  -o dist/default/production/TestInlineXC32_2.15.X.production.elf build/default/production/main.o build/default/production/otherFile.o          -DXPRJ_default=default  -legacy-libc    -Wl,--defsym=__MPLAB_BUILD=1,--no-code-in-dinit,--no-dinit-in-serial-mem,-Map="dist/default/production/TestInlineXC32_2.15.X.production.map",--memorysummary,dist/default/production/memoryfile.xml
      nbproject/Makefile-default.mk:151: recipe for target 'dist/default/production/TestInlineXC32_2.15.X.production.hex' failed
      make[2]: Leaving directory '/Users/ejacobus/MPLABXProjects/TestInlineXC32_2.15.X'
      nbproject/Makefile-default.mk:90: recipe for target '.build-conf' failed
      make[1]: Leaving directory '/Users/ejacobus/MPLABXProjects/TestInlineXC32_2.15.X'
      nbproject/Makefile-impl.mk:39: recipe for target '.build-impl' failed
      build/default/production/otherFile.o: In function `myInlineFunction':
      /Users/ejacobus/MPLABXProjects/TestInlineXC32_2.15.X/inlinedheader.h:6: multiple definition of `myInlineFunction'
      build/default/production/main.o:/Users/ejacobus/MPLABXProjects/TestInlineXC32_2.15.X/inlinedheader.h:6: first defined here
      /Applications/microchip/xc32/v2.15/bin/bin/gcc/pic32mx/4.8.3/../../../../bin/pic32m-ld: Link terminated due to previous error(s).
      collect2: error: ld returned 255 exit status
      make[2]: *** [dist/default/production/TestInlineXC32_2.15.X.production.hex] Error 255
      make[1]: *** [.build-conf] Error 2
      make: *** [.build-impl] Error 2
      BUILD FAILED (exit value 2, total time: 680ms)
       
       
       
    • By Orunmila
      I am trying to configure the DAC on the 47K40 Xpress Evaluation board using MCC and I am confused about what I see.
       
      The screen I see is to the right ->
      I can understand that the Vref+ and Vref- fields are necessary when you are using the input pins for a reference but it is really confusing when the Vref+ is shown and it is read-only AND it shows an incorrect value as it does here.
      I would have expected that if I select Vdd as the reference the Vref+ value would either be hidden, or that it would have the same value as Vdd. 
      I also do not understand why the Output of the DAC is referred to as "Required ref", this talk of "Ref" all over the place is very confusing to the unsuspecting user. You should call the DAC out Value the Required DAC out Value above the line you show the result of the calculation, and when the references are set to Vdd or Vss then Vdd should match Vref+ and Vref- should be 0 even if those are read-only - even better just hide them if they should not be used!
      It turns out that Vref+ and Vref- are ignored if you have selected Vdd and Vss, and that Required Ref actually means the output that you desire to get from the DAC, for those as confused as I was. When you select the Vref+ pin as the reference then Vdd field is ignored.
      It also seems that the Vdd and Vref+ fields allow you to enter values way outside the electrical specs of the device, it does create a note that this is the case, but I would have expected a proper warning for something dangerous like this, at first I did not even notice this as it was green and just a note.

      Lastly when I select to use the FVR _buf2 as the positive reference for the DAC the screen no longer makes any sense. Now I can only edit Vdd (which is 5v) but my Vref is set to 2.048V via the 2x buffer on the FVR, but the Vref+ field is read-only so I cannot update it. MCC is however using the correct input reference of 2.048 as can be seen by the output being limited to 1.984V even when I require 3V.
       
       
      Required Boilerplate:
      Component Version Device PIC18F74K40 MCC 3.75 MPLAB-X 5.10 Foundation Services 0.1.31 PIC18 Lib 1.76.0
    • By Orunmila
      If you have purchased a "MPLAB(R) Xpress PIC18F47K40 Evaluation Board" from Microchip (part number DM182027) and you are running into difficulty because the board is behaving strangely it is most likely caused by a silicon errata on this device!
      The errata can be downloaded here: http://ww1.microchip.com/downloads/en/DeviceDoc/PIC18F27-47K40-Silicon-Errata-and-Data-Sheet-Clarification-80000713E.pdf
      The relevant section of the Errata is shown at the end.
      What is happening is that the compiler is using a TBLRD instruction somewhere and this instruction is not behaving as expected due to a silicon bug in REV A2 of the PIC18F47K40, causing the read to fail and the program to malfunction. Typically this happens as part of the C initialization code generated by the XC8 compiler, and since the compiler is optimizing, changing the code may cause the problem to temporarily disappear because you have few enough global variables that a table read is no longer the fastest way to initialize the memory segment for variables with static linkage.
      The XC8 compiler can avoid generating the sequence which will cause the failure if you tell it in the linker settings to implement the workaround for this Errata. This is done by adding +NVMREG to the setting as follows. Note that this is under the section "XC8 Linker" and the Option Category "Additional Options".
       

       
      This is the relevant section of the Errata.

       
       
    • By Orunmila
      I am trying to do a simple test to measure the output of the DAC using the ADC. The datasheet for the DAC states very clearly that if you have enabled the DAC output pin this will override any pin output functions including the digital output (TRIS) the weak pull-ups and the digital input threshold circuit (so ANSEL behaves like it is set to 1):

      But MCC is generating a warning saying that my setup is incorrect.

      Since the output settings are overriden when the pin is a DAC output this warning should not be created when the pin is a DAC output which makes it behave as needed. Besides there should not be any problem measuring an output pin using the ADC when it is an output anyway? I do not understand why the warning is claiming that it "requires" this pin to be set as input. 
      Perhaps it would be better if the warning said "this pin is being driven by the device, if you are trying to measure an external voltage this will interfere with your readings, you can avoid this by disabling the pin output drivers by making the pin an input" or something to that extent?
      Required Boilerplate:
      Component Version Device PIC18F74K40 MCC 3.75 MPLAB-X 5.10 Foundation Services 0.1.31 PIC18 Lib 1.76.0
    • By Orunmila
      I have a bunch of old projects using the @ method to hard locate variables at a specific location in data memory, but since I upgraded to XC8 2.0 none of these are working any more!
      How do I do this with the latest compiler? I am using XC8 v2.xx.
      I also saw this error at my interrupt service routine and I suspect that this is the same problem.
      My interrupt code looks like this 
      void interrupt my_isr(void) { ... my code here } error: variable has incomplete type 'void'
×
×
  • Create New...