Author Topic: PIC and shift reg: peculiar delay  (Read 4228 times)

0 Members and 1 Guest are viewing this topic.

Offline PerranOakTopic starter

  • Frequent Contributor
  • **
  • Posts: 548
  • Country: gb
PIC and shift reg: peculiar delay
« on: November 24, 2021, 05:04:34 pm »
I have setup a PIC12F683 with the shift reg 74HC595 (circuit attached – I’ve not shown ground and Vcc connects but they’re there) and a simple prog to display a number on LEDs:

Code: [Select]
#pragma config FOSC = INTOSCCLK // Internal oscillator with FOSC/4 output on OSC2 and I/O on OSC1/CLKIN.
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown Out Detect (BOR enabled)
#pragma config IESO = ON        // Internal External Switchover bit (Internal External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)

#include <xc.h>


#define _XTAL_FREQ 250000       //slowed clock: doesn't overwhelm shift reg
#define data GPIObits.GP0
#define pulse_clock GPIObits.GP1 = 1, GPIObits.GP1 = 0;


void main(void)
{
    OSCCON = (OSCCON & 0xF) | 0b00100000;   //Blanks upper bits then ORs freq. Currently: 250kHz
    TRISIO = 0;                             //TRISIO to output
    CMCON0 = 0b00000111;                    //Sets GPIO pins to I/O and turns off comparator
    ANSEL = 0;                              //Sets pins to digital, as usual.   
   
    int display = 0b11110000;
   
    while(1)
    {
            for (int count = 0; count <8; count++)
            {
                data = (display >> count) & 1;  //right shifts by 0,1,2,3.. then blanks all but bit0
                pulse_clock
            }
            pulse_clock                         //Final pulse RCLK expects: it is one pulse behind SRCLK

            __delay_ms(1000);                   //needed or shift reg refresh blanks all LEDs
    }
}

I’ve made it like this because I want to use the absolute minimum number of pins on the uC as it has very few. The purpose is to investigate its registers “in-the-wild” as it were.

It seems to work well except for one peculiar thing: I noticed that when I increase the delay it increases the time before the number is displayed. This means that the number is not displayed until after the delay!

I cannot understand why this is so. Why does the number not display BEFORE the delay?

Any guidance gratefully received, thank you.
You can release yourself but the only way to go is down!
RJD
 

Offline Ian.M

  • Super Contributor
  • ***
  • Posts: 12860
Re: PIC and shift reg: peculiar delay
« Reply #1 on: November 24, 2021, 05:43:22 pm »
See http://picforum.ric323.com/viewtopic.php?f=38&t=12
My first suspicion when fast bit-banged I/O fails on a 'classic' midrange, or baseline PIC is always the RMW effect.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: PIC and shift reg: peculiar delay
« Reply #2 on: November 24, 2021, 06:40:20 pm »
Don't run it in a loop. It only make things difficult to debug. Do the required pulses and stop.

GP1 must be initialized to '0'. If it is '1' at the start, there will be no first pulse.

 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14472
  • Country: fr
Re: PIC and shift reg: peculiar delay
« Reply #3 on: November 24, 2021, 07:10:47 pm »
Yeah. I suspect you're interpreting what you see wrongly. If the first iteration of the 'while(1)' doesn't cause anything to display, then you'll see what you are seeing. And a likely cause is an initialization issue, such as what NorthGuy just suggested.

Just comment out the 'while(1)' statement, so there is only one iteration. If nothing displays, you'll have confirmation.
 

Offline PerranOakTopic starter

  • Frequent Contributor
  • **
  • Posts: 548
  • Country: gb
Re: PIC and shift reg: peculiar delay
« Reply #4 on: November 25, 2021, 03:43:25 pm »
Thanks all.

I initialised GP1 and removed the while(1) however, the PIC just looped and it became a blur. I then read Ian.M's link and, though I didn't quite get from that what the solution was, I guessed that a delay somewhere might do the trick.

I put the delay between "data" and "pulse" and it worked! Odd thing was that only a delay of at least 250ms (a huge amount of time in uC world!) would do, otherwise some bits were missed.

Then I experimented and came up with this (all config, etc. remain the same as before):

Code: [Select]
void main(void)
{
    OSCCON = (OSCCON & 0xF) | 0b00100000;   //Blanks upper bits then ORs freq. Currently: 250kHz
    TRISIO = 0;                             //TRISIO to output
    CMCON0 = 0b00000111;                    //Sets GPIO pins to I/O and turns off comparator
    ANSEL = 0;                              //Sets pins to digital, as usual.   
    GPIObits.GP1 = 0;                       //initialise GP1
   
    int display = 0b10000001;
   
    __delay_ms(250);                        //this has to be here! Why? Dunno!
    for (int count = 0; count <8; count++)
        {
            data = (display >> count) & 1;  //right shifts by 0,1,2,3.. then blanks all but bit0
            pulse_clock
        }
            pulse_clock                     //Final pulse RCLK expects: it is one pulse behind SRCLK

    while(1);
}

It worked too!

I'd thought that I needed a delay between the changing of GP0 and GP1 in re RMW but what's needed is a delay before any changes to bits!
Again, a minimum of 250ms is required.

How can I understand why this works?

Cheers.
« Last Edit: November 25, 2021, 04:18:40 pm by PerranOak »
You can release yourself but the only way to go is down!
RJD
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: PIC and shift reg: peculiar delay
« Reply #5 on: November 25, 2021, 05:37:17 pm »
There might be a need for a small delay if PIC becomes operational before the shift register, but 250 ms is absurdly long. You may have discrepancy between real instruction speed and _XTAL_FREQ setting, so the delay you produce is not really 250 ms, or you may have really slow voltage ramp at startup.
 

Offline MarkF

  • Super Contributor
  • ***
  • Posts: 2549
  • Country: us
Re: PIC and shift reg: peculiar delay
« Reply #6 on: November 25, 2021, 05:57:15 pm »
You might want to try changing the PWRTE config bit to ON.

  "The Power-up Timer provides a fixed 64 ms (nominal)time-out on power-up. 
  The chip is kept in Reset as long as PWRT is active.
  The PWRT delay allows the VDD to rise to an acceptable level.
"

#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)


Also, I don't understand why you need to run the PIC at such a slow clock (250 KHz).
The 74HC595 is capable of clock speeds over 20 MHz according to its datasheet.
While the instruction speed is a max of 2 MHz (Fosc/4).

I would like see the serial clock and data line on a scope....
We are really just guessing here without it.
 

Online Doctorandus_P

  • Super Contributor
  • ***
  • Posts: 3359
  • Country: nl
Re: PIC and shift reg: peculiar delay
« Reply #7 on: November 25, 2021, 09:27:59 pm »
Problems like this are a perfect application for an EUR 10 logic analyzer.

Sometimes ISR's are interfering with your software.
There are also "synchronizers" on input pins that may lead to confusing results.
I also like to sprinkle some output pin toggles through my code to to correlate the software with the rest of the outputs that the Logic Analyzer logs.

Also:
From memory, I think the 74xx595 also needs a latch signal to transfer data from the shift registers to the outputs.

« Last Edit: November 25, 2021, 09:33:41 pm by Doctorandus_P »
 

Offline nigelwright7557

  • Frequent Contributor
  • **
  • Posts: 690
  • Country: gb
    • Electronic controls
Re: PIC and shift reg: peculiar delay
« Reply #8 on: November 25, 2021, 09:36:49 pm »
I might be missing something but why no series resistors on LED's ?
Might be killing your power supply.
 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: PIC and shift reg: peculiar delay
« Reply #9 on: November 26, 2021, 08:54:15 am »
From memory, I think the 74xx595 also needs a latch signal to transfer data from the shift registers to the outputs.
Not the case here, as shift clock and latch clock are tied together: the extra pulse at the end of the loop will latch the current internal state to the output (while and shifting it internally - but we don't care).

I'll be obnoxious and comment on style, so not really related to OP's problem (I don't do PIC, though I think Ian.M got this right):
Code: [Select]
#define pulse_clock GPIObits.GP1 = 1, GPIObits.GP1 = 0;This is ugly for a number of reasons, and make the code look like Pascal (no semicolon, and no argument list in soimething that behaves like a function).
The use of comma operator plus semicolon in the #define can also cause some problems whit conditionals or loops, if care is not taken.
The usual way of declaring a function-like macro that acts (as much as possible...) as a real function and needs more than one statement is:
Code: [Select]
#define pulse_clock() do { GPIObits.GP1 = 1; GPIObits.GP1 = 0; } while (0)Then in the body of the code it can be used "normally":
Code: [Select]
pulse_clock();
« Last Edit: November 26, 2021, 01:02:09 pm by newbrain »
Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: thinkfat

Offline Ian.M

  • Super Contributor
  • ***
  • Posts: 12860
Re: PIC and shift reg: peculiar delay
« Reply #10 on: November 26, 2021, 01:45:36 pm »
Try:
Code: [Select]
#pragma config FOSC = INTOSCCLK // Internal oscillator with FOSC/4 output on OSC2 and I/O on OSC1/CLKIN.
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown Out Detect (BOR enabled)
#pragma config IESO = ON        // Internal External Switchover bit (Internal External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)

#include <xc.h>

#define _XTAL_FREQ 250000       //slowed clock: doesn't overwhelm shift reg
#define DATA GP0  // pins on GPIO port
#define CLK GP1

/******************** GPIO port shadowing ********************/
#define sGPIObits (*(GPIObits_t * volatile __bank(0))&sGPIO)
#define UpdateGPIO() ((void)(GPIO=sGPIO))
volatile __bank(0) uint8_t sGPIO; // software shadow for port
/*************************************************************/

/*********** macro to pulse clock and update port ************/
#define pulseCLK() do{ \
                   UpdateGPIO(); \
                   sGPIObits.CLK=1; \
                   UpdateGPIO(); \
                   sGPIObits.CLK=0; \
                   UpdateGPIO(); \
                   }while(0)
/*************************************************************/

void main(void){
    uint8_t display = 0b11110000;

    OSCCON=0x20;                          //Set 250kHz Fosc
    TRISIO=0;                             //TRISIO to output
    CMCON0=0b00000111;                    //Sets GPIO pins to I/O and turns off comparator
    ANSEL=0;                              //Sets pins to digital, as usual.     
       
    while(1){
            for (uint8_t mask=1; mask; mask<<=1){
               sGPIObits.DATA=!!(display&mask);
               pulseCLK();
            }
            pulseCLK();                    //Final pulse RCLK expects: it is one pulse behind SRCLK
            __delay_ms(1000);              //needed or shift reg refresh blanks all LEDs
    }
}
which should totally avoid the RMW issue by doing software shadowing for the GPIO port.

Caution: I don't currently have the XC8 toolchain installed, so the above has not been compiled and tested so may have some syntax errors.  Also its quite a while since I did anything in XC8 PIC C . . .

'Air Code' is the programmer's equivalent of 'Air Guitar' but is a *LOT* more embarrassing ;-)
« Last Edit: November 26, 2021, 01:47:44 pm by Ian.M »
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: PIC and shift reg: peculiar delay
« Reply #11 on: November 26, 2021, 02:58:14 pm »
This is ugly for a number of reasons, and make the code look like Pascal (no semicolon ...

Pascal does use semicolons.
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14472
  • Country: fr
Re: PIC and shift reg: peculiar delay
« Reply #12 on: November 26, 2021, 04:29:26 pm »
This is ugly for a number of reasons, and make the code look like Pascal (no semicolon ...

Pascal does use semicolons.

Of course, but semicolons are not required for the last statement of a block. Maybe seeing this 'pulse_clock' wtihout semicolon just before the closing } made newbrain think of Pascal, but this was just a particular use case here.

For macros that have a side-effect, I much prefer defining them with parentheses, even if they take no parameter. That makes them look like functions and the intent is clearer. And yes, avoid semicolons in macros too. I also prefer the convention of all-uppercase macros, so that you can immediately spot that this is a macro. So I'd define it like so:
Code: [Select]
#define PULSE_CLOCK() .....
And invoking it just looks like so:
Code: [Select]
PULSE_CLOCK();
 
The following users thanked this post: newbrain

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: PIC and shift reg: peculiar delay
« Reply #13 on: November 26, 2021, 05:02:36 pm »
For macros that have a side-effect, I much prefer defining them with parentheses, even if they take no parameter. That makes them look like functions and the intent is clearer. And yes, avoid semicolons in macros too. I also prefer the convention of all-uppercase macros, so that you can immediately spot that this is a macro. So I'd define it like so:
Code: [Select]
#define PULSE_CLOCK() .....
And invoking it just looks like so:
Code: [Select]
PULSE_CLOCK();

I just use inline functions.
 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: PIC and shift reg: peculiar delay
« Reply #14 on: November 26, 2021, 05:57:17 pm »
semicolons are not required for the last statement of a block
Yes, exactly what I was referring to. I loathed that thing - even if Pascal was my first high level language.
I also use UPPER_CASE_SNAKE for macros.

I just use inline functions.
So do I, most of the time - and TBH, modern compilers do a decent job of inlining short static functions even without the hint.
That, plus a liberal use of enums rather than #defines limits my use of the preprocessor to little more than includes and conditionals.

As this was an aside wrt the main topic, I did not want dig go too deep...
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14472
  • Country: fr
Re: PIC and shift reg: peculiar delay
« Reply #15 on: November 26, 2021, 06:13:56 pm »
semicolons are not required for the last statement of a block
Yes, exactly what I was referring to. I loathed that thing - even if Pascal was my first high level language.

I found it looked inconsistent. But the reason for this was that Pascal (and all its successors AFAIK) used the semicolon as a statement separator, rather than as a statement terminator.
I personally prefer statement terminators. And I have even more of a problem with languages having neither separators nor terminators (such as Python, Go...) But anyway.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: PIC and shift reg: peculiar delay
« Reply #16 on: November 26, 2021, 08:10:59 pm »
semicolons are not required for the last statement of a block
Yes, exactly what I was referring to. I loathed that thing - even if Pascal was my first high level language.

I found it looked inconsistent. But the reason for this was that Pascal (and all its successors AFAIK) used the semicolon as a statement separator, rather than as a statement terminator.

Technically yes, but you can use extra semicolons - you just create empty statements this way. So, anyone in the right mind would use a semicolon after the last statement in the block anyway. Otherwise, every time you add or delete a statement, you would have need to edit the previous line by adding or deleting the semicolon.

There's a similar thing in C with commas in enums. You don't need the last comma, but if you write enumerators one per line, it is very handy to have it.
 

Offline PerranOakTopic starter

  • Frequent Contributor
  • **
  • Posts: 548
  • Country: gb
Re: PIC and shift reg: peculiar delay
« Reply #17 on: November 30, 2021, 01:47:31 pm »
Thanks NorthGuy - neither was the case but cheers.
MarkF - tried the PWRTE but no difference. You're right about the clock: it was a hang-over from a previous investigation. I let the chip default to 4MHz and everything was the same.
Doctorandus_P - I don't have a logic analyser, worse luck!
nigelwright7557 - no I'm the one missing something: I forgot to show the resistors in the diagram, sorry, they are there though.
newbrain - oh. I though it was both clever and elegant, sorry. I would rather do things according to convention though so thank you.
Ian.M - thank you once more for your help (ref. many, many of my posts in the past). I tried it out and it does work (of course) thank you. See below.

Thank you very much to everyone. I used your points, and indeed code, to investigate. I was still getting weird errors that varied with all kinds of things: delays, whether MCLRE = ON or =OFF, when I cycled the power and so on.

Then came the final breakthrough. No matter what these things (delay, etc.) were set to or what I did it worked every time. What did I change? I unplugged the pickit3! When I unplugged it from the chip and powered on or reset it worked perfectly.  :palm:

What a pain in the @rse.
You can release yourself but the only way to go is down!
RJD
 

Offline Ian.M

  • Super Contributor
  • ***
  • Posts: 12860
Re: PIC and shift reg: peculiar delay
« Reply #18 on: November 30, 2021, 02:18:20 pm »
Yes.  Microchip ICSP programmer/debuggers have pulldown resistors on PGC (ICSPCLK) and PGD (ICSPDAT) for ICD (in-circuit debug) support to prevent glitches when changing the link direction between the programmer/debugger and the debug executive running on the PIC.  IIRC they are typically 4K7.  The additional loading can cause problems for some application circuits.

Exception: The original black button PICkit 2, didn't have the pulldowns - you had to provide them on the target or in your debug cable. They added them internally for the revised red button PICkit 2.

However your circuit should *NOT* be loading sensitive - the fact it is indicates you aren't handling the RMW effect properly, which may bite you in the ass if it is ever used in a high EMI environment
See John Oldenkamp's comments at https://www.microchip.com/forums/FindPost/313101

For anything more critical than blinking a LED to debug your code, either use the shadow register mitigation (e.g. the code I provided or one of the alternative implementations), or only write to the *WHOLE* port (and don't use the port register to store internal state for the code), or preferably switch to a PIC with LAT registers (e.g. PIC12/16F1xxx Enhanced Midrange, or PIC18) and use the LAT registers for *ALL* output, especially bit-banging.
 

Offline Dabbot

  • Regular Contributor
  • *
  • Posts: 192
  • Country: au
Re: PIC and shift reg: peculiar delay
« Reply #19 on: November 30, 2021, 11:46:45 pm »
When I unplugged it from the chip and powered on or reset it worked perfectly.  :palm:

Using the ICSPCLK / ICSPDAT pins as digital outputs with the PICKit3 still attached should not cause problems. I've done this before, using these same pins for data / clock on a chain of 595, with programmer still attached.

Are you decoupling your micro and 595? I don't see caps in your schematic.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: PIC and shift reg: peculiar delay
« Reply #20 on: December 01, 2021, 05:35:56 am »
Then came the final breakthrough. No matter what these things (delay, etc.) were set to or what I did it worked every time. What did I change? I unplugged the pickit3! When I unplugged it from the chip and powered on or reset it worked perfectly.  :palm:

No kidding. The pins you're using to control your shift register are the same pins used in ICSP. PICkit3 is probably still driving them while the PIC already started running, so you have to wait for PICkit3 to get out. Use different pins.
 
The following users thanked this post: SiliconWizard

Offline Ian.M

  • Super Contributor
  • ***
  • Posts: 12860
Re: PIC and shift reg: peculiar delay
« Reply #21 on: December 01, 2021, 06:59:05 am »
Yes,  As you (PerranOak) are using:
Quote
Code: [Select]
#pragma config MCLRE = OFF
the PICkit 3 cant hold the PIC in Reset to exit programming mode cleanly, so there may be a brief conflict on the GPIO pins used for ICSP.

I would always advise leaving /MCLR enabled, with an external 10K pullup.  Disabling it to use it as an ordinary input pin should be your absolutely last resort, only to be considered if its impractical to use a higher pin count PIC, and you cant figure out any other ways to save pins. 
 

Offline MarkF

  • Super Contributor
  • ***
  • Posts: 2549
  • Country: us
Re: PIC and shift reg: peculiar delay
« Reply #22 on: December 01, 2021, 04:38:11 pm »
Yes,  As you (PerranOak) are using:
Quote
Code: [Select]
#pragma config MCLRE = OFF
the PICkit 3 cant hold the PIC in Reset to exit programming mode cleanly, so there may be a brief conflict on the GPIO pins used for ICSP.

I would always advise leaving /MCLR enabled, with an external 10K pullup.  Disabling it to use it as an ordinary input pin should be your absolutely last resort, only to be considered if its impractical to use a higher pin count PIC, and you cant figure out any other ways to save pins.

I usually disable the MCLR- to save the pullup resistor.  As rarely do I need the reset function.
However, I avoid using any of the programming pins; MCLR-, ICSPDAT, ICSPCLK.  I just bring them straight to the programming header.  Thereby avoiding the messy multiplexing between the programming function and the application usage.
On these 8 pin PICs, it just might not be an option to avoid using the programming pins.
 

Online Doctorandus_P

  • Super Contributor
  • ***
  • Posts: 3359
  • Country: nl
Re: PIC and shift reg: peculiar delay
« Reply #23 on: December 05, 2021, 10:42:01 am »
If you don't have a Logic Analyser yet, then go buy one. (or two so you have a spare)

Sigrok / Pulseview has lots of supported hardware:
https://sigrok.org/wiki/Supported_hardware

For beginners I recommend an EUR 8 box with an Cypress CY7C68013A such as:
https://sigrok.org/wiki/VKTECH_saleae_clone

All those Saleeaeaea clones are pretty much equivalent.

Some time ago I also saw a pretty nice schematic to control a 74xx595 from a single uC pin.
It had two extra resistors and capacitors, and combined with some clever timing from the microcontroller it could control the clock, data and the output latch / clock independent from each other.
 

Offline Ian.M

  • Super Contributor
  • ***
  • Posts: 12860
Re: PIC and shift reg: peculiar delay
« Reply #24 on: December 06, 2021, 08:46:09 am »
Some time ago I also saw a pretty nice schematic to control a 74xx595 from a single uC pin.
It had two extra resistors and capacitors, and combined with some clever timing from the microcontroller it could control the clock, data and the output latch / clock independent from each other.
You are probably thinking of some variant of Roman Black's 'Shift1' concept.

With a few more components it can be extended for 8 bit output.  See https://www.eevblog.com/forum/projects/latched-shift-register-74hc595-control-via-single-mcu-io-pin/
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf