Shop OBEX P1 Docs P2 Docs Learn Events
Questions you think are too stupid to ask... - Page 2 — Parallax Forums

Questions you think are too stupid to ask...

2

Comments

  • pedwardpedward Posts: 1,642
    edited 2012-03-13 17:03
    cavelamb wrote: »
    And if your main loop doesn't complete in time to poll the "interrupt" pin???

    The main loop handles non time sensitive processing, it doesn't "poll" the interrupt. It post processes data from the interrupt.

    In my case the main loop was responsible for making the data useful to another machine and transmitting it. The UART could only do 57600, so the main loop was pretty much I/O bound. It would pull data from a few variables, put it in a structure, then transmit the structure. Once per second it would send a sync packet with information that is only useful once a second. I also bit packed the 10bit ADC data into 16 bit words IIRC, packing 80 bits into 5 words.

    My point is that with an interrupt driven architecture, you have to make a lot of educated guesses, compromises, or rewrite large portions of code if either of those methods don't work.

    With the prop, you simply write in a black box, without concern for any outside processes, it greatly simplifies real-time processing.
  • photomankcphotomankc Posts: 943
    edited 2012-03-13 22:55
    One way I save cores is to use counters where ever I can to monitor events that need me to do something right now but do need me to notice they happened. I have some light sensors I made with a 555 timer. Rather than eat up a core to sit and sample the frequency over and over I just hook that into the A and B timers and boom I get my count and as long as I know the frequency I check them at I can come up with the frequency of this sample. I implemented a seconds timer that way in my RTC object so again I can time events out to 4 billion seconds using the 1Hz output but don't eat a core watching that pin toggle.
  • average joeaverage joe Posts: 795
    edited 2012-03-13 23:32
    My dumb question. Is there any way to detect a reboot without wasting a pin? What I'm referring to is this. On reset, the prop loads it's program from eeprom. I want to share these pins using a 4066. I can use the reset pin to detect a hardware reset, but what I'm looking for is a way to detect a software reset. Any ideas?
  • DavidZemonDavidZemon Posts: 2,973
    edited 2012-10-25 22:14
    I've read through the the counter app note. Fantastic reading. And for the most part, it all makes sense to me. The diagram is simple enough and NCO/PWM mode looks extremely simple. So why do I feel like a retard? Here's my code that isn't working. It's being run on the Parallax QuickStart:
    CON
      _CLKMODE = XTAL1 + PLL16X
      _CLKFREQ = 80_000_000
    
    
    PUB Main | Apin, Bpin
    
    
      Apin := 16
      Bpin := 0
      dira[Apin] := 1
    
    
      repeat 8
        !outa[Apin]
        waitcnt(_CLKFREQ / 8 + cnt)
      
      frqa := 54 'Set FRQA so PHSA[31] toggles every second
      ctra := long[%00100 << 26 + Bpin << 9 + Apin] 'Establish mode and APIN (BPIN is ignored)
      repeat
    
  • kuronekokuroneko Posts: 3,623
    edited 2012-10-25 22:21
    ctra := long/COLOR][COLOR="#FFA500"]%00100 << 26 + Bpin << 9 + Apin[/COLOR][COLOR="#FF0000" 'Establish mode and APIN (BPIN is ignored)
    Get rid of the red part, you're accessing hub memory with that ... you really only want the expression.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2012-10-25 22:23
    That worked! Thanks. Can you explain what exactly was "confusing hub ram?
  • kuronekokuroneko Posts: 3,623
    edited 2012-10-25 22:29
    Can you explain what exactly was "confusing hub ram?
    You lost me there. long[addr] reads a long from hub address addr & -4. In your case - with Bpin being 0 and the counter mode being out of range for addressing - you end up reading from address 16 (Apin) which is $00020040. Assigning that to counter A leaves you with a disabled counter. HTH

    IOW, reg := expr and reg := long[expr] are two different things.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2012-10-25 22:38
    Oh! Coming from C/C++, I assume long[] was like type casting. Thanks.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2012-10-25 23:18
    The counter's LED on pin 16 doesn't fire. I can get the counter to work in spin, but not PASM.
    {{ blinky_asm.spin
       Project: Learning
       Author: David Zemon
       Purpose: Blink two LEDs, one with the built-in counter,
                another with an asembly loop }}
    
    
    CON
      _clkmode = xtal1 + PLL16X      
      _CLKFREQ = 80_000_000
      _ToggleLED = 18 
      _Apin = 16
      _Bpin = 17
      
    PUB Start(parameterAdr) : okay
      okay := cognew(@CtrToggle, parameterAdr)
    
    
    DAT
                  ORG $0
    CtrToggle     mov dira, ToggleLED               ' Set output pins
    
    
                  { Setup for counter module }
                  or dira, A_GPIO
                  or dira, B_GPIO
                  mov frqa, Frequency
                  movs ctra, Apin
                  movd ctra, Bpin    
                  movi ctra, CtrMode  
                  
                  { Infinite loop toggling LED w/ software }
    :Toggle       mov Time, cnt
                  add Time, qrtr_second
    :Loop         xor outa, ToggleLED
                  waitcnt Time, qrtr_second
                  jmp #:Loop
    
    
    { Constants for hardcoding a blinking LED }
    ToggleLED     long      |< _ToggleLED
    half_second   long      _CLKFREQ/2/2            ' Length of blink
    qrtr_second   long      _CLKFREQ/4/2
    tenth_second  long      _CLKFREQ/10/2
    custom_delay  long      15
    Time          res       1    
    
    
    { Constants for using the counter to blink an LED }
    CtrMode       long      100_000                         
    Frequency     long      54      
    Apin          long      _Apin        
    Bpin          long      _Bpin        
    A_GPIO        long      |< _Apin
    B_GPIO        long      |< _Bpin
    
  • kuronekokuroneko Posts: 3,623
    edited 2012-10-25 23:27
    If you use res (undefined variables) then any of them (in general) has to come after any long (defined variables/constants). So just move Time to the end of the code block.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2012-10-26 00:05
    What.
    the.
    ....

    I've been stuck on this problem since April. Moving that one line fixed it. Thank you again for the help and I guess now I know for next time... wish I'd posted that code a long time ago.
  • kuronekokuroneko Posts: 3,623
    edited 2012-10-26 00:12
    Check the manual (rev 1.2, page 339). It has more details than my (usually) minimal answers :)
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2012-10-26 03:41
    Still reading through that AN001. Lots of big words (or small acronyms lol) that I haven't seen before and am looking up. But, overall very cool.

    Here's another question:
    Why didn't Parallax implement interrupts, watchdog timer, or extra peripherals?
    I understand it's nice that we have 8 cores to utilize, and we can still do a lot without interrupts... but we could do SO MUCH more if we had them. It seems silly that I need to use an entire cog to poll a pin and wait on input to do something while a second cog runs foreground tasks. This is something that can easily be done with a single cog if it had interrupts, allowing the other 7 cogs to do other useful tasks.
    WDT: self explanitory. Why no WDT?
    Extra peripherals: As a relative newbie to the uC world, I'm always looking at specs for other uC that I hear about. It seems like every other chip out there has many many more peripherals on it than the prop (with the exclusion of the timers & video generators). Why no ADCs? No built-in serial communication modules? No built-in ____? Again, this chip would become even more versatile if it had these.

    I know the prop2 prelim says it will have ADCs. I'm very grateful for that. But still not adding the rest of it?

    Are there any other uC out there that have all of these? I know ARM makes some multi-core processors, but IIRC they are in the $50 range.

    Thanks,
    David

    There is another document ===> The Propeller counters, a dummies guide by Graham Stabler. Try to Google by this title and look for other items he may have written.

    WDT? Would one have been enough or do you want 8? I can't really say why, but I suspect that since there were no interrupts, that excluded the WDT feature as well. One can live without one.

    Peripherals? Well the Propeller was the first of its kind and usually such items are rather bare bones. The Propeller II is going to have ADC and DAC. Other peripherals can easily be replicated in software. This keeps the inventory of chips down and allow more resources going into development rather than selling overstocked silicon.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2012-10-26 07:27
    I'm sorry.... I've been too busy watching your avatar for the last 20 minutes to read anything :P
  • DavidZemonDavidZemon Posts: 2,973
    edited 2013-01-23 23:35
    In the assembly section, i've commented out 6 debugging lines (the lines i'm referring to all have the apostrophe as the first character). When those lines remain as comments, my assembly routine dies. Or goes into an infinite loop. Or something. I don't know - that's why I inserted the debugging lines.

    It's a heisenbug. When I uncomment those six lines, the bug is gone, and it runs perfectly. Does anyone have any idea why? Or better yet, more generally, how do YOU go about debugging heisenbugs??? This is my first one.

    The code is the beginning of a tachometer.

    I am also still new to prop code. If you have formatting suggestions or you think my code is hard to read, I'd like to hear it.
    {{ Tachometer.spin  Author: David Zemon
      Date Created: 10/9/11
      Date Modified: 1/24/13
    
    
      Write engine RPM to 16x2 character LCD
    }}
    
    
    CON
      _CLKMODE      = XTAL1 + PLL16X
      _CLKFREQ      = 80_000_000
    
      _TACH_PIN     = 18            ' Which pin is connected
    
      RS            = 0
      RW            = 1
      E             = 2
      DB0           = 8
      DB7           = 15
    
      TEST_OUT      = 17
      TEST_OUT_2    = 16
    
      TICKS_PER_REV = 2             ' Number of rising edges on tachometer signal per revolution
    
      ARRAY_SIZE    = 64           ' Number of ticks to count in the average
      LOG_SIZE      = 6             ' LOG_2(DEFAULT_AVG)
    
    
    OBJ
      lcd   :       "LCD_16x2_8Bit_spin"
    
    
    Var
      long divisor
      long tachCount
    
    
    PUB MAIN | asmCog, rpm
      ' 0123456789abcdef
    
    
      asmCog := cognew(@entry, @tachCount)
      lcd.start(RS, RW, E, DB0, DB7)
      if (-1 == asmCog)
        lcd.str(string("Error. Unable to"))
        lcd.move(1, 2)
        lcd.str(string("start PASM cog."))
      else
        lcd.str(string("Tachometer"))
        lcd.move(1, 2)
        lcd.str(string("initializing..."))
    
    
      lcd.clear
      lcd.str(string("RPM: "))
      tachCount := 0
    
    
      repeat
        waitcnt(CLKFREQ/4 + cnt)
        rpm := tachCount
        rpm := calculateRPM(rpm)
        'if (99999 < rpm) or (0 > rpm)
        '  rpm := 0
        lcd.move(6, 1)
        lcd.str(string("     "))
        lcd.move(6, 1)
        lcd.dec(rpm)
    
    
    PUB calculateRPM(tickCount) : rpm
      rpm := CLKFREQ / tickCount
      rpm *= TICKS_PER_REV * 15
    
    
    DAT
    
    
                            ORG 0
    entry                   waitpeq tachPin, tachPin        ' Ignore first period
                            waitpeq zero, tachPin
                            mov wPtr, @array                ' Set pointer to first address in the array
                            mov sum, #0
                            mov old, cnt                    ' Initialize old cnt value
                            sub zero, #1 wc, nr             ' Set the C flag
                            or dira, testLED
    '                        or dira, testLED2
    
    
    
    
                            {{ Wait for input to go high, store the time delay }}
    loop                    waitpeq tachPin, tachPin        ' Wait until pin goes high
                            mov new, cnt                    ' Save system count register
                            waitpeq zero, tachPin           ' Wait until pin goes low again
                            mov count, new
                            sub count, old                  ' Calculate time (in osc tick) between ticks
                            mov old, new
    
    
                            {{ Subtract the old value, add the new one (only if array full) }}
                  if_nc     movs decArray, wPtr
                            add sum, count
    decArray      if_nc     sub sum, 0-0
    
    
                            {{ Store a new value into the array }}
                            movd storeCnt, wPtr             ' Store the current pointer address into the move instruction
                            add offset, #1                  ' Increment the pointer
                            and offset, #(LOG_SIZE - 1)   ' Mod wPtr with ARRAY_SIZE
                            mov wPtr, @array
                            add wPtr, offset
    storeCnt                mov 0-0, count                  ' Store the count into the array
    
    
                            xor outa, testLED
    
    
                            {{ Add more values to the array if not full }}
    loopCnt       if_c      add loops, #1
                  if_c      cmp loops, #ARRAY_SIZE wc
    '              if_c      xor outa, testLED2
                  if_c      jmp #loop
    
    
                            {{ Turn off testLED2 }}
    '                        xor testLED2, invert
    '                        and dira, testLED2
    
    
                            mov temp, sum
                            shr temp, #LOG_SIZE
                            wrlong count, par               ' Write to HUB RAM
                            jmp #loop
    
    
    tachPin                 long    |< _TACH_PIN
    testLED                 long    |< TEST_OUT
    'testLED2                long    |< TEST_OUT_2
    zero                    long    0
    loops                   long    0
    'invert                  long    -1
    
    
    sum                     res     1
    old                     res     1
    new                     res     1
    count                   res     1
    array                   res     ARRAY_SIZE              ' Rolling sum array
    offset                  res     1                       ' Pointer offset
    wPtr                    res     1                       ' Write pointer to array
    temp                    res     1
    
    
    
  • kuronekokuroneko Posts: 3,623
    edited 2013-01-24 00:54
    It's a heisenbug. ...
    mov wPtr, @array isn't going to do what you think it does. Try mov wPtr, #array instead.

    And this only works for powers of two. LOG_SIZE - not being one - gives you any number of side effects.
    and offset, #(LOG_SIZE - 1)   ' Mod wPtr with ARRAY_SIZE
    
    Once you reach nc condition you'll stay there. Probably not what you want. Can you elaborate?
  • MagIO2MagIO2 Posts: 2,243
    edited 2013-01-24 01:16
    Hmmm ... interesting!

    This is a thought-experiment, as I'm sitting at work and don't have a prop at hand.
    I never tried one thing before:
      ...
      mov        hubaddress, # @array
      rd/wrlong hubaddress, array
      ...
    array           long  0
    hubaddress  res   1
    
    or the functional equivalent, but the assignment to hubaddress is done during compile-time
      ...
      rd/wrlong hubaddress, array
      ...
    array           long  0
    hubaddress  long @array
    

    From my point of view this should be possible, as array is placed in a DAT section (thus it is unique over all object instances) and exists in HUB-RAM and in COG-RAM.
    Where array is located is known during compile-time for both, COG-RAM and HUB-RAM.
  • Mike GreenMike Green Posts: 23,101
    edited 2013-01-24 06:48
    Your first code fragment won't do what you expect. Remember that the source field is only 9 bits and @array (the hub address of array) may be larger than that. In any event, RD/WRLONG works backwards from other instructions in that the destination field has the cog address of the data while the source field has the cog address of the hub address so you need "RDLONG array,hubaddress".

    The addresses of the cog array and the hub array may be known at compile time, but they're still in separate address spaces. The hub array is copied to the cog array only once ... when the cog is initialized by COGNEW or COGINIT. From that point onwards, the two copies of the array are separate. You can always keep the hub copy updated by explicitly writing any changes from cog to hub (if the cog is the only one changing the hub copy). It's a mess if other cogs can also change the hub copy. At that point, you should just keep a hub copy and access that directly.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2013-01-24 09:44
    A prof just said that an oscillator must have a small capacitor on each side of the crystal to work. Without the capacitance, there is no C in the RLC circuit to make an oscillation. I've never capacitors on my crystals on breadboards, yet my circuits work just fine (for basic stuff like the above example and blinky code). Why is this? Does the chip have built-in capacitors on those pins?

    (I'll try the above suggestions for my code when I get home)
  • Mike GreenMike Green Posts: 23,101
    edited 2013-01-24 10:16
    Yes, the oscillator on the chip has small capacitors built into it. Some of this capacitance is inherent to the CMOS gates that make up the oscillator. Other parts of this capacitance are switchable in and out of the circuit since some crystals require more or less capacitance to oscillate. Some chip oscillators don't provide enough capacitance for many crystals and their datasheets show how much has to be added externally. The printed circuit traces also add some capacitance that has to be taken into effect. Some real-time-clock chips' datasheets show a specific layout of the traces between the crystal and the chip that needs to be followed for best accuracy and minimal power consumption.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2013-01-24 22:20
    Is memory in cog RAM byte addressed or long addressed? I realized I'm only incrementing my offset by 1, but I want to be incrementing to the next long address.

    I changed @array to #array and that fixed that bug at least. I also fixed the "mod offset" brain fart.

    Battery died on my function generator so I think that's the world telling me to get some sleep. I'll test this again tomorrow.
  • BeanBean Posts: 8,129
    edited 2013-01-25 05:05
    cog ram is long addressed, hub ram is byte addressed. This is one thing that confused me in the beginning too.

    Bean
  • doggiedocdoggiedoc Posts: 2,241
    edited 2013-01-25 09:33
    Bean wrote: »
    cog ram is long addressed, hub ram is byte addressed. This is one thing that confused me in the beginning too.

    Bean
    I will tuck that nugget of knowledge away until I understand it better. Could you cite some examples where that might be a gotcha?

    Thanks!

    Paul
  • Mike GreenMike Green Posts: 23,101
    edited 2013-01-25 10:13
    Good example is that, if you're copying longs between hub and cog memory (like from a parameter list or control block, you have to increment the cog address by 1 and the hub address by 4.
  • doggiedocdoggiedoc Posts: 2,241
    edited 2013-01-25 14:44
    Thanks Mike. I think it's time I reviewed hub/cog ram relationship. My memory (sic) appears to be fuzzy. I've got the manual .pdf pulled up now.

    Thanks again for steering me in the right direction!
  • DavidZemonDavidZemon Posts: 2,973
    edited 2013-03-10 00:55
    Having trouble understanding the SPI Assembly module: http://obex.parallax.com/objects/431/. I'm attempting to port it to C/GAS and the methods SHIFTOUT and SHIFTIN seem broken to me. They contain numerous unused parameters, which I can only guess are there for compatibility with the Spin version of the driver. However, SHIFTIN sets the value of a local variable, "Flag" to 1, and then waits for that variable to be cleared... but the address of Flag is never passed to another cog, it is never referenced anywhere else... I have no idea what's happening.
  • kuronekokuroneko Posts: 3,623
    edited 2013-03-10 01:33
    The call has the address of Dpin passed in. Flag is the same as Dpin[5].
    PUB SHIFTIN(Dpin, Cpin, Mode, Bits)|Value,Flag          ''If SHIFTIN is called with 'Bits' set to Zero, then the COG will shut
                                                            ''down.  Another way to shut the COG down is to call 'stop' from Spin.
    
        Flag := 1                                           ''Set Flag                                           
        setcommand(_SHIFTIN, [COLOR="#FF0000"]@Dpin[/COLOR])
    ...
    PRI setcommand(cmd, [COLOR="#FF0000"]argptr[/COLOR])
        command := cmd << 16 + [COLOR="#FF0000"]argptr[/COLOR]                       ''write command and pointer
        repeat while command                                ''wait for command to be cleared, signifying receipt
    ...
    loop          rdlong  [COLOR="#FF0000"]t1[/COLOR],par          wz                ''wait for command
    ...
                  mov     [COLOR="#FF0000"]address[/COLOR],t1                        ''preserve address location for passing
    ...
    Update_SHIFTIN
                  mov     [COLOR="#FF0000"]t1[/COLOR],             address           ''     Write data back to Arg4
                  add     [COLOR="#FF0000"]t1[/COLOR],             #16               ''          Arg0 = #0 ; Arg1 = #4 ; Arg2 = #8 ; Arg3 = #12 ; Arg4 = #16
                  wrlong  t3,             t1
                  add     [COLOR="#FF0000"]t1[/COLOR],             #4                ''          Point t1 to Flag ... Arg4 + #4
                  wrlong  zero,           t1                ''          Clear Flag ... indicates SHIFTIN data is ready
    
    This may also be of interest [post=1061378]SPI_Asm vs. SPI_Spin[/post].
  • DavidZemonDavidZemon Posts: 2,973
    edited 2013-03-10 12:59
    Took me a minute to understand this... but are you saying that Beau Schwabe has hardcoded this thing to be super-optimized for these parameters written in exactly this order for this specific compiler??? Using address offsets to access parameters without ever passing values or addresses... that's crazy.

    Also... sounds like it isn't directly portable to C as I believe GCC pass parameters very differently - especially when there are more than 3. Do you think I'd be better off re-writing the assembly in SPI_Asm or porting SPI_Spin instead? I don't have a "desired clock rate" because I don't know what my requirements are, but I am running a real-time-system and gathering critical information through SPI.
  • kuronekokuroneko Posts: 3,623
    edited 2013-03-10 17:03
    Took me a minute to understand this... but are you saying that Beau Schwabe has hardcoded this thing to be super-optimized for these parameters written in exactly this order for this specific compiler??? Using address offsets to access parameters without ever passing values or addresses... that's crazy.
    That's the way parameters are passed to a cog. IOW one base address (you only have par availableA) and elements down the line are accessed by base+offset. Usually a block of consecutive VARiables is used. Applying this to parameters and locals only works for SPIN as the defined order is result/parameters/locals (i.e. this wouldn't necessarily work for other languages).

    How would you have done the parameter access?
    Do you think I'd be better off re-writing the assembly in SPI_Asm or porting SPI_Spin instead? I don't have a "desired clock rate" because I don't know what my requirements are, but I am running a real-time-system and gathering critical information through SPI.
    Up to you really, how fast does it have to be? As for parameters, create a block of consecutive variables (e.g. a structure) then pass its base address to the cog.


    A in this specific example par isn't used for the parameter array, its address is part of the command but the principle is the same
  • lardomlardom Posts: 1,659
    edited 2013-03-11 11:12
    JonnyMac wrote: »
    No. The outputs from each cog are OR'd together before going to the pin. What this means, though, is that if one cog makes the pin high (1), it doesn't matter what any other cog is doing, that pin will be high.
    That info might work for me. I think it will allow me to stay with an eight-bit pattern for my two steppers instead of switching to a four-bit pattern whenever I want my steppers to operate differentially.
    The motors, which are in separate cogs, call an object in a 3rd cog which has a repeat loop that tests 'combined conditions'. I think I have a contention problem and I've been working on it for at least a week. (My program works perfectly as long as I write the values myself as opposed to return values from a Ping.)
Sign In or Register to comment.