Delay when toggling Parallel Port Pins.

I’m currently testing the rabbit in the hopes of interfacing with external hardware.

I’m a bit confused. My processor is running at 50mhz (20ns period), yet it takes me about 1.6uS to toggle a pin from high to low and back to high again.

I ran some code in assembly…i’m not at my work computer but it was something like this…


ld a, (PCDRShadow)  //load shadow register
set a,0                       //set bit 0
ld (PCDRShadow),a    
ioi ld (PCDR),a          //update

ld a, (PCDRShadow)  //load shadow register
res a,0                      //clear bit 0
ld (PCDRShadow),a
ioi ld (PCDR),a         //update

1.6uS/20ns=80 cycles. What is taking so long?

I was testing some of the External I/O code from a recent post. It worked fine and I saw a 20ns strobe on the scope so I know the rabbit is capable of doing 20ns signals. I’m just wondering why I can’t do it manually.

So I was able to look at the list file. Here’s how the code breaks down:


000:e846 F5           push af                                  11
000:e847 3A00C5       ld a, (0xC500)                           9
000:e84a CBAF         res 5, a                                 4
000:e84c 3200C5       ld (0xC500), a                           10
000:e84f D3325000     ioi ld (0x0050), a                       11
000:e853 3A00C5       ld a, (0xC500)                           9
000:e856 CBEF         set 5, a                                 4
000:e858 3200C5       ld (0xC500), a                           10
000:e85b D3325000     ioi ld (0x0050), a                       11
000:e85f F1           pop af                                   7

That’s a total of 85 clock cycles.
85*20ns=~1.7uS.

Unfortunately this is way too much time to toggle a pin. This reduces my 50mhz processor to a 500khz processor.

There has to be a way to optimize the code. Is there an instruction that lets me access the registers directly, without having to load them into a? this would eliminate all the ld commands.

Someone chime in!!

As a first step, you do not need to save to the shadow register and load from it so many times. Only one load and one save. This shortens the pulse


  push af              ;; 11  
  ld a, (PCDRshadow)   ;;  9  Make sure other bits are not changed

  res 5, a             ;;  4  Assume pulse is active low
  ioi ld (PCDR), a     ;; 11  Emit pulse
  set 5, a             ;;  4  Remove pulse again
  ioi ld (PCDR), a     ;; 11  and output it; width is only 15 clocks

  ld (PCDRshadow), a   ;; 10  Restore state in case PCDR used elswhere
  pop af               ;;  7

If you want a stream of pulses you can replicate the middle code as follows:


  push af              ;; 11        
  ld a, (PCDRshadow)   ;;  9  Make sure other bits are not changed

  res 5, a             ;;  4  Assume pulse is active low
  ioi ld (PCDR), a     ;; 11  Emit pulse
  set 5, a             ;;  4  Remove pulse again
  ioi ld (PCDR), a     ;; 11  and output it; width is only 15 clocks

  res 5, a             ;;  4  Assume pulse is active low
  ioi ld (PCDR), a     ;; 11  Emit pulse
  set 5, a             ;;  4  Remove pulse again
  ioi ld (PCDR), a     ;; 11  and output it; width is only 15 clocks

// ... add more  or put into djnz loop 
 
  res 5, a             ;;  4  Assume pulse is active low
  ioi ld (PCDR), a     ;; 11  Emit pulse
  set 5, a             ;;  4  Remove pulse again
  ioi ld (PCDR), a     ;; 11  and output it; width is only 15 clocks

  ld (PCDRshadow), a   ;; 10  Restore state in case PCDR used elswhere
  pop af               ;;  7

For a faster pulse stream, you can load the “set” value in register b, the “reset” value into register c and the destination port into hl:


  push af              ;; 11
  push bc
  push hl
          
  ld a, (PCDRshadow)   ;;  9  Make sure other bits are not changed

  res 5, a             ;;  4  Assume pulse is active low
  ld b, a
  set 5, a             ;;  4  Remove pulse again
  ld c, a
  ld (PCDRshadow), a   ;; 10  Restore state in case PCDR used elswhere
  ld hl, PCDR          ;;     Port address to hl

  ioi ld (hl), b       ;; (6+ioi) Emit pulse
  ioi ld (hl), c       ;; (6+ioi) turn off

  pop hl
  pop bc
  pop af               ;;  7