Shop OBEX P1 Docs P2 Docs Learn Events
Converting my product to Open Source and using the Prop - Page 4 — Parallax Forums

Converting my product to Open Source and using the Prop

124»

Comments

  • CircuitsoftCircuitsoft Posts: 1,166
    edited 2012-01-12 18:10
    For prototyping, I would do the one-wire-to-each-pin method, but also solder a couple 5" long 10-gauge solid-core wires to the heat slug on the bottom of the chip to act as a heat sink. On your final board, you should have a couple vias from the thermal slug of the chip to the other side of the board, where you can either attach a heat sink, or just have a large area copper pour.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-12 20:11
    The mosfet I have bought is the one you recommended on the first page : http://search.digikey.com/us/en/products/BTS4160DGA/BTS4160DGACT-ND/2231091

    It does not have a heat sink so are you talking about putting one of those aluminum heatsinks like what is on the processor in a computer but smaller?
  • CircuitsoftCircuitsoft Posts: 1,166
    edited 2012-01-13 09:04
    I thought there was a pad on the bottom of the chip in the middle that would be soldered to the circuit board. If not, then disregard my comment about heat sinking it. Either way, your application isn't getting close to stressing the part, and it shuts itself down at 150C, if need be, anyway.

    See OPA2677 Datasheet, Page 30 for an example of what I'm talking about.
  • CircuitsoftCircuitsoft Posts: 1,166
    edited 2012-01-13 09:07
    So, looking at your code on page 3, I guess if it does go into thermal shutdown, you'll be stuck in 3rd gear? Can you drive that way at all, or will you burn out your torque converter?
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-13 16:51
    You can drive like that up to 45 or 50 MPH for a short while which is what the stock control unit does already.

    I am a little confused on how the mosfet chip works in this data sheet : http://www.infineon.com/dgdl/BTS+4160DGA_DS2008_03_18_neu.pdf?folderId=db3a304314dca389011537739e37155f&fileId=db3a30431a5c32f2011a957ab5875685

    On page 14 figure 9, it shows an example of how it would be connected in a circuit. What does "VccμC" stand for? And... For the diagnostic feedback, I am unsure what that pin actually does. These datasheets confuse me so much but I am learning! I am still reading up on it before I solder anything to the pins for testing. If I could use the diagnostic feedback to send a signal of some type back to the Prop letting it know that part in "in trouble", I could automatically kick the program into error mode and shut down the output for safety reasons.
  • CircuitsoftCircuitsoft Posts: 1,166
    edited 2012-01-13 20:47
    VCC(mu)C is the supply voltage to the propeller.

    The ST0 and ST1 pins will be pulled low if channels 0 or 1 go into thermal shutdown or if the output has no load. Details on page 18.
  • CircuitsoftCircuitsoft Posts: 1,166
    edited 2012-01-13 20:50
    You can drive like that up to 45 or 50 MPH for a short while which is what the stock control unit does already.
    What I really wonder is if you can start from a stop that way.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-13 21:22
    You can start from a complete stop like that, but it takes a little bit to get up to speed. The gear ratio is pretty low giving more torque output even in third gear. I can only go around 90mph in 3rd @ 7k RPM. I have had to drive in third gear for a few days until I created a simple circuit to control the transmission since the control unit went bad which is a common problem in vehicles like mine. I wanted more features so I upgraded to "digital" and now I am trying to go even more advanced :)

    I have the mosfet wired up on my breadboard with LED's as the test output. It seems to be working correctly. Do I need to have anything connected to the ST0 and ST1 pins if I am going to return some feedback to the Prop? I am not sure what voltage will be sent back when not in "fault" mode. I have read a 15K resistor to pull up(?) the ST pins to the 3.3v source. If I do that, how would I read if a fault happens?

    Also a little off subject... Can I have a cog automatically run in the background updating global variables and updating the LCD without having to call it in the main loop? When I push a button to change to the next gear and hold it, the display does not update the RPM value.
  • kuronekokuroneko Posts: 3,623
    edited 2012-01-13 21:31
    Can I have a cog automatically run in the background updating global variables and updating the LCD without having to call it in the main loop?
    Certainly. Just note that when the LCD is used from somewhere else (other than the RPM cog) you'll need some form of synchronisation between them (usually a lock will do, there are other solutions as well).
  • CircuitsoftCircuitsoft Posts: 1,166
    edited 2012-01-13 21:38
    You probably want one cog handling the LCD and seven-segment display, another driving the MOSFETs and handling switch input. Maybe a third watching engine RPM and updating a global variable?

    Anyway, the ST pins are open-drain, so they remain an open circuit until a fault occurs, when they are pulled low. If you add pullup resistors to the output of the MOSFETs, (15K will do since you already have them) they will warn you about open-circuited output as well.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-13 21:42
    Ok, so how would I start a cog and have it loop? Can I simply put the Repeat command in the init function after I start a new cog and call it before the main Loop?

    EDIT for Example :
    [PHP]
    '
    MAIN CODE
    OBJ
    lcdupdate : "LCD_Updater"
    readrpm : "jm_freqin"
    ' include LCD obj

    PUB Main | gear
    ' start LCD
    readrpm.init
    lcdupdate.init
    ......

    '
    LCD_Updater Code

    PUB init
    ' Code to Start a new cog....
    REPEAT
    lcd.gotoxy(5,1)
    lcd.string(Update RPM on screen)
    '
    [/PHP]

    The seven segment display is updated only when a button is pressed or it goes into error mode. Since the display code makes the pins lock high, I don't think it will hurt leaving it to update when needed.

    The RPM / frequency code does need to run on it's own without having to call it each pass through the main loop. I have not figured this out yet.

    The Mosfet pins along with the switch handling is all being handles in the main loop. I could be put into it's own Cog, but I don't think there is a need for it since that is the base everything else works off of. If someone hits the down button and are at 7k RPM, the code will simply check the RPM variable and ignore the next step to shift down a gear. I also want to read the vehicle speed to allow a wider range of tuning as well. That will come later after I get everything else working correctly though.
  • kuronekokuroneko Posts: 3,623
    edited 2012-01-13 21:56
    Ok, so how would I start a cog and have it loop? Can I simply put the Repeat command in the init function after I start a new cog and call it before the main Loop?
    Basically yes. From my earlier example, this time a background process updates the global rpm variable the main loop only displays it.
    CON
      _clkmode = XTAL1|PLL16X
      _xinfreq = 5_000_000
    
    CON
      pin = 16
      
    OBJ
      helper: "jm_freqin"
      serial: "FullDuplexSerial"
    
    VAR
    [COLOR="orange"]  long  rpm
      long  stack[32]
    [/COLOR]  
    PUB null
    
      serial.start(31, 30, %0000, 115200)                   ' debug output
      waitcnt(clkfreq*3 + cnt)                              ' startup delay
      serial.tx(0)                                          ' clear screen
    
    [COLOR="orange"]  cognew(background, @stack{0})[/COLOR]
      
      ctra := constant(%0_00100_000 << 23 | pin)            ' |
      frqa := 1789 {2^32*(1000/30)/clkfreq)}                ' |
      dira[pin]~~                                           ' simulate 1000rpm
    
      repeat                                                ' display value
        serial.hex(rpm, 8)
        serial.tx(32)
        serial.hex(result++, 8)                             ' increment for each reading (so we can observe change)
        serial.tx(1)
        waitcnt(clkfreq/3 + cnt)
    
    [COLOR="orange"]PRI background
    
      helper.init(pin)
    
      repeat                                                ' display value
        rpm := helper.freq{0.1Hz} * 3                       ' 0.1Hz -> rpm
        waitcnt(clkfreq + cnt)                              ' allow for new measurement[/COLOR]
        
    DAT
    
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-13 22:04
    Ok, I think I get it. Will the waitcnt cause any problems with timing anywhere else? I know in the frequency code posted by Johnny Mac, it says to not call faster than the expected input frequency. I guess I need to time it for that correct?
  • kuronekokuroneko Posts: 3,623
    edited 2012-01-13 22:11
    Will the waitcnt cause any problems with timing anywhere else? I know in the frequency code posted by Johnny Mac, it says to not call faster than the expected input frequency. I guess I need to time it for that correct?
    The waitcnt only affects the cog calling it (is that what you're worried about?). As for frequency updates, right now I have it update the RPM once per second (waitcnt in the background method). The object needs at least one period (from the incoming square wave) to measure its length. Calling it faster than that will give you null readings (value is cleared after reading until it's updated again). So you may have to deal with lower RPM values somehow, i.e. when 1/sec may be too often.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-13 22:28
    Ok, so since my minimum rpm would be 300 rpm which is 500 below idle, I could call the rpm reading function a max of 600 times a second (600 times / 2 pulses per revolution) Since 100 times per second is more than enough, I should be ok there.

    I don't want to clear the rpm variable since it may be in between updating when the main loop reads the RPM variable. It should simply update the RPM variable each pass though the 100 times per second loop. If I can get this working tomorrow, I may take it for a test drive. I wish I could consolidate everything to one bread board though. It would make things so much easier and less room for error.
  • kuronekokuroneko Posts: 3,623
    edited 2012-01-13 22:48
    Ok, so since my minimum rpm would be 300 rpm which is 500 below idle, I could call the rpm reading function a max of 600 times a second (600 times / 2 pulses per revolution) Since 100 times per second is more than enough, I should be ok there.
    Correct me if I'm wrong. 300 rpm are 5 revolutions per second (or 10 pulses/sec). Which means there wouldn't be much point sampling with more than 10Hz. Anyway, just get the current value, if it's null simply don't update the global rpm variable, e.g.
    if temp := helper.freq
      rpm := temp * 3
    
  • CircuitsoftCircuitsoft Posts: 1,166
    edited 2012-01-13 23:55
    Just don't update your display faster than your engine RPM and you'll be okay. You could do a display loop with:
    PUB Init
      cognew(LCDProc, @stack)
      '... Other stuff
    
    PRI LCDProc | tmp
      repeat
        tmp = cnt + CLKFREQ/10
        ' Update LCD here
        waitcnt(tmp)
    
    This will update the LCD at 10Hz. Although, I suppose that amounts to 300 RPM (4cyl) or 200 RPM (6cyl), so it could occasionally get confused.

    cognew starts a process in a new cog. It won't affect the timing in the main thread at all. That's why the propeller is a multicore processor.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-14 08:39
    Quick question... If I create a new file called "LCD_Updater" and call it from the main file, how do I pass or update global variables between the two? Do I have to put the function all in the main file instead of a second one?

    EDIT :
    I am having difficulties understanding how to start a new cog and have it repeat code in the background... Here is my current code :

    [PHP]CON
    _CLKMODE = XTAL1 + PLL16X
    _XINFREQ = 5_000_000
    solenoida = 2
    solenoidb = 3
    upbutton = 0
    downbutton = 1

    VAR
    LONG lastWritten
    LONG rpm
    BYTE EVal1
    BYTE lcdcogstack
    BYTE throttle
    BYTE gear

    OBJ
    i2c : "Basic_I2C_Driver"
    BS2 : "BS2_Functions"
    'throt : "RCTIME"
    lcd : "Serial_Lcd"
    getrpm : "jm_freqin"
    num : "simple_numbers"

    PUB Main
    ' Define global variables
    lcdcogstack := 0
    ' End Define
    lcd.init(8, 9600, 2)
    lcd.displayOn
    lcd.backLight(false)
    lcd.gotoxy(0,0)
    lcd.str(string("Testing Version "))
    lcd.gotoxy(0,1)
    lcd.str(string("Tims shifter V3 "))
    waitcnt(200_000_000 + cnt)
    BS2.start (31,30)
    EVal1 := 100
    gear := i2c.ReadLong(i2c#BootPin, i2c#EEPROM, @EVal1)
    if gear < 1 OR gear > 4
    gear := 1
    getrpm.init(15)
    lcd.cls
    lcd.str(string("Gear: "))
    lcd.gotoxy(0,1)
    lcd.str(string("RPM : "))
    cognew(LCDupdate, @lcdcogstack)

    gear := shiftgear(gear)

    repeat
    rpm := getrpm.freq * 3
    'throttle := getthrottle
    if ina[upbutton] == 1
    gear++
    gear := shiftgear(gear)
    if ina[downbutton] == 1
    gear--
    gear := shiftgear(gear)
    repeat while ina[downbutton] == 1 or ina[upbutton] == 1
    waitcnt(3_000_000 + cnt)

    waitcnt(10_000_000 + cnt)

    PRI LCDupdate
    repeat
    lcd.gotoxy(5,0)
    lcd.str(num.dec(gear))
    lcd.str(string("um"))
    lcd.gotoxy(5,1)
    lcd.str(num.dec(rpm))
    waitcnt(clkfreq / 100 + cnt)

    PUB shiftgear(tmp)
    if tmp > 4
    tmp := 4
    if tmp < 1
    tmp := 1

    'throttle := getthrottle(tmp)

    dira[solenoida]~~
    dira[solenoidb]~~
    outa[16..23]~
    dira[16..23]~~

    if tmp == 1
    outa[solenoida] := 1
    outa[solenoidb] := 1
    if tmp == 2
    outa[solenoida] := 0
    outa[solenoidb] := 1
    if tmp == 3
    outa[solenoida] := 0
    outa[solenoidb] := 0
    if tmp == 4
    outa[solenoida] := 1
    outa[solenoidb] := 0
    outa[16..23] := numbers[tmp]
    saveval(tmp)
    'lcd.gotoxy(5,0)
    'lcd.str(num.dec(tmp))
    return tmp

    PUB saveval(tmp) | temp, startTime
    temp := tmp
    if temp <> lastWritten and temp <> 0
    if i2c.WritePage(i2c#BootPin, i2c#EEPROM, @EVal1, @tmp, 4)
    abort ' an error occured during the write
    startTime := cnt ' prepare to check for a timeout
    repeat while i2c.WriteWait(i2c#BootPin, i2c#EEPROM, @tmp)
    if cnt - startTime > clkfreq / 10
    abort ' waited more than a 1/10 second for the write to finish
    lastWritten := temp
    return

    PUB getthrottle | thr
    dira[5]~~ ' Set as output
    outa[5]:=1 ' Set high
    BS2.Pause(10) ' Allow to charge
    'throttle := BS2.RCTime(5,1) ' Measure RCTime
    lcd.gotoxy(13, 0)
    lcd.str(string(" "))
    lcd.gotoxy(13, 0)
    lcd.str(num.dec(throttle)) ' Display
    return throttle

    DAT
    numbers byte %0000_0000, %0101_0000, %1100_1110, %1101_1010, %0101_0011[/PHP]
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-14 10:04
    ok, I am completely lost on the whole Cog thing and assigning stacks. I don't understand how to figure what number to use for certain stacks. Right now, the program is showing the boot screen, then going to 4th gear. If I push any button, it will automatically go to first gear. If I move the COGNEW command above the shiftgear() function, it boots to first gear like it should. How is the gear variable being updated to 4??? I am not updating the variable anywhere in the LCDupdate function. I was hoping to take this for a test drive today with a basic functionality.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-14 12:17
    Got it fixed :) Had to start another thread since I guess people stay away from huge threads?

    Now that I have that working, I am moving on to the next function... Reading the throttle input from the vehicle. I had this working on my SX at one point, but I cannot remember how to wire it up correctly. I remember there was a non polarized cap along with 2 resistors, but for the life of me, I can remember how it was hooked up. I have the BS2.RCTIME already set in my program, but I worry about hooking it up to my car since there is a voltage output of a max 5.5V from the TPS to ground. I will be doing some more digging and hopefully I can find it on my own, but if someone has the answer before I find it, I would greatly appreciate it!
  • frank freedmanfrank freedman Posts: 1,983
    edited 2012-01-14 21:24
    Got it fixed :) Had to start another thread since I guess people stay away from huge threads?

    Now that I have that working, I am moving on to the next function... Reading the throttle input from the vehicle. I had this working on my SX at one point, but I cannot remember how to wire it up correctly. I remember there was a non polarized cap along with 2 resistors, but for the life of me, I can remember how it was hooked up. I have the BS2.RCTIME already set in my program, but I worry about hooking it up to my car since there is a voltage output of a max 5.5V from the TPS to ground. I will be doing some more digging and hopefully I can find it on my own, but if someone has the answer before I find it, I would greatly appreciate it!

    If I recall correctly, most TPS circuits are a pot. You may have to scale the voltage value using an opamp such as the NTE 928 single supply device (because you can get it just about anywhere that sells NTE replacement parts, tv/electronics supply, Frys elex, others ). Then use either an ADC such as the MCP320X (multiple objects in the exchange w/ examples from 1 to 8 inputs), or sigma-delta method found elsewhere on the forum. Personally I would recommend going with the ADC chip. Costs more, but the S/D method layout requirements and issues make it [seem to me at least] a non-trivial way to do analog to digital conversion in a less than ideal environment.

    Nice to see your project moving forward!!

    FF

    Edited to add " checkout the project called DAQpac from the 2010 parallax propeller contest, you may find some work already done for you if the project is MIT licensed".
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-19 20:01
    I have gotten the throttle reading working to as accurate as I can with the current components I have so now.... Moving on to the next thing. Vehicle speed... From what I understand, the VSS is a reed switch that gets a 5v source from the ECU. For each revolution, there will be 4 pulses. I was thinking of using the BS2 Count function, but I was hoping for a simpler solution if there is one.

    Also...the math is going to be a little tricky as well since tire size will make a difference if I am not mistaken. According to this chart : http://www.jekylhyderacing.com/HeightofTires.htm, my tires are 24.88" tall. This converts to 78.12" around. Since there are 63360" in a mile, I am trying to figure out what the formula would be....

    This is what I have so far
    Revolutions to go one mile : 811.06 = Inches in a Mile : 63360 / (Tire Height : 24.88 * 3.14)
    Sensor Pulses in one mile : 3244.24 = 811.06 * 4

    Speed : 55 = ((Pulses Counted for 500ms : 1487 * 2) * 60 seconds) / Sensor Pulses in one mile : 3244

    Does that sound about right? Hopefully that did not confuse anyone :p
  • chetw77cruiserchetw77cruiser Posts: 12
    edited 2012-01-19 21:15
    What vehicle and what transmission is this going onto? There were many different VSS sensors that GM used with different output signals and counts per mile. Let me know and I will help where I can. I also have some code that will work with the VSS and converts to MPH that may work for your app. The vss setting is adjustable, and it even has an auto calibration function.
  • pedwardpedward Posts: 1,642
    edited 2012-01-19 21:37
    Think of MPH as the distance travelled per pulse.

    If it's ~25 inches * ~3 you have 75 inches per 4 pulses. That's ~18-3/4 inches per pulse. If you are counting 3000 pulses per minute, then 18.75 * 3000 * 60 = IPH / 63360 = MPH

    3000 * 18.75 = 56250 IPM
    56250 * 60 / 63360 = 53.25MPH

    To make the math easier and retain precision:

    3000 * (18.75 * 60) / 63360 = MPH
    3000 * 1125 / 63360 = MPH
    pulses per minute * 1125 / 63360 = MPH

    That will avoid overflow and you still have plenty of precision. If you update the MPH about once per second, you should have a fairly steady reading. Your problem will be extrapolation errors when you don't have a lot of samples or the samples are far apart.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-20 16:24
    The vehicle is a 93 Talon with a 94 AWD transmission and a 91 JDM engine turbo charged. Fun little car :) W4A33 is the transmission number.

    The low speed will be an issue and updating the MPH every 1 second will mean that cars that run 9's and 10's in the 1/4 may not be able to use this product. Since they usually run through 3 gears within about 6 to 7 seconds, it may not be able to keep up with their speed. I was hoping to update the MPH variable at least a minimum of 2 times a second.

    Where would the overflow be? If the variable is a long, I don't think it would hit the max size.
  • pedwardpedward Posts: 1,642
    edited 2012-01-20 16:37
    Tim, I referred to my notes and speedo setups are generally calibrated to provide a certain number of pulses per mile. I seem to recall 2000-8000 is a common number, depending on manufacturer and model. This should be enough resolution, the problem is at really low speeds, like 1mph, where you don't get enough pulses to calculate a steady speed.

    Updating the variable more than 1 time per second is advisable, I was referring to updating a display at 1Hz. If a guy is in a 10 second car, you won't want for pulses!

    Overflow refers to how you use the variable, you can overflow and underflow a variable, where you have too many digits or not enough. If you shift numbers over to account for the lack of floating point, you end up with big integers, and if you do the math operations in the wrong order you will end up with values less than 1, so you can overflow with too big of a value and underflow with too small of a value.

    In my code I did microseconds per hour divided by pulses per mile and divide that by the current pulsewidth of the last capture. That's 3.6 billion divided by (2000 * 60Mph) / pulsewidth, if I recall correctly. My micro was keeping track of rising edge to rising edge with a microsecond resolution. My code was written in C++ and ran on a computer or ARM PDA. I never got the PDA to run the code due to bugs in the QT/QPE widget environment.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-20 16:49
    Should I use the count method to get the input or is there a better way? I will try to get a reading at a few different speeds and go from there. For all I know, it could be 1 pulse per revolution :p
  • chetw77cruiserchetw77cruiser Posts: 12
    edited 2012-01-20 22:52
    You have a PM.
Sign In or Register to comment.