This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F28379D: TMS320F28379D & S : Flash API works on initial run (Debug and Flash), but not after reset.

Part Number: TMS320F28379D
Other Parts Discussed in Thread: TMS320F28379S, LAUNCHXL-F28379D

Hello,

I'm working on a bootloader for the TMS320F28379D and TMS320F28379S. It's working perfectly just after the first startup of the code. But after a single reset, the FlashAPI doesn't work anymore.

For example I try to do an erase and most of the time, when I run Fapi_getFsmStatus(), I get incomprehensive status like : 0x0810 or 0x0C10.

I've tried to investigate everywhere in my code but I seems to be properly configured. I couldn't manage to make it work. I've read multiple requests from the support, but they are for older version MCUs and even with trying their solutions it didn't work.

Links to the other requests I've found on the forum :- https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/641261/compiler-tms320f28075-flash-api-works-on-initial-run-but-not-after-reset- https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1074143/tms320f28377d-flash-api-works-on-initial-run-but-not-after-cpu-reset

Could you help me? Thank you in advance.

Bastien

  • Hello Bastien,

    1. Are you able to share the code you are using to initialize the flash API?

    2. Does your code match the initialization sequence shown in the flash programming example for this device?

    3. Have you ensured that this code is running from RAM?

    4. Is the FMSTAT value returned from Fapi_getFsmStatus() consistent or random?

    Best,

    Alex

  • Hello Alex,

    1. Here is an extract of my code to do an erase. It's working perfectly when run the first time. (For clarity, the code is designed to work with both single-core and dual-core TMS processors, so part of the code is not used with definitions that depend on the microcontroller. I did not download everything in order to make the code more readable).

    /* F2837xD specific includes for F28379D */
    #include "F2837xD_device.h"
    #include "F2837xD_Examples.h"
    /* F021 Flash API for F2837xD */
    #include "F021_F2837xD_C28x.h"
    #include "Constants/Constants.h"
    
    /****************************** Local Constants ******************************/
    /* F2837x Flash configuration */
    #define BL_F2837X_FLASH_BASE 0x80000UL          /**< Flash memory base address */
    #define BL_F2837X_LAST_SECTOR_SIZE_WORDS 2000UL /**< Last sector size in 32-bit words (8 KB) */
    
    #ifdef BL_TARGET_F2837XD
    #define BL_F2837X_NUM_SECTORS 14u /**< Number of flash sectors */
    #else
    #define BL_F2837X_NUM_SECTORS 28u                  /**< Number of flash sectors */
    #define PUMPREQUEST *(unsigned long *)(0x00050024) /**< Flash pump request register */
    #endif
    
    #define DEBUG 5
    
    /******************************** Local Macros *******************************/
    #if defined(__TI_COMPILER_VERSION__)
    #pragma CODE_SECTION(bl_flash_erase_sector, ".TI.ramfunc")
    #pragma CODE_SECTION(bl_flash_program, ".TI.ramfunc")
    #pragma CODE_SECTION(bl_flash_verify, ".TI.ramfunc")
    #pragma CODE_SECTION(bl_flash_activate_bank, ".TI.ramfunc")
    #pragma CODE_SECTION(bl_flash_init_bank0, ".TI.ramfunc")
    #pragma CODE_SECTION(bl_flash_init_bank1, ".TI.ramfunc")
    #pragma CODE_SECTION(bl_flash_get_sector_from_addr, ".TI.ramfunc")
    #endif
    
    /****************************** Local Variables *******************************/
    static uint32_t g_flash_fail_addr = 0;     /**< Last failed flash address */
    static uint16_t g_flash_expected_data = 0; /**< Expected data for failed operation */
    static uint16_t g_flash_actual_data = 0;   /**< Actual data read from failed operation */
    #if DEBUG == 1
    static Fapi_StatusType g_flash_api_status = Fapi_Status_Success; /**< Last Flash API status */
    #endif
    static int16_t g_flash_api_initialized = -1; /**< Flag: -1 if not initialized, 0 if Flash API bank 0 is initialized, 1 if Flash API bank 1 is initialized */
    Fapi_FlashBankSectorsType sectorTypes;       /**< Flash sector types structure */
    const uint32_t sectorsAddr[BL_F2837X_NUM_SECTORS] = {
        0x00080000,
        0x00082000,
        0x00084000,
        0x00086000,
        0x00088000,
        0x00090000,
        0x00098000,
        0x000A0000,
        0x000A8000,
        0x000B0000,
        0x000B8000,
        0x000BA000,
        0x000BC000,
        0x000BE000,
    };
    
    /************************* Local functions declaration ************************/
    uint16_t bl_flash_activate_bank(uint16_t sectorId);
    uint16_t bl_flash_init_bank0(void);
    uint16_t bl_flash_init_bank1(void);
    uint16_t bl_flash_get_sector_from_addr(uint32_t addr);
    static uint32_t bl_flash_get_sector_size_words(uint16_t sector_id);
    
    /************************* Local functions definition *************************/
    /*******************************************************************************
     * \brief Activate proper bank if needed before flash operations
     * \param sectorId Sector ID to be accessed
     * \return Fapi_Status_Success on success, error code otherwise
     ******************************************************************************/
    uint16_t bl_flash_activate_bank(uint16_t sectorId)
    {
        uint16_t status;
    
    #ifdef BL_TARGET_F2837XD
        if (g_flash_api_initialized != 0)
        {
            SeizeFlashPump(); // Ensure we have pump ownership
    
            status = bl_flash_init_bank0();
            if (status != 0)
            {
                return status; /* Error initializing bank */
            }
        }
    #else
    
        if (sectorId < 14) // if in bank 0 (sector 0-13)
        {
            if (g_flash_api_initialized != 0)
            {
                /* Switch to bank 0 */
                status = bl_flash_init_bank0();
                if (status != 0)
                {
                    return status; /* Error initializing bank 0 */
                }
            }
        }
        else // if in bank 1 (sector 14-27)
        {
            if (g_flash_api_initialized != 1)
            {
                /* Switch to bank 1 */
                status = bl_flash_init_bank1();
                if (status != 0)
                {
                    return status; /* Error initializing bank 1 */
                }
            }
        }
    #endif
        return 0; /* Success */
    }
    
    /*******************************************************************************
     * \brief Initialize Flash API for bank 0
     * \return 0 on success, non-zero on error
     *
     * \note This function should be called once when entering bootloader mode
     ******************************************************************************/
    uint16_t bl_flash_init_bank0(void)
    {
    #ifdef INCLUDE_F2837X_HEADERS
        Fapi_StatusType status;
        uint16_t sysclk_mhz = SYSCLK_HZ / 1000000u;
    
        /* Check if already initialized */
        if (g_flash_api_initialized == 0)
        {
            return 0; /* Already initialized */
        }
    
        EALLOW;
    
    /* === Initialize Flash API for bank 0 === */
    #ifdef BL_TARGET_F2837XD
        status = Fapi_initializeAPI(F021_CPU0_BASE_ADDRESS, sysclk_mhz);
    #else
        // Give pump ownership to FMC0(Bank0)
        PUMPREQUEST = 0x5A5A0002;
        status = Fapi_initializeAPI(F021_CPU0_W0_BASE_ADDRESS, sysclk_mhz);
    #endif
    
        if (status != Fapi_Status_Success)
        {
    #if DEBUG == 1
            g_flash_api_status = status;
    #endif
            return 1; /* Error */
        }
    
        /* Add small delay for Flash pump stabilization after POR */
        bl_hw_delay_us(1000); /* 1ms delay */
    
    #if !defined(BL_TARGET_F2837XD)
        // Fapi_setActiveFlashBank function sets the Flash bank0 and FMC0 for
        // further Flash operations to be performed on the bank0.
        // Note that the parameter passed is Fapi_FlashBank0 since FMC0 register
        // base address is passed to Fapi_initializeAPI()
        EALLOW;
        status = Fapi_setActiveFlashBank(Fapi_FlashBank0);
        EDIS;
        if (status != Fapi_Status_Success)
        {
    #if DEBUG == 1
            g_flash_api_status = status;
    #endif
            return 2; /* Error */
        }
    #endif
        EDIS;
    
        /* Mark as initialized */
        g_flash_api_initialized = 0;
    
        return 0; /* Success */
    #else
        g_flash_api_initialized = 0; /* Mark as initialized for stub */
        return 0;                    /* Stub: always succeed */
    #endif
    }
    
    /*******************************************************************************
     * \brief Initialize Flash API for bank 1
     * \return 0 on success, non-zero on error
     *
     * \note This function should be called once when entering bootloader mode
     ******************************************************************************/
    uint16_t bl_flash_init_bank1(void)
    {
    #ifdef INCLUDE_F2837X_HEADERS
        /* Check if already initialized */
        if (g_flash_api_initialized == 1)
        {
            return 0; /* Already initialized */
        }
    
        EALLOW;
    
    /* === Initialize Flash API for bank 1 === */
    #ifdef BL_TARGET_F2837XD
        return 1; // Always error: F2837xD has single bank
    #else
        Fapi_StatusType status;
        uint16_t sysclk_mhz = SYSCLK_HZ / 1000000u;
    
        // Give pump ownership to FMC1(Bank1)
        PUMPREQUEST = 0x5A5A0001;
        status = Fapi_initializeAPI(F021_CPU0_W1_BASE_ADDRESS, sysclk_mhz);
        if (status != Fapi_Status_Success)
        {
    #if DEBUG == 1
            g_flash_api_status = status;
    #endif
            return 1; /* Error */
        }
    
        // Fapi_setActiveFlashBank function sets the Flash bank0 and FMC0 for
        // further Flash operations to be performed on the bank0.
        // Note that the parameter passed is Fapi_FlashBank0 since FMC0 register
        // base address is passed to Fapi_initializeAPI()
        //
        EALLOW;
        status = Fapi_setActiveFlashBank(Fapi_FlashBank1);
        EDIS;
        if (status != Fapi_Status_Success)
        {
    #if DEBUG == 1
            g_flash_api_status = status;
    #endif
            return 2; /* Error */
        }
        EDIS;
    
        /* Mark as initialized */
        g_flash_api_initialized = 1;
    
        return Fapi_Status_Success; /* Success */
    #endif
    #else
        g_flash_api_initialized = 1; /* Mark as initialized for stub */
        return 0;                    /* Stub: always succeed */
    #endif
    }
    
    /*******************************************************************************
     * \brief Get sector ID from flash address
     * \param addr Flash address to check
     * \return Sector ID (0-27) or 0xFF if address is invalid/out of range
     ******************************************************************************/
    uint16_t bl_flash_get_sector_from_addr(uint32_t addr)
    {
        uint16_t i;
    
        /* Check if address is below flash range */
        if (addr < sectorsAddr[0])
        {
            return 0xFF; /* Address below flash range */
        }
    
        /* Find the sector containing this address */
        for (i = 0; i < (BL_F2837X_NUM_SECTORS - 1); i++)
        {
            /* Check if address is in current sector */
            if (addr >= sectorsAddr[i] && addr < sectorsAddr[i + 1])
            {
                return i;
            }
        }
    
        /* Check if address is in the last sector */
        if (addr >= sectorsAddr[BL_F2837X_NUM_SECTORS - 1] &&
            addr < (sectorsAddr[BL_F2837X_NUM_SECTORS - 1] + BL_F2837X_LAST_SECTOR_SIZE_WORDS))
        {
            return (BL_F2837X_NUM_SECTORS - 1); /* Last sector (27) */
        }
    
        return 0xFF; /* Address out of flash range */
    }
    
    /*******************************************************************************
     * \brief Get sector size (in 16-bit words) for the requested sector ID
     * \param sector_id Sector index
     * \return Sector size expressed in 16-bit words (0 if invalid sector)
     ******************************************************************************/
    static uint32_t bl_flash_get_sector_size_words(uint16_t sector_id)
    {
        if (sector_id >= BL_F2837X_NUM_SECTORS)
        {
            return 0UL;
        }
    
        if (sector_id < (BL_F2837X_NUM_SECTORS - 1U))
        {
            return sectorsAddr[sector_id + 1U] - sectorsAddr[sector_id];
        }
    
        return BL_F2837X_LAST_SECTOR_SIZE_WORDS;
    }
    
    /*************************** Public Functions **********************************/
    /*******************************************************************************
     * \brief Erase flash sectors based on sector mask
     * \param sector_mask Bit mask of sectors to erase (bit 0 = sector 0, etc.)
     * \return 0 on success, 1 for invalid sectors, 2+ for flash API errors
     ******************************************************************************/
    uint16_t bl_flash_erase_sector(uint32_t sector_mask)
    {
        /* Validate sector mask */
        if (sector_mask == 0)
        {
            return 1; /* Invalid: no sectors specified */
        }
    
        /* Reject sector 0 (bootloader protection) */
        if (sector_mask & 0x0001)
        {
            return 1; /* Invalid: sector 0 is protected */
        }
    
    #ifdef INCLUDE_F2837X_HEADERS
        Fapi_StatusType status;
        Fapi_FlashStatusType flashStatus;
        Fapi_FlashStatusWordType oFlashStatusWord;
        uint16_t sector_bit;
        uint32_t sector_addr;
    
        uint32_t sector_length_words; /* Sector length in 32-bit words */
    
        /* Erase each selected sector */
        for (sector_bit = 1; sector_bit < BL_F2837X_NUM_SECTORS; sector_bit++)
        {
            if (bl_flash_activate_bank(sector_bit) != Fapi_Status_Success) // Verify and activate proper bank
            {
                return 3; /* Error activating bank */
            }
    
    #ifdef BL_TARGET_F2837XD
            // F2837xD has single bank, no need to switch banks
            EALLOW;
            /* Enable Flash sector erase */
            Fapi_initializeAPI(F021_CPU0_BASE_ADDRESS, SYSCLK_HZ / 1000000u);
            EDIS;
    #else
            // F2837xS: switch to proper bank
            EALLOW;
            Fapi_initializeAPI((sector_bit < 14) ? F021_CPU0_W0_BASE_ADDRESS : F021_CPU0_W1_BASE_ADDRESS,
                               SYSCLK_HZ / 1000000u);
            EDIS;
            EALLOW;
            Fapi_setActiveFlashBank((sector_bit < 14) ? Fapi_FlashBank0 : Fapi_FlashBank1);
            EDIS;
    #endif
    
            if (sector_mask & (1u << sector_bit)) //
            {
                sector_addr = sectorsAddr[sector_bit];
    
                /* dummy call to unsecure zone as suggested by TI documentation */
                /* Read sector to ensure it's unsecure (CSM zone) before erasing */
                volatile uint16_t dummy_read = *(volatile uint16_t *)sector_addr + 0x10;
                (void)dummy_read; /* Avoid unused variable warning */
    
                EALLOW;
                /* Erase the sector */
                status = Fapi_issueAsyncCommandWithAddress(Fapi_EraseSector,
                                                           (uint32 *)sector_addr);
    
                /* Wait for completion */
                while (Fapi_checkFsmForReady() != Fapi_Status_FsmReady)
                {
                    /* Wait for FSM ready */
                }
                EDIS;
    
                if (status != Fapi_Status_Success)
                {
    #if DEBUG == 1
                    g_flash_api_status = status;
                    g_flash_fail_addr = sector_addr;
    #endif
                    return 4; /* Erase error */
                }
    
                /* Read contents to know the status of FSM after erase command to see
                 if there are any erase operation related errors */
                flashStatus = Fapi_getFsmStatus();
    
                /* Wait for FSM to be ready if busy */
                while ((flashStatus & (1 << 6)) != 0) /* Wait until FSM is not busy */
                {
                    flashStatus = Fapi_getFsmStatus();
                }
    
                /* Clear any error flags if needed */
                if ((flashStatus & 0x0020) != 0) /* Check for ECC error flag (bit 5) */
                {
                    Fapi_issueAsyncCommand(Fapi_ClearMore);
                    flashStatus = Fapi_getFsmStatus(); /* Re-read status after clearing */
                }
    
                /* Check for any remaining error flags */
                if (flashStatus != 0)
                {
    #if DEBUG == 5
                    g_flash_fail_addr = sector_addr;
                    g_flash_actual_data = flashStatus;
    #endif
                    return 5; /* Erase error */
                }
    
                /* Determine sector size using next boundary or fixed length for the last sector */
                sector_length_words = bl_flash_get_sector_size_words(sector_bit) / 2; /* Fapi_doBlankCheck expects 32-bit words */
    
                // Verify that the sector is erased.
                status = Fapi_doBlankCheck((uint32 *)sector_addr, sector_length_words, &oFlashStatusWord);
                if (status != Fapi_Status_Success)
                {
    #if DEBUG == 1
                    g_flash_api_status = status;
                    g_flash_fail_addr = sector_addr;
    #endif
                    return status; /* Erase error */
                }
            }
        }
        return Fapi_Status_Success; /* Success */
    #else
        (void)sector_mask; /* Avoid unused parameter warning */
        return 0;          /* Stub: always succeed */
    #endif
    }
    

    2. I followed the example in the TI documentation : SPNU629A & SPNU630A

    3. Yes, you'll find all the pragma at the beginning of my code. And the copy to RAM is done at the beginning of my main.

    4. When it's working, it's persistent and always working. But after a reset, for 90% of the time it returns 0x0810 and the other 10% 0x0C10.

    Also I'm testing my code on the LAUNCHXL-F28379D.

    Thank you for your concern.

  • Bastien,

    I'm looking into this a bit farther, when calling Fapi_setActiveFlashBank, you should always use Fapi_FlashBank0 as per the TMS320F2837xD Flash API Version 1.54 Reference Guide (section 3.2.1). Can you try making this change?

    Best,

    Alex

  • I've tried it and it works. Now I can reset and the FlashAPI still works.
    Thank you very much!