Shop OBEX P1 Docs P2 Docs Learn Events
Is there a limit to local longs? Strange behavior when I initialize some local longs. - Page 4 — Parallax Forums

Is there a limit to local longs? Strange behavior when I initialize some local longs.

124»

Comments

  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-25 10:07
    I also took the opportunity to get some cam sensor readings as well, the cam sensor uses a 3 trigger wheel with teeth offset, I do not have the exact degree spacing, but I believe they are spaced approximately at 100degrees, 100 degrees and 145 degrees with about 5 degrees of width per trigger wheel. This is not exact or measured yet, but it reflects the large "gap" between the 3rd trigger wheel and the camshaft rotating around completing a full revolution before it passes the 1st trigger wheel by the sensor again.

    These files I tried to name appropriately also
    3TrigCamSensor(idle)ScopeAt20mS.jpg
    3TrigCamSensor(5000rpm)ScopeAt5mS.jpg
    3TrigCamSensor(idle)ScopeAt50mS.jpg
    3TrigCamSensor(idle)ScopeAt100mS.jpg
    3TrigCamSensor(5000rpm)ScopeAt10mS.jpg
    3TrigCamSensor(5000rpm)ScopeAt20mS.jpg

    idle is again approximately 900rpm and I can get different rpm and time division readings if you would like to see those.

    When I come home tonight I am going to try and write some code reflecting the things you've said in your last post.
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-03-25 14:26
    Nice images!

    But what I don't understand ... why don't you try to get the most information out of it? If you compare the 5000/1ms crank reading with the 5000/20ms reading, the first one is much better, right? And with a bigger sample rate it would be even better than that. But OK, most interesting so far is that it's a symetrical alternating voltage somewhere close to 5V @ 700RPM and 10V @ 5000RPM.

    Just did some calculations and it looks like the idle RPM is more in 700 range.

    The prop scope has 2 channels, right? Why didn't you measure the crank and the cam at once? You'd then see how both signals are related. ;o)

    Did you already tell what all this efford is good for? What's your goal? Just out of curiosity .. and if you are willing/allowed to share this information.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-25 17:48
    Hi,

    With your question, do you mean why did I not go to the point where a single sine wave encompassed the entire prop scope screen? I did a couple of different samples because I wanted to show the bridge/gap in at least one of them since this signal is different than your average signal, in that it physically disappears after 34 cycles for 2 of the cycles. I can do a few different samples or overlay them with the second channel if you'd like, just let me know the scenarios and I'll grab them. I should have overlayed them, I just didn't think about it :D . 700rpm may be correct, the factory tachometer isn't known for its accuracy and I was looking at it from the passenger seats angle as well.

    My ultimate goal is to be able to adjust the cam angle in relation to the crank angle, which the factory ecu currently does right now. It has an oil pressure controlled gear, of which the oil pressure is modulated by a solenoid. It can change the cam angle up to 30 degrees before or after the "0 angle" location that it would be stationary at, if the auto manufacturer had decided to not make it adjustable.

    If I can get that far, there are then a few other things I would like to do in addition to that.


    I have gotten the bulk write to partially work, and I'm not 100% sure why. Some of the values are working and some are not, maybe you can explain what I didn't do correctly (code is attached)?
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-27 12:03
    Hello,

    I'm still struggling with the bulk write, I drew out a chart with cells on how cog ram maps to hub ram, to try and help myself visualize this. By the way, can I tell PASM to write to the hex address itself and not a pointer to an address?

    So the longs in hub ram map to par, par + 1, par + 2, par + 3 etc, (assuming it has been coded that way) . If par was @1B, then cog ram would map to $1B - $1E? and par + 1 would map to $1F - $22, par + 2 would map to $23 - $26 etc ... is this correct? Do the numerical values at the bottom, where the variables for PASM are instantiated, represent an allocation number of bytes? Is that why they are ordered as 4, 8, 12, 16, 20, 24, 28, 32? I think this will be easier for me to understand, if I can picture in my head how the values are mapped and how those numerical columns affect things.

    If so, I'm not sure why my code is not working properly, basically it is supposed to follow the logic of

    cog ram long, write to par
    cog ram long + 1, write to par + 4
    cog ram long + 2, write to par + 8

    Is this logic at least correct?


    Here is the variable value definition section:
                            org     0
    
    frcntr                  mov     tmp1, par                       ' * start of structure, passes an address to the value par represents and copies that address to tmp1
                            rdlong  tmp2, tmp1                      ' * get beginning variable address location, copy into tmp2
    
                            mov     ctra, POS_DETECT                ' * ctra measures high phase
                            add     ctra, tmp2                      ' * add tmp2 to ctra and write to ctra
                            mov     frqa, #1                        ' * move frqa 1 byte?
                            
                            mov     ctrb, NEG_DETECT                ' * ctrb measures low phase
                            add     ctrb, tmp2                      ' * add tmp2 to ctrb and write to ctrb
                            mov     frqb, #1                        ' * move frqb 1 byte? 
                            
                            mov     mask, #1                        ' * create pin mask
                            shl     mask, tmp2                      ' * shift left the mask, number of bytes of tmp2? 
    
                            ' save addresses of hub storage
                            add     cyclepntr, tmp1                  ' * adds value of cyclpntr and tmp1 and writes that to cyclepntr
                            add     toothcntptr, tmp1                ' * adds value of toothcntptr and tmp1 and writes that to cyclepntr
                            add     averageptr, tmp1                 ' * adds value of averageptr and tmp1 and writes that to cyclepntr
                            add     maxptr, tmp1                     ' * adds value of maxptr and tmp1 and writes that to cyclepntr
                            add     minptr, tmp1                     ' * adds value of minptr and tmp1 and writes that to cyclepntr
    '                        add     averageptr, tmp1                 ' * adds value of averageptr and tmp1 and writes that to cyclepntr
                            add     toothCntMaxptr, tmp1             ' * adds value of minptr and tmp1 and writes that to cyclepntr
                            add     gapCntAsmptr, tmp1
                            add     gapCntAsmPeakptr, tmp1
                            
                            mov     timeStamp, cnt   
    

    The method I'm trying to get working:
                            mov     loopCount, #BULK_NUM_OF_LONGS
                            mov     varLongCount, #0
    wrlongLoop
                            wrlong  cycles+varLongCount, cyclepntr  ' * write cycles to cyclepntr
                            add     wrlongLoop, add1toDest  ' * add 1 to the wrlongLoop value for the djnz
                            add     cyclepntr, #4 ' * add 4 bytes since we are referring to a byte addressed hub ram value, goes to value in hub ram defined after cyclepntr
                            add     varLongCount, #1   
                            djnz    loopCount, #wrlongLoop  
                            ' Cleanup below
                            mov     wrlongLoop, resetWrlong
                            sub     cyclepntr, #(BULK_NUM_OF_LONGS<<2)
    
    resetWrlong             wrlong cycles, cyclepntr
    
    

    The variable name assignment:
    ' --------------------------------------------------------------------------------------------------
    
    POS_DETECT              long    %01000 << 26 
    NEG_DETECT              long    %01100 << 26
    
    cyclepntr               long    4
    toothcntptr             long    8
    averageptr              long    12
    maxptr                  long    16
    minptr                  long    20
    toothCntMaxPtr          long    24
    gapCntAsmptr            long    28
    gapCntAsmPeakptr        long    32  
    
    maxc                    long    0
    minc                    long    -1
    
    tooth                   long    0
    toothCntMaxAsm          long    0
    gapCntAsm               long    0
    gapCntAsmPeak           long    0
    timeStamp               long    0
    delta                   long    80_000_000
    tempCnt                 long    0
    
    loopCount               long    0
    varLongCount            long    0
    
    database                long    0
    averagex                
    avgcnt                  long    8
    dontcount               long    13400 
    add1toDest              long    %1_000000000
    
    
    tmp1                    res     1
    tmp2                    res     1
    
    mask                    res     1                               ' mask for frequency input pin
    cycles                  res     1                               ' cycles in input period
    
    
                            fit     492
    
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-03-27 13:52
    Ok ... let's explain par ...
    par inside of a COG is like a readonly variable which contains the content of the second parameter of the COGNEW:
    cognew( @mypasm, @first_var )
    is like
    par := @first_var & %11111111_11111111_11111111_11111100

    This is why you'll never find a $1b here. Remember, the address has to be long alligned!

    par is a pointer to HUB-RAM in our case pointing to the first variable. And even if this address has to be long alligned, it's still a HUB-RAM address which is a byte-address. So, if the first variable is a long you get to the address of the next variable by adding 4 (par + 4). The next long after that has address par + 8 ... and so on.
    If you'd then have a number of words in the variable list, you'd only add 2 from one to the next word.

    4, 8, 12, 16, 20, 24, 28, 32 are simply the offsets related to tmp1, which has the same value as par. The initialization at the end plus all the "add x, tmp1" instructions work like this:
    cyclepntr := par + cyclepntr which is par + 4
    toothcntptr := par + toothcntptr -> par + 8
    ...

    The logic of the loop is correct!

    The problems you have are:
    1. wrlong cycles+varLongCount, cyclepntr ' * write cycles to cyclepntr
    does not work as you expect it to work AND
    2. you did not understand how to go forward to the next COG-RAM location in the wrlong

    About 1.:
    cycle is a label which is converted to a COG-RAM address by the compiler. varLongCount is a label which is converted to a COG-RAM address as well. cycle + varLongCount simply adds those addresses. What you expected was use the cycle address an add the content of varLongCount.

    About 2.:
    In PASM you have to use self-modifying code to forward addresses used by an instruction. If you have a look at an instruction on bit-level things get clearer:
    iiiiii_czri_cccc_ddddddddd_sssssssss
    i is the instruction opcode iteslf, so you find different values here for mov, sub, add, wrlong .....
    czri are the flags that tell the COG whether the carry flag, the zero flag shall be written (WC, WZ), whether the instruction shall be readonly (WR, NR) and whether the source bits are direct addresses ( # ).
    cccc are the conditional execution flags ( IF_Z, IF_NZ, IF_B ..... )
    ddddddddd is the destination address - for example cycles -address would be placed here.
    sssssssss is the source address

    So, if you want to increment the destination-address you actually have to add
    000000_0000_0000_000000001_000000000
    to the instruction itself. That's why I gave you the code
    add wrlongLoop, add1toDest

    It should have been fully functional - no need to add the varLongCount stuff ;o) The only thing missing is a jump back to a meaningfull loop after the cleanup-code and before the definition of resetWrlong.
    The cleanup restores the original instruction of wrlongLoop, so that dest points to cycles again and resets the cyclepntr.

    Hope that helped!
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-03-27 13:56
    And cycles is not in a row with all the other variables you want to write back. According to the current loop it should be the first of all the long variables in COG-RAM and not a res at the end!
  • kuronekokuroneko Posts: 3,623
    edited 2012-03-27 17:11
    MagIO2 wrote: »
    par inside of a COG is like a readonly variable which contains the content of the second parameter of the COGNEW:
    cognew( @mypasm, @first_var )
    is like
    par := @first_var & %00000000_00000000_11111111_11111100
    FTFY
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-27 18:14
    Hey, thanks for the reply.

    I think I have noticed something I didn't realize before, cogram can technically only store 9 bits of data if it were a single long? And the remaining 23 bits in the register are used for other various functions? If this is correct, why is this?

    I understand the value of having the hubram values in the proper order, and the corresponding cogram values also being in order but I'm still not able to make this code work completely. I'm not sure what I'm doing wrong but I'm going to try and test with it in the car rather than spend more time trying to figure out why I can't get the bulk write loop to work. Based on what you've told me, my loop is correct now and my order of longs is correct now, so it is something else that is hosing delta t, peak cnt and min. They all work when I have the separate writes though.

    I just noticed you can compile and look at the memory addresses in the prop IDE, strangely enough averagex does not have a hex address? Maybe this is my problem? I also thought it was strange that min was set to -1?
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-03-27 23:23
    " If this is correct, why is this?"
    Because you want to have all informations needed to execute an instruction to fit into 32 bit. So, if you want to use direct data the only place to store it is the source address and setting the I-flag (immediate)accordingly. If you'd allow immediates with any size lager than 9 bit you'd have to occupy the next long anyway, so in terms of COG-RAM usage there is really no difference in using registered data vs. having longer immediate data. The difference is in the details of the processor internal circuitry needed. If you want to support different size immediate you need flexible instruction lenght which needs more complex logic. In fact this is what CISC processors really have - a lot of addressing modes and flexible instruction sizes...

    "...rather than spend more time trying to figure out why I can't get the bulk write loop to work."
    Fine, as I said bulk write is an optimization in terms of COG-RAM usage and not really needed right now as there is still some COG-RAM left for adding more code. I'll take care of it the next days.

    "... averagex does not have a hex address?"
    averagex and avgcnt use the same address - one memory location, different labels, where each label matches the usage of the memory location. If you have a closer look at the usage of the code, you'll see that in the beginning avgcnt is used and once we have more than 7 samples, the averagex is used. I simply implemented the moving average in a way that it only spits out an average if you have the right number of samples (=8 in this case) in the database. Otherwise you'd need a counter storing the actual number of samples and even more important, you'd really need a division for calculating the right average for the given number of samples. Fix it to 8 you don't need a counter and you can use >>3 to divide the database by 8.

    Additional explaination:
    mov calcavg, nopinstr ' * move calcavg to nopinstr
    This actually replaces the "djnz avgcnt..." with a NOP - an operation which is doing nothing. From there on the averagex-code becomes effective for all following loops and avgcnt is no longer used.

    "I also thought it was strange that min was set to -1?"
    1 = $0000_0001
    -1 = - ($0000_0001) = $FFFF_FFFE + 1 = $FFFF_FFFF which is the biggest number you can store in a long when using unsigned compare
    ( $FFFF_FFFE + 1) is the two's complement of 1 -> http://en.wikipedia.org/wiki/Two%27s_complement

    @kuroneko:
    Thanks for that ... nice to have you as a backup!
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-28 08:09
    Woah, another epiphany! Thank you, that was a beautiful explanation and really helps me in picturing it in my head. I feel like Neo and that I have just seen the Matrix :D

    So each cog has 512 long registers (I know a few of them are special purpose)
    So each cog can work with a maximum of ~500 individual 9 bit values (possibly x 2 with some creative coding) ... if that is true, now I see why you are teaching me early on about register conservation :)
    And somewhere around 9000 bits are available for data source and destination usage within ~500 registers per cog.

    I've heard risc/cisc but I did not have a general understanding of the terms until now after your comments prompted me to find this. http://www-cs-faculty.stanford.edu/~eroberts/courses/soco/projects/2000-01/risc/risccisc/

    I learned 2's compliment a few years ago, I'm going to have to refresh my memory of that with the wiki link.

    Honestly, I think being explained the architecture of the chip really helps you understand PASM and why it does things the way that it does, this has been very beneficial.
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-03-28 11:57
    To be precise, you have 496 longs per COG the rest are special purpose registers. That's why PASM code usually has the

    FIT 496

    statement at the end. This tells the compiler that the code between ORG 0 and FIT should not extend 496 longs. Otherwise the compiler complains.

    Each COG has 496 32bit registers for free usage. It does not care whether you put instructions or data there. If you use instructions you have 9 bits for a destination address and 9 bits for a source address xor a 9 bit immediate value. It's also 9 bit by purpose: the max. value a 9 bit number can store is ???? 511! Starting at 0 this makes 512 different values and make sure that each instruction can address each other register in COG RAM.

    If you have stored some data in COG RAM it's your responsibility what the content means. If you want you can pack 3 x 9bit-values in one long. Or 16 x 2 bit values. It's your code which then has to deal with this kind of data.

    So, if you want to count how many 9 bit values fit into a COG you have to take this into account - even if I don't really understand what this counting is good for ;o)
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-03 18:20
    Hello Mag ... I finally built a small circuit and went out to test the code. : D

    The prop was reading but the calculations were off and I'm trying to figure what I did wrong in my bench preparation/testing? I really thought my bench test scenarios were solid. The following screen capture is what the condition signal looks like on the prop scope and what the pst was reading in relation to that signal at that moment. I'm working on getting the voltage peaks a little closer to 3.3v, but I'm not sure that is affecting my reading of the pulses.

    Any thoughts?

    cranksignalconditioning.jpg

    cranksignalconditioning.jpg
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-04-04 00:10
    I think I already mentioned it somewhere (post #82 ;o) ... the point is, that
    a) Crank.spin creates a symetrical signal, 50% pulse and 50% pause
    b) the CrankSensor works asymetrical
    restart                 waitpne mask, mask                      ' * wait for 0 phase
                            mov     cycles, phsa                    ' * copies phsA to cycles
                            mov     phsa, #0                        ' * clear high phase counter
    
    [color=red]' here we do nothing but wait for the next high[/color]
    
                            ' wait for pin == 1
    highphase               waitpeq mask, mask                      ' * wait for pin to equal 1
                            add     cycles, phsb                    ' * adds phsB to cycles (already containing phsA)
                            mov     phsb, #0                        ' * clear low phase counter
    
    [color=red]' from here on we do the whole calculations[/color]
    
                            ' write number of cycles measured to fcCycles
                            wrlong  cycles, cyclepntr               ' * writes cycles to cyclepntr which is really fcCycles address
    
                            ' count the teeth
                            cmp     tooth, #36 WZ,WC' *compare unsigned values of tooth and literal number 36, some sort of post fix flags?
    if_ae                   mov     tooth, #1       ' *if above or equal, move to tooth
    if_b                    add     tooth, #1       ' *if below, add 1 to tooth
    .....
    

    So, the code above implies, that the low can be shorter and that the high has to be at least long enough to do all the calculations. And here the worst case scenario counts, so all conditions are in a state that the longest possible branch is taken.

    I guess what you currently have in the real setup is, that the low-phase is long and you only have high peaks which are to short.

    Can you also record logic-levels with the PropScope? It would be interesting to see those with a good time-resolution, because that's what's used in the end.
    Possible solution: Add an inverter to the hardware?
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-04 08:49
    I would agree that they are asymmetrical (I do remember you warning me of that), but looking at the physical teeth, they are not completely out of balance to the point where it would be the tooth was 25% of the size of the gap, if that helps in giving a mental picture.

    I did snap another screen shot before going to work this morning, as I remember you had told me previously that you like also seeing the shape of the wave. To me the waves look pretty close, what do you think, do you still feel there isn't enough time during the peaks? I can definitely try and inverter.



    With the 3.3v zener

    cranksignalconditioned4.jpg



    With the 5.1v zener (for comparison)

    cranksignalconditioned4.jpg
  • SapiehaSapieha Posts: 2,964
    edited 2012-04-04 09:02
    Hi.

    Why not use Smith trigger to condition them from analog to Digital signals.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-04 10:10
    Hello,

    I had considered that in the final design portion of the circuit to give myself some hysteresis, but at this development point I was just hoping to test the code out. I may have to go to a schmitt trigger sooner than I anticipated though. It probably is a good idea, I was trying to start off as simple as possible.

    Sapieha wrote: »
    Hi.

    Why not use Smith trigger to condition them from analog to Digital signals.
  • SapiehaSapieha Posts: 2,964
    edited 2012-04-04 10:17
    Hi.

    My concern are that if You start simple without --- You will work 2 times on same programing
    As none of Yours previous timings will be same
    turbosupra wrote: »
    Hello,

    I had considered that in the final design portion of the circuit to give myself some hysteresis, but at this development point I was just hoping to test the code out. I may have to go to a schmitt trigger sooner than I anticipated though. It probably is a good idea, I was trying to start off as simple as possible.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-04 10:59
    You make a good point! I don't want to do the programming two times :)

    I have a few of these at home somewhere, maybe it is time I used one.

    http://www.nxp.com/documents/data_sheet/74HC7014_CNV.pdf
  • SapiehaSapieha Posts: 2,964
    edited 2012-04-04 11:05
    Hi.

    Good choice ---- But Ground all unused inputs.


    turbosupra wrote: »
    You make a good point! I don't want to do the programming two times :)

    I have a few of these at home somewhere, maybe it is time I used one.

    http://www.nxp.com/documents/data_sheet/74HC7014_CNV.pdf
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-04 16:14
    What do you think of this signal Mag? It appears "on time" is about 80% of off time, and there is about 2.5-3 peaks during 1mS at 4000rpm, so approximately 1 high every 125 micro seconds at 10000rpm, or about 1 peak every 8000 clk cycles, maybe 40% of that is "on time" so say worst case scenario about 3000 clk cycles at 10000rpm. Do you still feel there is not enough time?



    @Sapieha

    Here is the comparison on each side of the 466Ω resistor (channel 2 is before, channel 1 is after)

    3.3 zener

    cranksignalconditioned5.jpg



    5.1 zener

    cranksignalconditioned5.jpg


    And here are two samples on the scope with the schmitt trigger as part of the circuit, one at idle (900rpm) and one at 4000rpm. Channel 2 is the signal going into the schmitt, channel 1 is the signal coming out of the schmitt.

    idle

    cranksignalconditioned5.jpg



    4000rpm

    cranksignalconditioned5.jpg
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-05 08:59
    What do you think of the wave shape and can you tell me what you mean by "logic-levels" and then I will record them with the scope?

    Below is what the signals look like with the schmitt in place, and they are compatible with the prop. Just to test, I was able to get the old spin code to read the values, but it would choke when I revved the engine up and freeze? The old spin code reads the time from one peak to the next, I'm trying to figure out how the PASM code is different, at idle there is something like 166000 clk cycles in between each logic high, even if 1/10th of that were the time waitpeq had to work, that's still 16k cycles, which I would think would be plenty of time for PASM? To me it looks like the logic low is about 3 times as long as the logic high. I don't know if I can tweak the PASM code on my own, but before I attempt that, do you agree?


    cranksignalconditioned5.jpg


    MagIO2 wrote: »
    So, the code above implies, that the low can be shorter and that the high has to be at least long enough to do all the calculations. And here the worst case scenario counts, so all conditions are in a state that the longest possible branch is taken.

    I guess what you currently have in the real setup is, that the low-phase is long and you only have high peaks which are to short.

    Can you also record logic-levels with the PropScope? It would be interesting to see those with a good time-resolution, because that's what's used in the end.
    Possible solution: Add an inverter to the hardware?


    It's actually partially working, the rpm will sometimes be correct, it appears to me it is not recognizing the gaps based on the PST output?

    cranksignalconditioned5.jpg
    Here is how the long gap looks on the scope at high resolution, it's about 5.5mS at 1000rpm for the long gap
    cranksignalconditioned5.jpg


    Here is how the standard gaps look at high resolution, it's about 1.5mS at 1000rpm for the standard gaps
    cranksignalconditioned5.jpg]
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-06 14:19
    Hi Mag,

    I don't know if you're still interested in this, but the hardware circuit I built is giving a square wave signal now (or really close) and I can read it at low rpm's with spin, with my old spin code.

    I'd love to be able to read it with PASM so that I don't have to be concerned with speed. Below is the code I used to read the rpm in spin, I'm not sure I can tweak the PASM code on my own, so I'd appreciate your help if you are still interested.
    PUB calculateCrankRpm(localCrankPeriod) | elapsed
    
        elapsed := -cnt
    
        l_previousNum8 := l_previousNum7 
        l_previousNum7 := l_previousNum6
        l_previousNum6 := l_previousNum5
        l_previousNum5 := l_previousNum4
        l_previousNum4 := l_previousNum3
        l_previousNum3 := l_previousNum2
        l_previousNum2 := l_current
        l_current := localCrankPeriod
    
    
    
        if (l_timeStampCrank == 0)
          l_timeStampCrank := (cnt + clkfreq)
    
        if (l_previousNum8 <> 0 and l_previousNum7 <> 0 and l_previousNum6 <> 0 and l_previousNum5 <> 0 and l_previousNum4 <> 0 and l_previousNum3 <> 0 and l_previousNum2 <> 0)
          l_previous7average := ((l_previousNum8 + l_previousNum7 + l_previousNum6 + l_previousNum5 + l_previousNum4 + l_previousNum3 + l_previousNum2)/7)
          l_tCnt += 1
     
          if (((l_current/10)*100) > ((l_previous7average/10)* 110)) or (((l_current/10)*100) < ((l_previous7average/10)*90))
            l_Cnt += 1
         
            if (cnt > l_timeStampCrank)
              l_timeStampCrank := (cnt + clkfreq)  
              l_CntPeak := l_Cnt ' I should a number here matching see rpm/60, for a frequency of 6000 I should see 166.67 of these each second
              l_CntPeakRead := false 
              l_Cnt := 0
              
            l_current := l_previous7average
           
          else
                   
            if (((clkfreq/l_current)*60)/36) < 200
              pst.str(string("crap2"))
              pst.char(13)
           
            else
    
              l_toothRpm := (((clkfreq/l_previous7average)*60)/36)
    
    
          elapsed += cnt - 544
    
    
    Far away
    cranksignalconditionedd.jpg

    Up close showing the gap and the first tooth (I'm not sure why it elongates the first tooth)
    cranksignalconditionedd.jpg

    Up close to compare the logic highs and logic lows
    cranksignalconditionedd.jpg


    And how it looks on the pst (next I'll be cleaning this up so it displays like you set it up)
    pstdualtransistors1.jpg


    Here is a close up of the crank trigger wheel and the bridge/gap
    362cranktrigger1.jpg
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-04-08 09:25
    Hi Turbo,

    I've been off for a while - just watching with my mobile, but it's no fun to write!

    Looking at the screenshots I think the problem is that the GAP detection is not working properly. I think I already mentioned somewhere that it needs to be changed?
    Anyways, one thing I'd do is add an inverter after your schmitt trigger because on some screenshots it looks like the high-time after the gap is not really longer then the usual tooth-high-time. The low time seems to be more reliable.
    Or you can maybe change the code by exchanging both waitpxxx-instructions. Need to think about it. Or you simply try it ;o)

    Why exactly do you start with this previousNum thing again? You remember that we already calculate an average using the moving-average code?
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-08 17:45
    Hello,

    When I was having trouble reading the frequency with PASM, I wanted to see how it did with spin just as a baseline. The code I posted works at lower rpm, but does not have the speed needed for higher rpm. It was just me verifying that the hardware portion was working.

    You are right, gap detection is not working, the rest of the calculations seem to be working though since the new hardware was implemented and I was able to copy and imitate the signal perfectly with the prop. :)

    At least I can now test confidently, knowing that the signal I generate with the prop matches the signal the cars hardware is putting out perfectly.

    workingpasmpst1.jpg

    Here is the code I use to generate the proper signal

    crank.spin
    CON
      ' current code only allows from 1Hz upwards 
      MIN_FREQUENCY = 1
      ' dunno which upper limit can be achieved by the SPIN-code        
      MAX_FREQUENCY = 9200
      
    VAR
      byte   pin, presentTeeth, missingTeeth, cog
      long   frequencyRate
    
      long   pulse, sync, timing, l_localIndex
      long   stack[100]
    
    PUB start(p, pt, mt, initFrequency)
      pin := p
      presentTeeth := pt
      missingTeeth := mt
      setFrequency( initFrequency )
    
      if cog
        cogstop( cog-1 )
    
      'cog := cognew( crankPulser, @stack )+1
      cog := cognew(simulateCrankWheel(pin, presentTeeth, missingTeeth, initFrequency), @stack )+1  'simulateCrankWheel(4, 36, 2, 15000)
    
    PUB setFrequency( newFrequ )
      frequencyRate := (newFrequ #> MIN_FREQUENCY ) <# MAX_FREQUENCY
    
      timing := clkfreq / frequencyRate
      pulse := timing >> 1
    
    PUB getFrequency
      return frequencyRate
      
    PRI crankPulser
      dira[pin] := 1                                                ' make output 
    
      frqa := 1
      phsa := 0
      ctra := (%00100 << 26) | pin                   ' setup counter for pin
    
      sync := cnt                                                   ' sync with system clock  
      repeat    
        repeat l_localIndex from 1 to (presentTeeth- missingTeeth)
          phsa := -pulse                                              ' create 1ms pulse
          waitcnt(sync += timing)                                     ' hold for current hz setting
        
        repeat l_localIndex from 1 to (missingTeeth)
          phsa := 0                                             ' create 1ms pulse
          waitcnt(sync += timing)
    
    
    
    PUB simulateCamWheel(simCamWheelPinNum, engineRPM, crankRotsToCamRots, degreeOfTrigger1, degreeOfTrigger2, degreeOfTrigger3, camTriggerDegreeWidth) | localIndex1, crankRpmPerSecond, camRpmPerSecond, localCnt, trigger1Wait, trigger2Wait, trigger3Wait, emtpySpace1Wait, emtpySpace2Wait, emtpySpace3Wait, cyclesPerDegOfRot
    
      
      
      dira[simCamWheelPinNum]~~
      outa[simCamWheelPinNum]~
      localIndex1 := 0
    
      crankRpmPerSecond := (engineRPM/60)                   ' 166.667 crank rots per second at 10k rpm
      camRpmPerSecond := (((engineRPM*10)/60)/2)                 ' 83.333 cam rots per second at 10k rpm
      cyclesPerDegOfRot := (((clkfreq/camRpmPerSecond)/360)*10)  ' 960000/360 at 10k or 2660
    
      trigger1Wait := (camTriggerDegreeWidth*cyclesPerDegOfRot)                     ' 13300 / 5 degrees
      trigger2Wait := (camTriggerDegreeWidth*cyclesPerDegOfRot)                     ' 13300 / 5 degrees
      trigger3Wait := (camTriggerDegreeWidth*cyclesPerDegOfRot)                     ' 13300 / 5 degrees
      emtpySpace1Wait := (degreeOfTrigger1*cyclesPerDegOfRot)                       ' 266000 / 100 degrees
      emtpySpace2Wait := (degreeOfTrigger2*cyclesPerDegOfRot)                       ' 266000 / 100 degrees 
      emtpySpace3Wait := (degreeOfTrigger3*cyclesPerDegOfRot)                       ' 385700 / 145 degrees    
                                                                                    ' + = 957600   (((clkfreq/957600) * 60sec/min) * 2rots campercrank) = 10krpm
     
      localCnt := cnt                                      
    
      repeat
    
        outa[simCamWheelPinNum]~~
        waitcnt(localCnt += trigger1Wait)                ' 6665                
        outa[simCamWheelPinNum]~
        'waitcnt(localCnt += (clkfreq/521))                  ' 160000-6665 
        waitcnt(localCnt += emtpySpace1Wait)
        outa[simCamWheelPinNum]~~
        waitcnt(localCnt += trigger2Wait)                ' 6665
        outa[simCamWheelPinNum]~
        'waitcnt(localCnt += (clkfreq/521))                  ' 160000-6665 
        waitcnt(localCnt += emtpySpace2Wait)
        outa[simCamWheelPinNum]~~
        waitcnt(localCnt += trigger3Wait)                ' 6665
        outa[simCamWheelPinNum]~
        'waitcnt(localCnt += (clkfreq/521))                  ' 160000-6665 
        waitcnt(localCnt += emtpySpace3Wait)
    
    
    PUB simulateCrankWheel(simCrankWheelPinNum, crankTeethSimToothCnt, crankTeethSimMissingToothCnt, crankTeethSimRPM) | localIndex, waitTime, logicHighWaitTime, logicLowWaitTime, logicHighGapWaitTime, logicLowGapWaitTime, startCnt, existingTeeth 
     
    
      
       ' Initialize variables here 
      dira[simCrankWheelPinNum]~~
      outa[simCrankWheelPinNum]~
      localIndex := 0
      waitTime := (clkfreq/((crankTeethSimRPM*(crankTeethSimToothCnt*2))/60))  ' for 1500rpm = 44444
      logicHighWaitTime := ((waitTime/50)*45) 
      logicLowWaitTime := ((waitTime/50)*55)
      logicHighGapWaitTime := ((((waitTime*6)/100)*43)-logicHighWaitTime) ' this percentage can be measured by a prop scope and a signal capture
      logicLowGapWaitTime := ((((waitTime*6)/100)*57)-logicLowWaitTime)
      existingTeeth := (crankTeethSimToothCnt - crankTeethSimMissingToothCnt)
      
      startCnt := cnt
    
      {ctra := (%00100 << 26) | simCrankWheelPinNum                                  ' setup counter for pin
      frqa := 1                                                                     ' this makes the cnt screw up every 26 seconds                                      
      phsa := 0}
    
      {
        This is for a Hall effect signal/sensor simulation
        For 1000rpms on a 36-2 crank trigger wheel, it'd be (1000(36*2)) = 72000, then 72000/60 = 1200 teeth on/teeth off per clkfreq. 80000000(clkfreq)/1200 =
        a tooth on or tooth off every 133333.3 clk cycles. It would be on for 66666.67 clk cycles and then was off for every 66666.67 clk cycles  
        So you'd loop on for 66666.67 cycles and then off for 66666.67 cycles and after 34 times, you'd wait for 66666.67 cycles * 4, to simulate the 2
        missing teeth on and accompanying 2 "missing" teeth off (or gaps in between each tooth) . It should account for 2 missing teeth and 3 missing toothgaps
        An example to start the method would be simulateCamWheel(7, 3, 105, 100)
      }
      
     
      repeat
    
        repeat localIndex from 1 to (existingTeeth)    ' loop number of physical teeth on and off  
          outa[simCrankWheelPinNum]~~
          'l_crankTeethSimOn := startCnt
          waitcnt(startCnt += logicHighWaitTime)              ' on for 1 tooth
          outa[simCrankWheelPinNum]~
          'l_crankTeethSimOff := startCnt
          waitcnt(startCnt += logicLowWaitTime)               ' off for 1 tooth
          
     
        repeat localIndex from 1 to 1'(crankTeethSimMissingToothCnt)                             ' loop number of times for each missing tooth
          outa[simCrankWheelPinNum]~
          'l_crankTeethSimOff := startCnt
          waitcnt(startCnt += logicLowGapWaitTime)            ' off for 57% of 2 teeth
          outa[simCrankWheelPinNum]~~
          'l_crankTeethSimOff := startCnt
          waitcnt(startCnt += logicHighGapWaitTime)           ' on for 43% of 2 teeth
          
    
                                      
    


    stepbystep.spin
    l_rpm := 15000
      l_toothCount := 36
      l_frequency := ((((l_rpm*10)/60)*l_toothCount)/10)
      
      'co.start(CRANK_WRITE_PIN, 36, 2, l_frequency)                                               
      co.start(CRANK_WRITE_PIN, 36, 2, l_rpm)
    
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-08 19:22
    Hi Mag,

    I have some good news, I haven't checked this on the car, only the sim method, but I noticed gap cnt was 2x what it should be, I believe because the a/c gap wave, which is about the width of 4 teeth is being split at the digital conversion so that the digital version (ac wave split in half) has a longer than usual low, but also a longer than usual high, both being about the equivalent width of 2 teeth. Unfortunately it does not work at lower rpm :(

    I think this is causing the gap portion to count twice? So when I call the method, I've just done a /2 now.

    The question is, how do I go from here?

    I don't exactly know how I want to go about this, but I know my end goal. I want to be able to compare the cam sensor location to the crank sensor location and then adjust the cam sensor location via a simple transistor, until the feedback from the cam sensor location matches where I'd like it to be. Maybe I can do a time comparison based on trigger tooth 1 of both the cam sensor trigger and the crank sensor trigger and then calculate the offset? Does that make sense?

    The code I use to simulate the cam sensor output, which I wrote this weekend and it simulates the cam sensor output perfectly.

    Do you have any guidance on how to reference trigger tooth 1 of each sensor and then offset it the amount of degrees or time accordingly?


    workingpasmpst2.jpg
    PUB simulateCamWheel(simCamWheelPinNum, engineRPM, crankRotsToCamRots, degreeOfTrigger1, degreeOfTrigger2, degreeOfTrigger3, camTriggerDegreeWidth) | localIndex1, crankRpmPerSecond, camRpmPerSecond, localCnt, trigger1Wait, trigger2Wait, trigger3Wait, emtpySpace1Wait, emtpySpace2Wait, emtpySpace3Wait, cyclesPerDegOfRot
    
      
      
      dira[simCamWheelPinNum]~~
      outa[simCamWheelPinNum]~
      localIndex1 := 0
    
      crankRpmPerSecond := (engineRPM/60)                   ' 166.667 crank rots per second at 10k rpm
      camRpmPerSecond := (((engineRPM*10)/60)/2)                 ' 83.333 cam rots per second at 10k rpm
      cyclesPerDegOfRot := (((clkfreq/camRpmPerSecond)/360)*10)  ' 960000/360 at 10k or 2660
    
      trigger1Wait := (camTriggerDegreeWidth*cyclesPerDegOfRot)                     ' 13300 / 5 degrees
      trigger2Wait := (camTriggerDegreeWidth*cyclesPerDegOfRot)                     ' 13300 / 5 degrees
      trigger3Wait := (camTriggerDegreeWidth*cyclesPerDegOfRot)                     ' 13300 / 5 degrees
      emtpySpace1Wait := (degreeOfTrigger1*cyclesPerDegOfRot)                       ' 266000 / 100 degrees
      emtpySpace2Wait := (degreeOfTrigger2*cyclesPerDegOfRot)                       ' 266000 / 100 degrees 
      emtpySpace3Wait := (degreeOfTrigger3*cyclesPerDegOfRot)                       ' 385700 / 145 degrees    
                                                                                    ' + = 957600   (((clkfreq/957600) * 60sec/min) * 2rots campercrank) = 10krpm
     
      localCnt := cnt                                      
    
      repeat
    
        outa[simCamWheelPinNum]~~
        waitcnt(localCnt += trigger1Wait)                ' 6665                
        outa[simCamWheelPinNum]~
        'waitcnt(localCnt += (clkfreq/521))                  ' 160000-6665 
        waitcnt(localCnt += emtpySpace1Wait)
        outa[simCamWheelPinNum]~~
        waitcnt(localCnt += trigger2Wait)                ' 6665
        outa[simCamWheelPinNum]~
        'waitcnt(localCnt += (clkfreq/521))                  ' 160000-6665 
        waitcnt(localCnt += emtpySpace2Wait)
        outa[simCamWheelPinNum]~~
        waitcnt(localCnt += trigger3Wait)                ' 6665
        outa[simCamWheelPinNum]~
        'waitcnt(localCnt += (clkfreq/521))                  ' 160000-6665 
        waitcnt(localCnt += emtpySpace3Wait)
    
    
    
Sign In or Register to comment.