PG Config Flow - GaloisInc/betaflight GitHub Wiki

This document will describe the flow for initializing, reading/writing to flash, and validating the config file. The config file will store the parameter group values for the board. The config file will be stored in presistent memory so it can load config settings of board at every boot.

  1. in init.c - pgReset which eventually calls pgResetInstance pgResetInstance will reset all pg - in the pg template not flash

  2. in init.c - config spi which calls spi init - declares the spi instance, work mode, data bit length, endiannes

  3. in init.c - init flash this will init spi again set spi clk rate

  4. from init function in init.c - will call initEEPROM function in config_eeprom.c

    • a. from initEEPROM in config_eeprom.c call loadEEPROMFromExternalFlash which goes to config_eeprom.c
    • b. read flash from the starting address
      • b.1. return to init.c
  5. from init function in init.c call - will call ensureEEPROMStructureIsValid function in config.c

    • a. from ensureEEPROMStructureIsValid - will call isEEPROMStructureValid in config_eeprom.c
    • b. from isEEPROMStructureValid function in config_eeprom.c - will check if structure is valid then return
      • b.1. it will check structure with comparing generated CRC with stored CRC in config file
    • c. if structure valid, return to init.c
    • d. if structure not valid, retun to config.c to ensureEEPROMStructureIsValid
      • d.1. from ensureEEPROMStructureIsValid in config.c - will call resetEEPROM in config.c
      • d.2. from resetEEPROM in config.c - will call resetConfig which in config.c
      • d.3. from resetConfig in config.c - will call pgResetAll (from step (1))
      • d.4. NOTE some boards use target configs by setting flag USE_TARGET_CONFIG in the /target.h. This will then call /config.c with defined configs (see ALIENFLIGHTF4 example)
        • d.4.1. If USE_TARGET_CONFIG is defined, then call targetConfiguration
        • d.4.2. return to resetEEPROM which goes to config.c
    • e. from resetEEPROM in config.c - will call writeUnmodifiedConfigToEEPROM in config.c
      • e.1. writeUnmodifiedConfigToEEPROM - will call validateAndFixConfig in config.c
        • e.1.1 validateAndFixConfig (is currently commented out)
      • e.2. writeUnmodifiedConfigToEEPROM - will call suspendRxPwmPpmSignal in rx.c
        • e.2.1 which will supend pwm or ppm
      • e.3. writeUnmodifiedConfigToEEPROM will call writeConfigToEEPROM which goes to config_eeprom.c
        • 5.e.3.1 which will call writeSettingsToEEPROM which goes to config_eeprom.c
          • 5.e.3.1.a from config_streamer.c will call config_streamer_init, return to writeSettingsToEEPROM in config_eeprom.c
          • 5.e.3.1.b next, writeSettingsToEEPROM will call config_streamer_start from config_streamer.c, return to writeSettingsToEEPROM
          • 5.e.3.1.c next, writeSettingsToEEPROM will call config_streamer_write from config_streamer.c to write the PG file header to EEPROM
            • 5.e.3.1.c.1 config_streamer_write will call write_word from config_streamer.c
            • 5.e.3.1.c.2 if the RISCV-K210 is the target, write_word will call flash_write_data from flash_riscv_k210.c (this is a Kendryte API function), return to config_streamer_write, then to writeSettingsToEEPROM
          • 5.e.3.1.d writeSettingsToEEPROM will call the macro PG_FOREACH(reg)
            • 5.e.3.1.d.1 Still within writeSettingsToEEPROM, PG_FOREACH(reg) will call config_streamer_write (which then calls write_word and flash_write_data as described in 5.e.3.1.c.1 and 5.e.3.1.c.2). Here, we are invoking the PG_FOREACH(reg) macro to write the individual PGs from flash to EEPROM. After each PG has been processed, return to writeSettingsToEEPROM.
          • 5.e.3.1.e next, writeSettingsToEEPROM will call config_streamer_write again, this time to write the PG file footer to EEPROM, and return to writeSettingsToEEPROM once complete
          • 5.e.3.1.f next, writeSettingsToEEPROM will call config_streamer_write again, to write the inverted CRC in big endian format to EEPROM. Return to return to writeSettingsToEEPROM once complete
          • 5.e.3.1.g writeSettingsToEEPROM will call config_streamer_flush from config_streamer.c
            • 5.e.3.1.g.1 config_streamer_flush calls write_word and flash_write_data as described in 5.e.3.1.c.1 and 5.e.3.1.c.2. Return to writeSettingsToEEPROM once complete
          • 5.e.3.1.h writeSettingsToEEPROM will call config_streamer_finish from config_streamer.c
            • 5.e.3.1.h.1 if the macro CONFIG_IN_EXTERNAL_FLASH is defined (as it is when RISCV-K210 is the target), config_streamer_finish will call flashFlush from flash.c. If all is correct config_streamer_finish should return 0. Return to config_streamer_finish and writeSettingsToEEPROM once complete
          • 5.e.3.1.i Back in writeSettingsToEEPROM, we check if config_streamer_finish returned 0. If so, Success == 1. If not, Success == 0.
          • 5.e.3.1.j If all the above executes correctly writeSettingsToEEPROM will now return Success to writeConfigToEEPROM
        • 5.e.3.2 from writeConfigToEEPROM in config_eeprom.c - will call loadEEPROMFromExternalFlash in config_eeprom.c
          • 5.e.3.2.a from loadEEPROMFromExternalFlash will call flash_read_data from flash_riscv_k210.c (this is a Kendryte API function). Depending on the mode of operation specified (standard, dual, or quad) flash_read_data calls several other API functions: flash_receive_data, flash_receive_data_enhanced, andspi_init. For the purpose of brevity, the entire structure of the function won't be explained in detail. Once the desired flash block has been read, will return to 0 to loadEEPROMFromExternalFlash in the variable 'success'.
          • 5.e.3.2.b then loadEEPROMFromExternalFlash will return the inverse of 'success' to writeConfigToEEPROM
        • 5.e.3.3 finally, writeConfigToEEPROM checks the value of success, and the returns of isEEPROMVersionValid, and isEEPROMStructureValid. If all three are 1, execution will return to writeUnmodifiedConfigToEEPROM in config.c
      • e.4. writeUnmodifiedConfigToEEPROM - will call resumeRxPwmPpmSignal in rx.c
        • e.4.1 which will resume pwm or ppm
      • e.5. return to resetEEPROM in config.c. If all the above has executed correctly, resetEEPROM will return 'true' to ensureEEPROMStructureIsValid in config.c
    • f. from ensureEEPROMStructureIsValid return to from init function in init.c
  6. from init function in init.c call - will call readEEPROM in config.c

    • a. from readEEPROM will call suspendRxPwmPpmSignal from rx.c, which which will supend pwm or ppm, then return
    • b. from readEEPROM will call loadEEPROM from config_eeprom.c. This function initializes all PG records from EEPROM sequentially, scanning EEPROM for each one.
      • b.1. from loadEEPROM will call the macro PG_FOREACH(reg).
        • 6.b.1.1 from PG_FOREACH(reg) will call findEEPROM from config_eeprom.c. This function finds config records reg + classification (profile info) in EEPROM. For each PG findEEPROM will check if it's size is zero, too large, or too small. If the PG has the expected size, findEEPROM will return the PG record to PG_FOREACH. If the PG does not have the expected size, will return NULL.
        • 6.b.1.2 if a PG record was returned, PG_FOREACH attempts to load the PG returned from findEEPROM by calling pgLoad from pg.c
          • 6.b.1.2.a from pgLoad will call pgResetInstance (also in pg.c) then return to pgLoad
          • 6.b.1.2.b next, from pgLoad will call pgVersion and check its return against the expected PG version
          • 6.b.1.2.c if the version numbers match, will call memcpy, and return 'true' to PG_FOREACH. If the version numbers don't match return 'false'.
        • 6.b.1.3 back in PG_FOREACH, it checks the return value from pgLoad. If false, PG_FOREACH sets success = false, then goes to fetch the next PG record
        • 6.b.1.4 if NULL was returned (see 6.b.1.1), will call pgReset from pg.c
          • 6.b.1.4.a pgReset will call pgResetInstance (also in pg.c). After pgResetInstance completes, return to pgReset, return to PG_FOREACH inside loadEEPROM (in config_eeprom.c)
        • 6.b.1.5 after pgReset, will set success = false, then goes to fetch the next PG record
      • b.2 repeat steps 6.b.1.1 - 6.b.1.5 for each PG record in EEPROM
      • b.3 once all PG records have been processed, return success value to readEEPROM
    • c. from readEEPROM will call featureInit from feature.c, then return to readEEPROM
    • d. from readEEPROM will call validateAndFixConfig (is currently commented out), return to readEEPROM
    • e. from readEEPROM will call activateConfig (is currently commented out), return to readEEPROM
    • f. from readEEPROM will call resumeRxPwmPpmSignal from rx.c, which which will resume pwm or ppm, then return to readEEPROM
    • g. from readEEPROM will return success variable (from loadEEPROM), return to init function in init.c
  7. Assign success (returned from readEEPROM) to the bool variable readSuccess.

  8. init function in init.c: if (!readSuccess || !isEEPROMVersionValid() || strncasecmp(systemConfig()->boardIdentifier, TARGET_BOARD_IDENTIFIER, sizeof(TARGET_BOARD_IDENTIFIER)))

⚠️ **GitHub.com Fallback** ⚠️