Shop OBEX P1 Docs P2 Docs Learn Events
Faster Serial Data Sending — Parallax Forums

Faster Serial Data Sending

gwilli3gwilli3 Posts: 3
edited 2009-04-14 20:05 in Propeller 1
Hello,
I am using the Propeller to serially drive 2 A6762 ICs to light up some LEDs.· I have not been able to get the LEDs to function (doing more than just staying lit or not turning on) without stalling for 381 clock cycles, which really limits my ability to fade colors.··I have been·loading·data to the·A6276 serially. ·Is there a way I can do this faster?· Here is my code.


PUB writeLong( _illuminate ) | illuminator
··· templumination := _illuminate
··· outa[noparse][[/noparse]outputenable] := 1················· 'disable LED output
··
··· illuminator := 0······
··· repeat illuminator from 0 to 15··········· ' sends eight bits as serial communication while pulsing latch enable

······ outa[noparse][[/noparse]serialoutpin] := templumination······· ' set data out pin to data
······ templumination >>= 1······················· ' shift to next bit····
······ outa[noparse][[/noparse]clockpin] := 1····················· ' set clock pin High
·
······ outa[noparse][[/noparse]clockpin] := 0····················· ' set clock pin Low
······ outa[noparse][[/noparse]latchenable] := 1·················· ' set latch enable high
······ outa[noparse][[/noparse]latchenable] := 0·················· ' set latch enable low

··· outa[noparse][[/noparse]outputenable] := 0················· 'enable LED output

Comments

  • MagIO2MagIO2 Posts: 2,243
    edited 2009-03-25 12:53
    Of course. You can do it in PASM.

    I don't really know the mentioned IC, but do you really have to set the latch enable to high/low after each bit? I'd expect that you first shift in your 16 bits and then do the latch-cycle.
    Do you want the LEDs have different brightness? Otherwise it might be a solution to let a counter do the dimming by enable/disable the shift register outputs with PWM.
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-03-25 20:19
    Now I had a look into the datasheed of the A6276.

    What you have to do is to shift 16 bits into your 2 registers by:
    1. Set/Clear the data out pin
    2. Wait for 50ns
    3. Set clock to high
    4. Wait for 50ns
    5. set clock to low
    6. Wait for 50ns
    7. Repeat with 1 until the 16 bits have been shifted
    8. Wait for 50ns
    9. set latch to high
    10. wait 100ns
    11. set latch to low

    Of course this is only the minimum time you have to wait. If your program is slower (and spin is much slower) there is no problem. With PASM it's possible to shift the data with the maximum speed. That would allow round about 300000 updates per second. Enough for a PWM.

    The general brightness can be controlled by the output enable as well.
  • gwilli3gwilli3 Posts: 3
    edited 2009-04-11 16:04
    Thanks Mag, I'll try exactly what you said. But, I do not know how to run PASM. Can you tell me a little bit about PASM and how I can use it for this. I have looked online a little, and I haven't found much about it.

    Thanks a lot,

    gwilli3
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-11 18:42
    PASM is of course described in the propeller manual. You start a PASM program with the cognew command. Instead of the name of a function you give it the adress of the PASM program and one parameter. If you need more parameters, you have to store them in a variable-block and pass the adress of the first parameter.

    cognew( @A6762_driver, @parameter_block)

    As you see in the name, for a lot of devices that need to be driven by PASM-code, the model of a driver is used. The driver is started once and runs in the COG for the whole time. You use the parameter block to pass commands to it and for data-exchange.

    Well, the implementation depends a little bit on what you want/need. 50ns waittime means you don't have to wait in the propeller at all because runtime of one instruction is exactly 50ns. So, I would simply repeat the sequence set pin, clock high, clock low 16 times. If you use a loop you loose speed for jumping.

    Here is the first bunch of code. This is currently only test code, not driving an A6276. But it's the sceleton of the dirver code. The only part which is missing is shifting out the signals.

    Please note, I use a 10MHz crystal, so please change the constants accordingly, if you want to run the code. The code is build for driving 9 LED's on pins 0-8. If you remove/change the lines marked with comment 'debug code' you can adopt it to your setup.
    CON
            _clkmode        = xtal1 + pll8x
            _xinfreq        = 10_000_000
    var
            long          yep
            ' this is the parameter variable for communication with COG
            long          A6276_par
            
    pub PASMstore
      A6276_par.word[noparse][[/noparse]1] := $0010                            ' setting the waittime of the COG until it reads
                                                            ' the next value from parameter variable
      A6276_par.byte[noparse][[/noparse]0] := $02                              ' set clock pin (0-31)
      A6276_par.byte[noparse][[/noparse]1] := $01                              ' set output pin (0-31)
      ' A6276_par := $0000_01_02                            ' alternative way to do the same
      dira[noparse][[/noparse]8]:=1                                            ' debug code
      outa[noparse][[/noparse]8]:=1
      
      cognew( @A6276_driver, @A6276_par )                   ' start the driver
      repeat while A6276_par                                ' and wait until startup is complete
      !outa[noparse][[/noparse]8]                                              ' debug code
      yep := 0                                              ' test code
      repeat                                                ' 
        yep++
        A6276_par:=yep                                      ' set the parameter
        repeat while A6276_par                              ' and wait for sync
        !outa[noparse][[/noparse]8]                                            ' debug code
        waitcnt( clkfreq/4+cnt)
    dat
                            org 0
    A6276_driver
                            mov     dira, #$ff              ' debug code
                            mov     ppointer, par           ' store the pointer to the parameter
                            rdlong  parameter, ppointer     ' and read the parameter from HUB-RAM
                            ' high word of parameter is the waittime
                            ' maybe it makes sense to shift the value for smaller times
                            ' or maybe use the log-table
                            mov     waittime, parameter     ' make a copy of the parameter
                            and     waittime, highword WZ   ' and extract the waittime word
                  if_z      mov     waitornot1, nowait1     ' if waittime is zero, remove waitcnt from code
                  if_z      mov     waitornot2, nowait2
                            ' prepare the pin-masks for output-pin and clock-pin
                            mov     temp, parameter
                            shr     temp, #8                ' extract the high byte of low word
                            and     temp, #$1f
                            shl     outpin, temp
                            mov     temp, parameter
                            and     temp, #$1f              ' extract the low byte
                            shl     clkpin, temp
                            ' set the two pins to output
                            or      dira, outpin
                            or      dira, clkpin
                            wrlong  zero, ppointer          ' show caller that we're done with reading parameter
    A6276_loop1             mov     time, cnt               ' calculate the counter value to wait for
                            add     time, waittime          ' if waittime was zero it's uselss, but no problem
    A6276_loop2             rdlong  parameter, ppointer WZ  ' see if we have to send a value
    waitornot1    if_z      waitcnt time, waittime          ' if waittime was given, then wait
    nowait1       if_z      jmp     #A6276_loop2            
                            ' if a new value is found, then start sending to A6276
                            ' ************************************
                            ' this part is missing currently
                            ' ************************************
                            mov     outa, parameter         ' debug code
                            
                            wrlong  zero, ppointer          ' show caller that we're done with sending
    waitornot2              jmp     #A6276_loop1            ' if waittime was given, go to calc next counter
    nowait2                 jmp     #A6276_loop2
                            
    ppointer      long      0
    parameter     long      0
    time          long      0
    waittime      long      0
    zero          long      0            
    highword      long      $ffff_0000
    outpin        long      $0000_0001
    clkpin        long      $0000_0001
    temp          long      0
    A6276_end     long      0
    
    

    The functionality currently is to get the startup-parameters, which are all passed in one long variable. The high-word of the long is the wait-time. If a value other than 0 is given there, the driver waits after each unsucessful check of the parameter. A wait will decrease power consumption. If the parameter is 0, the startup routine moves some code to skip waiting.

    In the two bytes of the low-word the pins have to be passed.

    For synchronization the parameter is set to zero as soon as the driver is done with the work. If you have other things to do there is of course no need to sync.

    The word to be send has to be passed in the high word. As the value can be zero and zero means 'nothing to do' for the driver, at least one bit of the low word should be set to start transmission.

    Try to check out how this code works. Maybe you can try to do the rest by yourself. I'll continue tomorrow.

    Bye

    Post Edited (MagIO2) : 4/11/2009 10:58:54 PM GMT
  • gwilli3gwilli3 Posts: 3
    edited 2009-04-14 18:13
    Thanks a lot Mag,

    I have deleted the extra latching and unlatching each loop iteration , but I am still having the same problem. I am trying to decipher the code that you have here, but I do not completely understand all of it. I am having problems with the PASM. The manual is not very demonstrative in its explanations of Pasm code. I have a few questions as well that may give you a better idea:

    1) I see that you have the _xinfreq at 10_000_000. Is this from the A6276?

    2) I do not know how to invoke PASM coding from another method or from another object. I know how to invoke methods from other or the same object in Spin. Can you tell me the difference.

    3) I think that I am having problems somewhere in my data manipulation between sending serial data to the A6276. I can get the LEDs to blink at rates faster than the eye can detect when I just send some 1's and then all zeros in a repeating loop with minimal delay. But, when I try to manipualte the bits before sending them out, there seems to be some problem that causes ther to be a minimum wait time between iterations. Is spin too slow even at 80MHz? Do I need to do all the manipulations AND the sending of the data to the A6276 in PASM instead?

    Thanks a lot.

    --Glenn
  • StefanL38StefanL38 Posts: 2,292
    edited 2009-04-14 19:27
    Hello Glenn,

    a cog can run PASM OR SPIN.

    it is NOT possible to mix PASM and SPIN on ONE cog
    The reason is if you execute SPIN the SPIN-interpreter occupies the COMPLETE RAM of the cog (2kB).
    SPIN-bytecode is stored in the HUB-RAM (32kB) The spin-interpreter fetches bytecode from HUB-RAM and
    is interpreting it running PASM-interpreter code

    PASM has to be in COG-RAM for execution

    PASM is low-level programming compared to SPIN
    The commands that you have are much simpler than a
    "repeat X from 0 to 255"
    or
    "IF Var1 > 10) and (Var2 == 70) or (Var3 < 10)"

    To see if it could be done in SPIN it would be interesting how many bits you have to shift-out as maximum
    and if some calculations have to be done
    maybe it is possible to do the calculations in one cog and the shifting-out in a second cog or a second method

    best regards

    Stefan
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-14 20:05
    1) _XINFREQ is set to 10_000_000 because I have the propeller running with a 10MHz crystal. That's why I have to set the _CLKMODE to 8x . 8x10_000_000 = 80_000_000 which is the speed that the propeller is running internally. Most other setups have a 5MHz crystal. With _CLKMODE set to 16x this is also 80MHz internal speed.

    2) cognew is starting a new COG with the SPIN or PASM code you hand as first parameter. In SPIN you simply use the name of the SPIN-method. In PASM you pass the adress of the code using the @ as adress operator. But the PASM code I gave you is only called during initialisation at startup-time. From this time on, the PASM code is running endlessly. You communicate with it by using the A6276_par variable. What it really does still has to be defined in the ' this part is missing currently' -part.
    So the difference is that if you are using a different COG for shifting out the bits to the A6276, your main program can go on without waiting and do something else. The A6276 code running in that COG of course can be in SPIN as well, but PASM will do it as fast as possible.

    3) In your original post you said you want to fade colors. The A6276 will drive all LED's with a constant current, so you have to use PWM for fading. For a good PWM you will need a minimum speed. For a 8 bit PWM at a refresh rate of 40Hz and with independent PWM values per LED you need to send 256x40x16 bits per second (163840 bits/second). And a 8 bit PWM is not what you would call 'full color fading'. The problem is the eye, which does not recognizes the brightnes linear to the light emitted. So the effective number of different brightness values will be much smaller than 256.
Sign In or Register to comment.