Welcome to the Pycom forum Forum
    • \[\[global:header.categories\]\]
    • \[\[global:header.recent\]\]
    • \[\[global:header.tags\]\]
    • \[\[global:header.popular\]\]
    • Login

    Explore Pybytes | Official Documentation | Report a Firmware Bug/Issue | GitHub

    Does pulses_get function have a 200 bit limitation when reading?

    Scheduled Pinned Locked Moved Discussion
    49 Posts 5 Posters 5.7k Views 5 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • C Offline
      crumble @Pesien
      last edited by

      @Pesien said in Does pulses_get function have a 200 bit limitation when reading?:

      @robert-hh Any new ideas on why is this happening?

      According to the link from @robert-hh this function is part of an API whicht deals with infrared remote controls. They send/receive usualy only short messages.

      1 Reply Last reply Reply Quote 0
      • robert-hhR Offline
        robert-hh @Pesien
        last edited by robert-hh

        @Pesien No luck with simple hacks. Also machine.RMT offers no better choices. But in documentation there the 128 entry limit is mentioned. I do not know whether this is a limitation of the underlying RTOS or the way the pycom firmware uses it.

        P 2 Replies Last reply Reply Quote 0
        • P Offline
          Pesien @robert-hh
          last edited by

          @robert-hh Then I guess I'll have to try again with interrupts and timers...
          Thank you for your help again, and if you know any better solutions for pulse reading i'd love to hear them.

          1 Reply Last reply Reply Quote 0
          • J Offline
            jcaron @Pesien
            last edited by

            @Pesien According to the documentation, you can configure the UART to use only one pin if you are only receiving. Just state None as the TXD pin and you should be all set.

            robert-hhR 1 Reply Last reply Reply Quote 0
            • robert-hhR Offline
              robert-hh @jcaron
              last edited by

              @jcaron Well, but@Pesien wnat to send AND receive in hald-duplex mode. But it may be possible to switch between send & receive. The only problem would be to find the right time, because the send() returns before the data actually has been transmitted.

              J 1 Reply Last reply Reply Quote 0
              • J Offline
                jcaron @robert-hh
                last edited by

                @robert-hh Ah indeed, had only seen discussion about receiving data, but I now see that the protocol implies data in both directions.

                One may try to give the same pin for both RXD and TXD, maybe? Not sure if the ESP32 would support that. There would probably be "echoing" of sent data if it were the case, though.

                Otherwise the timing issue should be pretty simple. 1200 bits/s, 7 bits, parity, probably one start, one stop, that means 120 characters per second.

                robert-hhR 1 Reply Last reply Reply Quote 0
                • robert-hhR Offline
                  robert-hh @jcaron
                  last edited by robert-hh

                  @jcaron I made a little bit of testing. It seems that you can a single Pin between TX and RX, by re-doing the uart init or instantiation between send and receive with the option pins=(pin, None) and pins=(None, pin) for send and receive. That switch takes 600-800 µs, about 1 bit duration. There are some hiccups involved.

                  • The other side must not send any characters before the switch from TX to RX has happened. Otherwise, the receiver will lock up and will not detect anything for about 3 seconds (maybe 32 characters, t.d.a.).
                  • The Pycom device must wait with switching until all characters have been sent. Otherwise the message will not be sent.

                  So its a little bit of tricky timing, which works best if the sensor is a slow responder. But I read that in SDI-12 the sensor must respond within 15 ms. uart.wait_tx_done() may be appropriate for the wait.

                  J 1 Reply Last reply Reply Quote 0
                  • J Offline
                    jcaron @robert-hh
                    last edited by

                    @robert-hh did you by any chance try to use the same pin for RX and TX? I would be surprised if that worked, but you never know...

                    robert-hhR 2 Replies Last reply Reply Quote 0
                    • robert-hhR Offline
                      robert-hh @jcaron
                      last edited by robert-hh

                      @jcaron Yes. That was indeed the intention of the test - using the same pin for send and receive. To some extent it worked, with a strange glitch:
                      If in the process of switching the pin from send to receive characters for receive arrive too early, the receiver locks up for a while. I could not determine with my simple set-up, whether it locks up for a certain time (2-3 seconds or ~250 character times at 1200 baud) or for some number of characters, which are dropped. My gut feeling says it's the latter, and has something to do with the receive ring buffer. But I did not look into the code yet, and it is surely tricky to make a proper test set-up.

                      J 1 Reply Last reply Reply Quote 0
                      • robert-hhR Offline
                        robert-hh @jcaron
                        last edited by robert-hh

                        @jcaron The test code used for that was;
                        LoPy4 test code:

                        from machine import UART
                        from time import ticks_us, ticks_diff, sleep_ms
                        msg = "cccccccc\n"
                        def run():
                            uart=UART(1, baudrate=1200, pins=("P3", None))
                            sleep_ms(5000)
                            for _ in range (3):
                                uart.write(msg)
                                print(uart.wait_tx_done(int((len(msg) * 8.333)) + 10))
                                uart.init(baudrate=1200, pins=(None, "P3"), timeout_chars=20)
                                print(uart.readline())
                                uart.init(baudrate=1200, pins=("P3", None))
                        
                        run()
                        

                        PC test code (Lopy4 connected to PC with a USB/Serial adapter, both RX and TX of that adapter connected to LoPy P3:

                        import serial
                        
                        ser = serial.Serial("/dev/ttyUSB2", 1200)
                        
                        while (True):
                            while True:
                                line = ser.readline()
                                print(line)
                                if (b"ccc" in line):
                                    break
                            print("Send Echo")
                            ser.write(b"Response\n")
                        

                        Edit: That test code works fine. Trimming is required for the wait time after sending the command.
                        Edit2: Actually it's not that difficult. The specified wait time just has to be long enough, because the call returns as soon as the message has been sent (or after the wait time, if that is earlier).

                        1 Reply Last reply Reply Quote 0
                        • J Offline
                          jcaron @robert-hh
                          last edited by

                          @robert-hh sorry, I meant using the same pin as both TXD and RXD when configuring the UART. Probably not allowed by the internal mux, but you never know.

                          robert-hhR 1 Reply Last reply Reply Quote 0
                          • robert-hhR Offline
                            robert-hh @jcaron
                            last edited by

                            @jcaron I just tried that. Even if you get no error message, no data is sent.

                            1 Reply Last reply Reply Quote 0
                            • P Offline
                              Pesien @robert-hh
                              last edited by Pesien

                              @robert-hh I got it working with time.sleep_us, but I have a new problem. When I read the sensor 6-7 times the timers stop working properly, and the more I read it, the worse it gets. It feels like the timers are not reseting when the board does.
                              However, manually reseting the board or forcing at the end of the code a power reset fixes it.
                              Here is the code, and I'll really appreciate any help you can give me about this problem.
                              (The code works reading the pin every 833 us, which is the duration for 1 bit, and storing the value in a list to translate it later. The timer at the end is not 833 because I had to take into acount the time the chip needs to run the code before it.)

                                      self.pin_unico=Pin(Pin_SDI12, mode=Pin.IN, pull=Pin.PULL_DOWN)
                                      self.lista_bits=[]
                                      self.lista_bytes=[]
                                      while True:
                                          if self.pin_unico()==1:
                                              break
                                      self.lista_bits.append(1)
                                      time.sleep_us(833)
                              
                                      while True:
                                          self.lista_bits.append(self.pin_unico())
                              
                                          if len(self.lista_bits)==10:
                                              if self.lista_bits==[0,0,0,0,0,0,0,0,0,0]:
                                                  #self.lista_bytes.append(self.lista_bits)
                                                  self.lista_bits=[]
                                                  break
                                              else:
                                                  self.lista_bytes.append(self.lista_bits)
                                                  self.lista_bits=[]
                                          time.sleep_us(777)
                              

                              The correct answer for the identification command for this sensor is:
                              013DECAGON MPS-6 386889208069\r\n
                              (I get this the first 6-7 times)
                              Then I get this results:
                              013DECAGON MPS-6 38688920807FSFENQ (7th time)
                              013DECAGON MPS-6 3868[FSYCAN[CANESCFSFENQ (8th time)
                              013DECAGONP&()SYNESCPEM[ESC[[NlLnLMNcB (9th time)

                              And so on. As you can see the reading is incorrect because there is some kind of problem with the timers, but the only way I found to solve this was to power reset the board.

                              robert-hhR 1 Reply Last reply Reply Quote 0
                              • robert-hhR Offline
                                robert-hh @Pesien
                                last edited by robert-hh

                                @Pesien Long long ago i made a UART read by pit probing. As far as I recall, the software:

                                • waited for the start bit transition, and then
                                • probed the value in the middle of the following bit frames.

                                I see no reason why your approach would deviate over time. Expept that the time for append increases. So for the 7 bits of a byte I would preallocate a bytearray of 7 bytes, or just shift that into a single int value. Something like:

                                        EOL = const(0x0a) # end of line
                                        self.lista_bytes=b''
                                        
                                        while True:
                                            bits = 0
                                            while True: # wait for the start bit
                                                if self.pin_unico()==1:
                                                    break
                                            time.sleep_us(1200) # wait for a 1.5 bit times
                                        
                                            for bit in range (8): # get the next 8 bits
                                                bits = (bits << 1) | (1 - self.pin_unico())
                                                time.sleep_us(800) # to be determined, about a bit time
                                            bits >>= 1
                                            self.lista_bytes += bits.to_bytes(1, "little")
                                            if bits == EOL: # maybe \n or 0x0a
                                                break
                                # now msg contains a list of bytes with the response
                                

                                Edit: If the lowest order bit is sent fist, then the inner loop may be:

                                            for bit in range (8): # get the next 8 bits
                                                bits = (bits >> 1) | ((1 - (self.pin_unico()) << 8)
                                                time.sleep_us(800) # to be determined, about a bit time
                                

                                and the shift after the loop can be omitted.

                                P 1 Reply Last reply Reply Quote 0
                                • P Offline
                                  Pesien @robert-hh
                                  last edited by

                                  @robert-hh Thank you. I'll try to preallocate an array of bytes before reading and the 1.5 initial bit time and will update with the results.

                                  robert-hhR 1 Reply Last reply Reply Quote 0
                                  • robert-hhR Offline
                                    robert-hh @Pesien
                                    last edited by robert-hh

                                    @Pesien Yesterday evening I though I coudl try if my test function works and indeed got it working for 1200 baud, 7 data bits. What cause me some time to overcome was a glitch in the firmware, which I will analyze later: you cannot have reliable sleep_us(x) with x > 1000, means, sleep_us() longer than 1 ms. The resulting sleep time is sometimes much shorter. The code below uses a low for mark, when reading form the pin. If you want to adapt it, you have to invert the level. At the moment it also generates reference pulses at P11 to see, if the read timing matches the data stream.
                                    In the target, you would pre-allocate buffer.
                                    Still, using the built-in UARt class with the method discussed below seems more robust to me.

                                    from time import sleep_us, sleep_ms
                                    import gc
                                    from machine import Pin, disable_irq, enable_irq
                                    t = Pin("P11", Pin.OUT)
                                    t(1)
                                    pin = Pin("P9", Pin.IN)
                                    
                                    
                                    def read_ser(pin_unico):
                                        EOL = const(0x0d)  # maybe \n or \r
                                        buffer = bytearray(100)
                                        buffer_size = len(buffer)
                                        bytes = 0
                                        gc.collect()
                                    
                                        while True:
                                            bits = 0
                                            while True:  # wait for the start bit
                                                if pin_unico() == 0:
                                                    break
                                            sleep_us(390)  # wait for a 1.5 bit times
                                            sleep_us(390)  # since there is a bug for wait time > 1 ms
                                            sleep_us(390)  # three shorter sleeps are used.
                                    
                                            for bit in range(7):  # get the next 7 bits
                                                bits = (bits >> 1) | (pin_unico() << 7)
                                                t(0)
                                                sleep_us(20)
                                                t(1)
                                                sleep_us(780)  # to be determined, about a bit time
                                            bits >>= 1
                                            bits &= 0x7f
                                            # print(hex(bits), chr(bits))
                                            buffer[bytes] = bits
                                            bytes += 1
                                            if bits == EOL or bytes >= buffer_size:
                                                return buffer[:bytes]
                                    # now msg contains a list of bytes with the response
                                    
                                    P 1 Reply Last reply Reply Quote 0
                                    • P Offline
                                      Pesien @robert-hh
                                      last edited by

                                      @robert-hh I'm afraid I am not able to make your code work. The SDI-12 sensors have 10 bits/byte, and the 7 data bits are in inverted USASCII code. You also have the starting high bit, the parity bit and the (low) ending bit.
                                      Trying to adapt your code to these settings has failed, probably because of my own inexperience and the fact that I don't know what some of the things there do, but it might be because of the inverted 7 data bits.
                                      I'll keep trying.

                                      robert-hhR 2 Replies Last reply Reply Quote 0
                                      • robert-hhR Offline
                                        robert-hh @Pesien
                                        last edited by

                                        @Pesien The 10 bits are 1 start, 7 data, 1 parity, 1 stop.
                                        my code ignores the start bit (the initial delay skips it) and the parity & stop bit. The latter should always be ignored, to get more time to store the data. Adapting to the reverse polarity and parity should be like the code below. But I will try this evening with reverse polarity.

                                        from time import sleep_us, sleep_ms
                                        import gc
                                        from machine import Pin, disable_irq, enable_irq
                                        t = Pin("P11", Pin.OUT)
                                        t(1)
                                        pin = Pin("P9", Pin.IN)
                                        
                                        
                                        def read_ser(pin_unico):
                                            EOL = const(0x0d)  # maybe \n or \r
                                            buffer = bytearray(100)
                                            buffer_size = len(buffer)
                                            bytes = 0
                                            gc.collect()
                                        
                                            while True:
                                                bits = 0
                                                while True:  # wait for the start bit
                                                    if pin_unico() == 1:
                                                        break
                                                sleep_us(390)  # wait for a 1.5 bit times
                                                sleep_us(390)  # since there is a bug for wait time > 1 ms
                                                sleep_us(390)  # three shorter sleeps are used.
                                        
                                                for bit in range(8):  # get the next 8 bits including parity
                                                    bits = (bits >> 1) | ((1 - pin_unico()) << 8)
                                                    t(0)
                                                    sleep_us(20)
                                                    t(1)
                                                    sleep_us(780)  # to be determined, about a bit time
                                                bits >>= 1
                                                bits &= 0x7f # strip off parity
                                                # print(hex(bits), chr(bits))
                                                buffer[bytes] = bits
                                                bytes += 1
                                                if bits == EOL or bytes >= buffer_size:
                                                    return buffer[:bytes]
                                        # now msg contains a list of bytes with the response
                                        
                                        1 Reply Last reply Reply Quote 0
                                        • robert-hhR Offline
                                          robert-hh @Pesien
                                          last edited by

                                          @Pesien I wonder why you tell that the data is inverted. From the SDI12 spec I cannot tell that it is. But besides that, the spec is not very detailed about that topic, and I have no real unit for testing.

                                          P 1 Reply Last reply Reply Quote 0
                                          • P Offline
                                            Pesien @robert-hh
                                            last edited by Pesien

                                            @robert-hh I have seen it with an oscilloscope. The sensor returns the data as I said in my last post.
                                            Edit: In order to translate the pulses into characters, I created my own dictionary with all the characters, so translation is not needed, only pulse storage.

                                            robert-hhR 1 Reply Last reply Reply Quote 0

                                            Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                                            Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                                            With your input, this post could be even better 💗

                                            Register Login
                                            • 1
                                            • 2
                                            • 3
                                            • 2 / 3
                                            • First post
                                              Last post

                                            Pycom on Twitter

                                            Pycom