Spin and PWM



  • Since I was unable to get serial to work on the Flip I decided to use a method of assigning a value from another flip to this flip. The assignment operator worked in earlier tries(5 years ago). I run at 5meg because the original system operated at four MHz(aPIC16C57). I tried to do this with arduino but couldn't slow the system enough. Arduino runs at 16MHz.
  • JonnyMacJonnyMac Posts: 6,737
    edited 2020-06-21 - 20:19:00
    Since I was unable to get serial to work on the Flip...
    What? Serial is dead easy on the Propeller.
    I run at 5meg because the original system operated at four MHz(aPIC16C57). I tried to do this with arduino but couldn't slow the system enough. Arduino runs at 16MHz.
    Zoinks. The Propeller is a completely different beast -- it has features that are specifically designed to facilitate programs like the one you're attempting. No matter what else, don't apply the rules of one processor to the programming of another -- it's usually ends in tragedy. For example, you seem to assume that Spin runs the method called main first (like C). It doesn't unless that method is the first in the listing.

    Because there was never a clear description (in English) of how you wanted the program to behave, I made the assumption that the 5MHz clock speed was about power saving. The only time I've ever worried about speed and power savings was for badges Parallax made for DEF CON (I coded them). Since I've been programming a while (since 1980), and have been using the Propeller since before it was released to the public (I worked for Parallax at the time), I was able to make your program work (sans mystery inputs) at 5MHz ('scope trace attached). Now... it works, but if you start bashing it with features that are not well thought out, it will break. Again, I thought you were after energy savings so this program runs in one cog. If you bloat the main loop, the waitcnt target will be missed and the program will appear to hang. I forced this to happen by changing the ms parameter in the call to the buttons scan. At 8ms, the program hangs.

    My programs are more verbose than yours -- let me suggest you lean toward my style. As I may have said elsewhere in this thread, program listings should be easy on the eyes (nice formatting) and brains (sensible naming) of the other humans that will read the code.

    If you change the PLL setting to 16x (standard), do you know how the behavior of my program is affected? It's not. On the outside it will do exactly the same thing -- under the hood the instructions will be running faster, but the calculated constants will be updated so that the external behavior is as we intended: 1ms pulse every 10ms (when active).

    Please, please, please... stop using *magic* numbers like this (your code):
    To an inexperienced programmer, 5000 means nothing. I knew to check the clock speed and was able to determine that this is equal to a 1ms pulse -- but only at 5MHz. If you change the PLL setting to 2x but don't change the 5000, you'll now get pulses that are 1/2ms wide. This is why it makes sense to do things like this (my code):
    con { timing }
      _clkmode = xtal1 + pll1x                                     
      _xinfreq = 5_000_000                                          ' use 5MHz crystal
      CLK_FREQ = (_clkmode >> 6) * _xinfreq                         ' system freq as a constant
      MS_001   = CLK_FREQ / 1_000                                   ' ticks in 1ms
      US_001   = CLK_FREQ / 1_000_000                               ' ticks in 1us
      MOVE = MS_001                                                 ' pulse output is 1ms in 10ms cycle
      STOP = 0
    Since MS_001 is a calculated constant, the program will sort itself any time I make a PLL setting change.

    Your code, in fact, has a double-whammy: In addition to 5000 not being meaningful, you're putting that value into a variable that is used later -- this is just consuming extra cycles to read a constant value from that variable (and at 5MHz, you don't have a lot of cycles to waste).

    Yes, writing code in the manner I (and others) do takes a little extra time -- but very little, and always saves more, especially for others attempting do decode our work. In fact, they shouldn't have to decode anything; our listings should make the program intent obvious.

    Here's the listing as is; one cog, no libraries used, running at 5MHz. Please note that if you edit this code and re-post it anywhere, YOU MUST REMOVE MY NAME. I don't want credit for anyone's work.
    '' =================================================================================================
    ''   File....... jm_telescope_control.spin
    ''   Purpose....
    ''   Author..... Jon "JonnyMac" McPhalen
    ''               Copyright (c) 2020 Jon McPhalen
    ''               -- see below for terms of use
    ''   E-mail..... jon.mcphalen@gmail.com
    ''   Started....
    ''   Updated.... 20 JUN 2020
    ''   {$P1} 
    '' =================================================================================================
    con { timing }
      _clkmode = xtal1 + pll1x                                     
      _xinfreq = 5_000_000                                          ' use 5MHz crystal
      CLK_FREQ = (_clkmode >> 6) * _xinfreq                         ' system freq as a constant
      MS_001   = CLK_FREQ / 1_000                                   ' ticks in 1ms
      US_001   = CLK_FREQ / 1_000_000                               ' ticks in 1us
    con { io pins }                                                  
      RX1  = 31  { I }                                              ' serial / programming
      TX1  = 30  { O }                                            
      SDA1 = 29  { I/O }                                            ' i2c / eeprom
      SCL1 = 28  { I/O }
    con { user io }
      NS_PLS = 16                                                   ' pulse to goose N or S movement
      NS_DIR = 15                                                   ' direction 0 (n) or 1 (s)
      EW_PLS = 17                                                   ' pulse to goose E or W movement
      EW_DIR = 18                                                   ' direction 0 (e) or 1 (w)
      ' these inputs should be re-ordered
      ' -- would simplify input scan code
      BTN_N  =  4  { should be 7 }
      BTN_E  =  5  { should be 6 }        
      BTN_S  =  7  { should be 5 }        
      BTN_W  =  3  { should be 4 }        
    con { navigation }
      NORTH = %1000                                                 ' raw input states
      EAST  = %0100
      SOUTH = %0010
      WEST  = %0001
      #0, GO_NORTH, GO_SOUTH                                        ' direction control
      #0, GO_EAST, GO_WEST
      CYCLE_TIX = CLK_FREQ / 100                                    ' run at 100Hz (10ms/loop)
      MOVE = MS_001                                                 ' pulse output is 1ms in 10ms cycle
      STOP = 0
      #true,  ON, OFF 
      #false, NO, YES
      long  nspulse                                                 ' pulse timing (ticks)
      long  ewpulse                                                     
    pub main | t, nav
      t := cnt                                                      ' start loop timing
        nav := scan_nav_buttons(5)
        case nav
          NORTH :
            nspulse := MOVE
            outa[NS_DIR] := GO_NORTH
            ewpulse := STOP
          EAST :
            ewpulse := MOVE
            outa[EW_DIR] := GO_EAST
            nspulse := STOP
          SOUTH :
            nspulse := MOVE
            outa[NS_DIR] := GO_SOUTH
            ewpulse := STOP
          WEST :
            ewpulse := MOVE
            outa[EW_DIR] := GO_WEST
            nspulse := STOP
            longfill(@nspulse, STOP, 2)                             ' stop both
        phsa := -nspulse                                            ' update pulses
        phsb := -ewpulse 
        waitcnt(t += CYCLE_TIX)                                     ' finish loop timing
    pub scan_nav_buttons(ms) : nav | t 
      --nav                                                         ' arm all inputs
      t := cnt
      repeat ms
        waitcnt(t += MS_001)
        nav &= (ina[BTN_N] << 3) | (ina[BTN_E] << 2) | (ina[BTN_S] << 1) | ina[BTN_W]
      Note: If the inputs were contiguous and appropriately ordered, the line above could be
            nav &= ina[BTN_N..BTN_W]
            ...which is cleaner and faster.
    pub setup
    ' reset all pins to input state
      outa := $00000000
      dira := $00000000
    ' configure counters & pins for pulse output
      ctra := %00100 << 26 | NS_PLS                                 ' set for pwm/nco mode              
      frqa := 1                                                     ' highest resolution                                       
      phsa := STOP                                                                                
      dira[NS_PLS] := 1                                             ' make pwm pin output
      dira[NS_DIR] := 1                                             ' make direction control an output
      ctrb := %00100 << 26 | EW_PLS 
      frqb := 1                     
      phsb := STOP                  
      dira[EW_PLS] := 1             
      dira[EW_DIR] := 1             
    con { license }                                                  
      MIT License
      Permission is hereby granted, free of charge, to any person obtaining a copy
      of this software and associated documentation files (the "Software"), to deal
      in the Software without restriction, including without limitation the rights
      to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      copies of the Software, and to permit persons to whom the Software is
      furnished to do so, subject to the following conditions:
      The above copyright notice and this permission notice shall be included in all
      copies or substantial portions of the Software.

  • Ok that takes care of the mount unit but I still have the other which plugs into the mount which I would like to send by serial. It is only one way to the mount. you said that the serial works good . Tell me what you need and I will send.
  • JonnyMacJonnyMac Posts: 6,737
    edited 2020-06-22 - 05:54:18
    I'm not interested in doing any more unpaid consulting on your project.

    There are dozens of threads in these forums covering serial communications; short distance (direct), long distance (RS-485; one of my favorites), and even radio via XBee and other devices(e.g., Bluetooth).
  • Does anyone out there know the link to the fdserial.spin library all i can find is fdserial.c library.
  • Google is your friend. So is git and the relocated obex containing multiple versions of fdserial in spin.
  • I did and all I got was fdserial.c library
  • JonnyMacJonnyMac Posts: 6,737
    edited 2020-06-25 - 18:56:02
    bbrien wrote: »
    Does anyone out there know the link to the fdserial.spin library all i can find is fdserial.c library.
    If you had the decency to actually look at the template archive I provided for you in this thread, you'd see that it contains jm_fullduplexserial.spin which is built from the original FullDuplexSerial.spin (installed in the default library for Propeller Tool). I changed the buffer size (from 16 to 128 bytes) and added several formatting features.
  • I did look at it but I didn't really understand it, I have it in my downloads.
  • I couldn't find anything relating to the fdserial.spin anywhere in the propeller tool ver 1.2.1. I did find something in the project file called home automation but there some questions regarding rx_head and rx_tail . What are they?
  • Where did the filename fdserial.spin come from ?

    Did you just guess that filename ?

    I'm just a bit confused, as earlier you were asking about fdserial.c, (which is C language in SimpleIDE), then you ask about a .spin file (which is SPIN language in PropellerTool).

    Which language are you wanting to use? If both, you need to know that the 2 languages are not interchangeable.

    As Jon mentioned a couple post up, for SPIN code development you want a spin language driver, such as " jm_fullduplexserial.spin " which I think was shared above.
  • This may come as a shock, but for most people it takes more than a quick glance to suss out code written by others. Had you spent ten or 15 minutes -- which seems like small investment considering the years you've been seeking help on your project -- you'd have found that jm_fullduplexserial.spin is, at the core, FullDuplexSerial.spin, just with bigger buffers (I often TX & RX packets that are much bigger than 16 bytes), and with nice formatting features.

    If you're using Propeller Tool, the original FullDuplexSerial.spin is installed in the default library.
  • I found the title in some other posts discussing communication with other devises. I tried to use fdserial .c when I was writing in prop.C Which didn't work.
  • JonnyMacJonnyMac Posts: 6,737
    edited 2020-06-25 - 20:59:30
    I wrote C code for the PixyCam for Parallax. It invokes the simpletools library which invokes the fdserial library. It works fine. BlocklyProp -- a big educational tool for Parallax -- uses fdserial, too.

    While I can write C, I prefer Spin; IMO it's cleaner and easier to code. Serial coms in Spin is very simple; if one understands the issues with serial having nothing to do with the micro employing serial coms.

  • In your CON {pst formatting} what are the lines referencing and what are the numbers about.
  • Jon,

    You should apply for sainthood. Based on the contents of this thread I think you'd have a good chance of getting it.

  • JonnyMacJonnyMac Posts: 6,737
    edited 2020-06-26 - 17:34:30
    In your CON {pst formatting} what are the lines referencing and what are the numbers about.
    PST = Parallax Serial Terminal. Those are control codes for PST. Many are common with other terminals.
  • JonnyMacJonnyMac Posts: 6,737
    edited 2020-06-26 - 04:12:28
    You should apply for sainthood. Based on the contents of this thread I think you'd have a good chance of getting it.
    Thank you for making me LOL, Sandy. I actually did get an offline note from another forum friend about this thread. I'm trying to help, but I'm failing miserably.

  • bbrien,
    Your forum posts on your ill-fated telescope have been excruciating to follow.
    Your request requirements have been stated in unstructured and incomplete snippets.
    There are some seriously competent forum members who are willing to donate their time to help solve your problems, but they cannot suggest solutions when they have poor quality requirements.
    I think many forum members would join me in saying we would like to see your telescope problems solved completely so you can get on with your stargazing.
    May I suggest a reset/recap on your problem.
    Could you provide a series of posts with complete data and requirements.
    You may have provided some of this before, but it would be good to have it in one place in a structured data collection.
    Something like;
    1post with photographs
    1post with equipment details. Electrical schematics and mechanical drawings/sketches
    1 post with desired operating description
    1 post with desired software requirements - inputs, processing and outputs.
    Let us get this telescope working!
  • Good advice @macrobeak

    And may I also suggest to @bbrien that you choose one programming language for this project - so we can remove any confusion that might come from swapping between languages.

    If your not sure yet which language you need, that's ok too, - just let us know when you post the details macrobeak suggested, and from your project description we can start by suggesting the language and tools that would fit best, and then everyone can give advice based on the right target.

    It's understandable (natural and normal even!) that confusion can creep in when you first start out, and are faced with options in a topic you are not yet confident.
    So when you hit those moments of "urgh?", then just take a step back and let us know what doesn't make sense, and we can try to explain things another way.
    But you also need to put in the effort to figure things out too, or you'll never move forward, and you'll find people just can't help you see the stars that way!

    Be organised and methodical, and keep going!

  • These are the photos of the project.
    2560 x 1920 - 1M
    2560 x 1920 - 995K
    2560 x 1920 - 915K
    1152 x 864 - 416K
    1152 x 864 - 425K
  • Equipment details:Devise is a 2008 LX50 Schimdt cassagrain telescope. no hand controller available. also no schematics or programs available. Meade will not release them. so have to duplicate using a different platform. Have tried to use other languages but cannot get the I2C or Serial to work so I'm trying Spin. I have heard that propellers cannot act as slaves so have to use serial. need to use a four pin connector so SPI not usable. schematics are below. Also included are two programs. I cant seem to find my spin files for the slave. I'll code it in later when time permits. Downloadable files are in one of the earlier posts from JM.
  • What produced the SCH files? Can you export to PDF?
  • JonnyMacJonnyMac Posts: 6,737
    edited 2020-06-26 - 20:19:24
    I have heard that propellers cannot act as slaves so have to use serial.
    It's not the norm for the Propeller, but it has been done (not by me -- but I have seen it in the past). They key is understanding the protocol; perhaps the I2C slave the telescope wants to deal with is a standard chip (e.g., an IO expander).

    Maybe you missed these suggestions by @macrobeak
    -- post with desired operating description
    -- post with desired software requirements - inputs, processing and outputs

    I have asked -- several times -- for you to spell out what you want in plain English. Your non-working code is no substitute to a proper specification. Something that I tease my clients with is: The root word of specification is SPECIFIC.

    As humans we have this problem where we assume that if we understand something, everybody understands that thing, so we don't have to go into details. Writing a specification isn't easy, but it has to be done for you to get what you want (trust me, I know, as I was a product manager for a multi-billion dollar corporation). I'm not trying to be unkind, I am trying to help -- your refusal to be forthright with details has caused your project to be extended far longer than necessary.

    You might want to post the schematics as PDFs. I use Diptrace, so I was unable to open your files. You can't count on everyone using the same software, so post in a universal format when possible.

    I live and work in Hollywood (your pictures look like they could have been taken from the hills near DTLA). In the movie, Jerry Maguire, Jerry says to his client, "Help me help you." It's the best line of the movie (though "Show me the money!" is what everyone remembers).
  • Operating description: On the mount board are three inputs(modular jacks), one is a six pin jack for the guide scope camera. It has four opto-isolators (4 directional pins and a common pin ) which can be gnd or +3.3 volts. Four pin jack provides power and 2 lines for serial. The third is a 8 pin mod jack for the encoders which will not be used at this time bugt fills a hole in the cover panel. The program will test (1); Camera controller inputs for active pins. if no pins are active then a small pulse will be delivered to the outputs, there are 2 "M1_EW and Mi_Dir" and if any pins are active pulses will be sent to either M1 group or to M2 group. A total of four output pins.(M2_NS,M2_Dir). In the second cog the serial inputs will be tested for presence of a pulse If there is then a receive buffer will be filled with four longs and then sent to the corresponding output pins which means stopping the first cog and restarting the first cog when the buffers are emptied.
    1152 x 864 - 399K
  • Break it up now. Create, hand draw and stuff it through a scanner/copier if need be, an interconnect diagram and show labeled pin outs for each connector. If possible add a table with the description and expected logic levels for each pin. Software alone is not enough, what one circuit likes could just as well let out the magic smoke in another.

    So as Jon asks, break the project down, existing hardware specifications to the extent known, what you may know of the original controllers functions, what you want your project to do prioritized most to least important to you. Map it out and then try to create each piece on your own. What you learn will make each subsequent function easier to do. Then if something does not work, you can come here, say this is what I tried. It was supposed to do X, but did Y. I then tried Z but no luck. This last will likely get much better assistance since no one will have to reinvent the wheel.
  • This is my current program for the slave;
        _clkmode = xtal1 + pll1x
        _xinfreq = 5_000_000
        M1_EW = 17
        M1_Dir = 18
        M2_NS =  16
        M2_Dir =  15
        BTN_N  =    4
        BTN_E   =    7
        BTN_S   =    5
        BTN_W  =    3
        long pulsewidth
        long cycle_time
        long period
        long cog
        long rx_head
        long rx_tail
        long tx_head
        long tx_tail
        long rx_pin
        long tx_pin
        long rxtx_mode
        long bit_ticks
        long buffer_ptr
        byte rx_buffer[16]      'receive buffer 16 bytes
        byte tx_buffer[16]      'transmit buffer 16 bytes
    PUB   Start(rxPin, txPin, mode, baudrate):ok
          {{Start serial driver - starts a cog
             parameters :  rxPin()
             return: cog #
                        example:  Serial.start((31, 30, %0000, 9_600) }}
          longfill(@rx_head, 0, 4)
          longmove(@rx_Pin, @rxPin, 3)    '?
          bit_ticks := _clkfreq/ baudrate
          buffer_ptr := @rx_buffer
          okay := cog := cognew(@ entry, @rx_head)+1
    PUB  Stop
        if cog
          Cog stop(cog~-1)
          longfill(@rx_head, 0, 9) ' zero out configuration variable
    PUB    RxFlush
        repeat while RxCheck => 0        'call RxCheck until buffer is empty
    PUB    RxCheck: rxByte
        if rx_tail<>rx_head
          rxByte := rx_buffer[rx_tail]
          rx_tail := (rx_tail + 1) & $F
    PUB  RxTime(ms) := rxByte | t
        t := cnt
          repeat until(rxByte := RxCheck) =>0 or(cnt-t)/(_clkfreq/1000) > ms
    PUB   Rx : rxByte
        repeat while  (rxByte := RxCheck) < 0
    PUB  Go
        ctra[30..26] := %00100              'configure counterA for NCO
        ctra[5..0]     := 17                      ' set output pin
        ctrb[14..9]   := 16
        frqa  :=  1
        pulsewidth :=  -5000
        cycle_time  :=  clkfreq/100
        period        := cnt
              phsa         := pulsewidth
              period  := period + cycle_time
              waitcnt := period
    PUB  Scan_buttons
        ' ' Scan direction control buttons
          if(debounce ( BTN_N, 5) == 1)
            return "N"
          if(debounce ( BTN_E, 5) == 1)
            return "E"
          if(debounce ( BTN_S, 5) == 1)
            return "S"
          if(debounce ( BTN_W, 5) ==1)
            return "W" 
            return  0 
    PUB  debounce (pin, ms )
         repeat ms
           if(ina[pin] == 0)
             return  no
           return  yes
    PUB  main | move
           move := Scan_buttons
           case  move
                    motors.set_speed( M2_NS, 25_0)
                     high( M2_Dir)
                    motors.set_speed( M1_EW, 25_0)
                    high( M1_Dir)
                    motors.set_speed( M2_NS, 25_0)
                    low( M2_Dir)
                      motors.set_speed( M1_EW, 25_0)
                      low( M1_Dir)
                      motors.set_speed( M1_EW, STOP)
                      motors.set_speed( M2_NS, STOP)
                      low( M1_Dir)
                      low( M2_Dir)
  • JonnyMacJonnyMac Posts: 6,737
    edited 2020-06-27 - 06:43:15
    This is my current program for the slave;
    That's not a program; it's a collection of bits that you've smashed together, apparently hoping that you'd get lucky.

    Sorry, that's not the way programming works. Your code doesn't compile because you still don't know what you're doing with Spin -- that's not a crime, we all start there.

    What is a crime is your refusal to provide a detailed information of how the circuit should behave. If you do that, one or more of us will show you the code that makes things work, and you can start to get over this steep part of the learning curve that you've been stuck in for a long time.

    Questions that shouldn't have to be asked, but I'm going to....

    1) When no buttons are pressed, what is the state of the outputs?
    2) When the N button is pressed, what is the state of the outputs?
    3) When the E button is pressed, what is the state of the outputs?
    4) When the S button is pressed, what is the state of the outputs?
    5) When the W button is pressed, what is the state of the outputs?
    6) Why are you setting the clock to 5MHz? -- this isn't a battery powered convention badge.
    7) Why is your buttons group not contiguous?
    8) Why are you ripping up working libraries (e.g., FullDuplexSerial) instead of calling them as designed?
  • As you said , I have no idea what I am doing and I have little program experience. I am also 71 years old. (1) if no buttons are pushed their should be only a pulse of approximately 1.5 to 2.0 ms with a period of 28 ms or about 51 Hz. Since the original system operated at 4.0 mega Hz I figure there is a reason like the number of instructions per second. When I tried arduino I could not get a slow enough speed on the motors , and if I used less than 22/255 the motors would not turn. the speed of the processor might be too fast. Using the flip at 5MHz I am able to get about 1.8 ms. I also wrote in prop.C and the input to the second Flip showed a very quick set of pulses but not continuous.
    (2) When the 'N' button is pressed the M2_NS output should read a pulse of 75% and the M2_Dir output should be a HIGH. (3) When the 'E' button is pressed the M1_EW output should show a pulse of 75% and the M1_Dir output should be High.(4) When the 'S' button is pressed, the M2_NS output puts out the 75% pulse and the M2_Dir output sends a Low. (5) When the 'W' button is pressed the M1_EW output sends out a 75% pulse and theM1_Dir output sends a Low.
    (6) the buttons are not contiguous because on the first Flip that was used I had a problem with pin # 6.
    (7) I dont understand ripping up . I saw no need for the Tx group since there is no two way comm. Unless it is needed tor run tests with the terminal.
  • frank freedmanfrank freedman Posts: 1,634
    edited 2020-06-27 - 21:32:00
    The processor speed was likely just a common value for the chip. It's easy enough to set up time intervals as Jon and others have presented in their examples. You could experiment with timing a bit if you would step back and work your way through the prop education manual. At the very least, ch 4,5,6 should be well understood. That would give you a better handle on prop program flow and object use. You can overcome the lack of programming experience only by practice. Build the example code, then fold, spindle and mutilate until you can predict what your code will do and the code behaves as expected. Then you should see faster progress on your main project. I'm guessing you have some hardware background or help since nothing has been fried yet and you have gotten the timing / pulse values somehow.

    edited for spelling failures.
Sign In or Register to comment.