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

    Advice to speed up write to SD card file - Datalogger

    Scheduled Pinned Locked Moved Discussion
    4 Posts 3 Posters 68 Views 3 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.
    • J Offline
      JSmith
      last edited by

      Hello,

      My Wipy 3.0 with expansion board V3.1 has a datalogger mode in its use case, whereby I append/write ~32 class object attributes/variables to a csv file at a frequency that I can choose (im using an interrupt to do this).

      I ideally want the logging frequency to be as good as 100Hz (10ms between writes), but I am finding it takes 100ms to write the data, with my current write to file strategy.

      Below is the existing code:

      def log(alarm):
          global last_time_ms
          if sd_mounted:
              if data_file_version == 0:
                  setup_log_file()
                  last_time_ms = chrono3.read_ms()
              timenow_ms = chrono3.read_ms()
              timenow_s = timenow_ms/1000
      
              ADC_mV_str = ",".join(str(inst.mV_val_WMAfilt) for inst in ADCInput._ADCregistry[1:])
              ADC_engval_str = ",".join(str(inst.engineering_val) for inst in ADCInput._ADCregistry[1:])
              Output_str = ",".join(str(inst.desired_duty_perc) for inst in output_class._Outregistry[1:])
              CAN_str = ",".join(str(inst.engineering_value) for inst in CANSPN._registry[0:])
      
              with open('/sd/data_log_%s.csv' % data_file_version,'a') as f:
                  f.write(str(timenow_ms)+","+str(timenow_s)+","+str(timenow_ms-last_time_ms)+","+ADC_mV_str+","+ADC_engval_str+","+Output_str+","+CAN_str +"\n")
              #print("logged dT: ", str(timenow_ms-last_time_ms))
              last_time_ms = timenow_ms
          else:
              print("cannot log data, SD card not mounted succesfully on boot!")
      

      As you can see I open the file at each interval in append mode, and write in the new variable string set.

      Can anyone suggest a faster alternative (e.g. writing to the flash?, or simply adding the new string to a massive/accumulating string which I then write to the card periodically?, or just keeping the file open instead of opening each time I want to log?)

      Im a novice so my current solution maybe slow, but I do like simply appending to a pre-existing file since the data is safe if the device were to malfunction or loose power.

      Many thanks

      robert-hhR 1 Reply Last reply Reply Quote 0
      • C Offline
        claus
        last edited by

        I would probably try to write the data into a memory queue from the main thread and have a separate thread that regularily checks the queue and writes everything it finds to the sd, removing the saved items from the queue. You will have to use locking on the queue to avoid race conditions though.

        A simpler option would be to wait for a good number of data to accumulate and write every 10/100 steps or so to the disk. This probably will not take much longer than writing a single row.

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

          @JSmith Do not open & close the file all the time. That takes a lot of time. Keeping the file open has obviously the risk of loosing data in case of a fatal error. But at least exceptions could be covered, such that the file is closed when it happens.
          Buffering is already done by the FAT library, so you do not have to do that.

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

            @robert-hh thanks for your suggestion. I have attempted to improve the minimum sapling frequency, by keeping the file open if the desired sampling freq < 100ms. Unfortunately, if I set the delta time to 50ms (updating the interrupt in via a IOT feed) the time between samples is still excessive at 90ms.

            If I comment out the write operation so that the function isnt actually writing to sd, then the min delta T becomes 65ms (still long). I have found however that the bulk of this is due to the time to collect the variables (28 class attributes) and the convert to strings & concatenate.

            def log(dTms):
                global last_time_ms
                global file_open_status
                global f
                if sd_mounted:
                    if data_file_version == 0:
                        setup_log_file()
                        last_time_ms = chrono3.read_ms()
                    timenow_ms = chrono3.read_ms()
                    timenow_s = timenow_ms/1000
            
                    ADC_mV_str = ",".join(str(inst.mV_val_WMAfilt) for inst in ADCInput._ADCregistry[1:])
                    ADC_engval_str = ",".join(str(inst.engineering_val) for inst in ADCInput._ADCregistry[1:])
                    Output_str = ",".join(str(inst.desired_duty_perc) for inst in output_class._Outregistry[1:])
                    CAN_str = ",".join(str(inst.engineering_value) for inst in CANSPN._registry[0:])
            
                    if dTms >= 100:                                                                 # non-volatile mode if samp freq <10Hz (closes file each time)
                        if file_open_status:
                            f.close                                                                 # this closes the file as switching from high samp freq to slow/non volatile mode
                            file_open_status = False
                        with open('/sd/data_log_%s.csv' % data_file_version,'a') as f:
                            f.write(str(timenow_ms)+","+str(timenow_s)+","+str(timenow_ms-last_time_ms)+","+ADC_mV_str+","+ADC_engval_str+","+Output_str+","+CAN_str +"\n")
                    else:                                                                           # volatile mode which keeps file open between logs in high freq use cases
                        if not file_open_status:
                            f = open('/sd/data_log_%s.csv' % data_file_version,'a')
                            file_open_status = True
                        f.write(str(timenow_ms)+","+str(timenow_s)+","+str(timenow_ms-last_time_ms)+","+ADC_mV_str+","+ADC_engval_str+","+Output_str+","+CAN_str +"\n")
                    print(str(timenow_ms-last_time_ms))
                    last_time_ms = timenow_ms
                else:
                    print("cannot log data, SD card not mounted succesfully on boot!")
            

            Could you advise if my approach of collecting my variables from class instance attributes from other modules is slow practice? I cannot see a more suitable approach since I want to access many variables within multiple modules.

            Kind regards

            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 / 1
            • First post
              Last post

            Pycom on Twitter

            Pycom