/************************************************************************************//** ** \brief Copies data from the source to the destination address. ** \param dest Destination address for the data. ** \param src Source address of the data. ** \param len length of the data in bytes. ** \return none. ** ****************************************************************************************/ void CpuMemCopy(blt_addr dest, blt_addr src, blt_int16u len) { blt_int8u *from, *to; /* set casted pointers */ from = (blt_int8u *)src; to = (blt_int8u *)dest; /* copy all bytes from source address to destination address */ while(len-- > 0) { /* store byte value from source to destination */ *to++ = *from++; /* keep the watchdog happy */ CopService(); } } /*** end of CpuMemCopy ***/
/************************************************************************************//** ** \brief Determines the flash sector base address. ** \param sector Sector to get the base address of. ** \return Flash sector base address or FLASH_INVALID_ADDRESS. ** ****************************************************************************************/ static blt_addr FlashGetSectorBaseAddr(blt_int8u sector) { blt_int8u sectorIdx; /* search through the sectors to find the right one */ for (sectorIdx = 0; sectorIdx < FLASH_TOTAL_SECTORS; sectorIdx++) { /* keep the watchdog happy */ CopService(); if (flashLayout[sectorIdx].sector_num == sector) { return flashLayout[sectorIdx].sector_start; } } /* still here so no valid sector found */ return FLASH_INVALID_ADDRESS; } /*** end of FlashGetSectorBaseAddr ***/
/************************************************************************************//** ** \brief Transmits a communication interface byte. ** \param data Value of byte that is to be transmitted. ** \return BLT_TRUE if the byte was transmitted, BLT_FALSE otherwise. ** ****************************************************************************************/ static blt_bool UartTransmitByte(blt_int8u data) { /* check if tx holding register can accept new data */ if ((U0LSR & UART_THRE) == 0) { /* UART not ready. should not happen */ return BLT_FALSE; } /* write byte to transmit holding register */ U0THR = data; /* wait for tx holding register to be empty */ while((U0LSR & UART_THRE) == 0) { /* keep the watchdog happy */ CopService(); } /* byte transmitted */ return BLT_TRUE; } /*** end of UartTransmitByte ***/
/************************************************************************************//** ** \brief Determines the flash sector the address is in. ** \param address Address in the flash sector. ** \return Flash sector number or FLASH_INVALID_SECTOR. ** ****************************************************************************************/ static blt_int8u FlashGetSector(blt_addr address) { blt_int8u sectorIdx; /* search through the sectors to find the right one */ for (sectorIdx = 0; sectorIdx < FLASH_TOTAL_SECTORS; sectorIdx++) { /* keep the watchdog happy */ CopService(); /* is the address in this sector? */ if ( (address >= flashLayout[sectorIdx].sector_start) && \ (address < (flashLayout[sectorIdx].sector_start + \ flashLayout[sectorIdx].sector_size)) ) { /* return the sector number */ return flashLayout[sectorIdx].sector_num; } } /* still here so no valid sector found */ return FLASH_INVALID_SECTOR; } /*** end of FlashGetSector ***/
/************************************************************************************//** ** \brief Transmits a packet formatted for the communication interface. ** \param data Pointer to byte array with data that it to be transmitted. ** \param len Number of bytes that are to be transmitted. ** \return none. ** ****************************************************************************************/ void UartTransmitPacket(blt_int8u *data, blt_int8u len) { blt_int16u data_index; blt_bool result; /* verify validity of the len-paramenter */ ASSERT_RT(len <= BOOT_COM_UART_TX_MAX_DATA); /* first transmit the length of the packet */ result = UartTransmitByte(len); ASSERT_RT(result == BLT_TRUE); /* transmit all the packet bytes one-by-one */ for (data_index = 0; data_index < len; data_index++) { /* keep the watchdog happy */ CopService(); /* write byte */ result = UartTransmitByte(data[data_index]); ASSERT_RT(result == BLT_TRUE); } } /*** end of UartTransmitPacket ***/
/************************************************************************************//** ** \brief Programs FLASH_WRITE_BLOCK_SIZE bytes to flash from the block->data ** array. ** \param block Pointer to flash block info structure to operate on. ** \return BLT_TRUE if successful, BLT_FALSE otherwise. ** ****************************************************************************************/ static blt_bool FlashWriteBlock(tFlashBlockInfo *block) { blt_int8u sector_num; blt_bool result = BLT_TRUE; blt_addr prog_addr; blt_int32u prog_data; blt_int32u word_cnt; /* check that address is actually within flash */ sector_num = FlashGetSector(block->base_addr); if (sector_num == FLASH_INVALID_SECTOR) { return BLT_FALSE; } /* program all words in the block one by one */ for (word_cnt=0; word_cnt<(FLASH_WRITE_BLOCK_SIZE/sizeof(blt_int32u)); word_cnt++) { prog_addr = block->base_addr + (word_cnt * sizeof(blt_int32u)); prog_data = *(volatile blt_int32u*)(&block->data[word_cnt * sizeof(blt_int32u)]); /* keep the watchdog happy */ CopService(); /* program the word to flash */ if (FlashLibProgram((uint32_t *)&prog_data, prog_addr, sizeof(blt_int32u)) != 0) { result = BLT_FALSE; break; } /* verify that the written data is actually there */ if (*(volatile blt_int32u*)prog_addr != prog_data) { result = BLT_FALSE; break; } } /* still here so all is okay */ return result; } /*** end of FlashWriteBlock ***/
/************************************************************************************//** ** \brief Erases the flash sectors from first_sector up until last_sector. ** \param first_sector First flash sector number. ** \param last_sector Last flash sector number. ** \return BLT_TRUE if successful, BLT_FALSE otherwise. ** ****************************************************************************************/ static blt_bool FlashEraseSectors(blt_int8u first_sector, blt_int8u last_sector) { blt_int16u nr_of_blocks; blt_int16u block_cnt; blt_addr start_addr; blt_addr end_addr; /* validate the sector numbers */ if (first_sector > last_sector) { return BLT_FALSE; } if ( (first_sector < flashLayout[0].sector_num) || \ (last_sector > flashLayout[FLASH_TOTAL_SECTORS-1].sector_num) ) { return BLT_FALSE; } /* determine how many blocks need to be erased */ start_addr = FlashGetSectorBaseAddr(first_sector); end_addr = FlashGetSectorBaseAddr(last_sector) + FlashGetSectorSize(last_sector) - 1; nr_of_blocks = (end_addr - start_addr + 1) / FLASH_ERASE_BLOCK_SIZE; /* erase all blocks one by one */ for (block_cnt=0; block_cnt<nr_of_blocks; block_cnt++) { /* keep the watchdog happy */ CopService(); /* erase the flash page with size FLASH_ERASE_BLOCK_SIZE */ if (FlashLibErase(start_addr + (block_cnt * FLASH_ERASE_BLOCK_SIZE)) != 0) { return BLT_FALSE; } } /* still here so all went okay */ return BLT_TRUE; } /*** end of FlashEraseSectors ***/
/************************************************************************************//** ** \brief Programming is done per block. This function adds data to the block ** that is currently collecting data to be written to flash. If the ** address is outside of the current block, the current block is written ** to flash an a new block is initialized. ** \param block Pointer to flash block info structure to operate on. ** \param address Flash destination address. ** \param data Pointer to the byte array with data. ** \param len Number of bytes to add to the block. ** \return BLT_TRUE if successful, BLT_FALSE otherwise. ** ****************************************************************************************/ static blt_bool FlashAddToBlock(tFlashBlockInfo *block, blt_addr address, blt_int8u *data, blt_int32u len) { blt_addr current_base_addr; blt_int8u *dst; blt_int8u *src; /* determine the current base address */ current_base_addr = (address/FLASH_WRITE_BLOCK_SIZE)*FLASH_WRITE_BLOCK_SIZE; /* make sure the blockInfo is not uninitialized */ if (block->base_addr == FLASH_INVALID_ADDRESS) { /* initialize the blockInfo struct for the current block */ if (FlashInitBlock(block, current_base_addr) == BLT_FALSE) { return BLT_FALSE; } } /* check if the new data fits in the current block */ if (block->base_addr != current_base_addr) { /* need to switch to a new block, so program the current one and init the next */ block = FlashSwitchBlock(block, current_base_addr); if (block == BLT_NULL) { return BLT_FALSE; } } /* add the data to the current block, but check for block overflow */ dst = &(block->data[address - block->base_addr]); src = data; do { /* keep the watchdog happy */ CopService(); /* buffer overflow? */ if ((blt_addr)(dst-&(block->data[0])) >= FLASH_WRITE_BLOCK_SIZE) { /* need to switch to a new block, so program the current one and init the next */ block = FlashSwitchBlock(block, current_base_addr+FLASH_WRITE_BLOCK_SIZE); if (block == BLT_NULL) { return BLT_FALSE; } /* reset destination pointer */ dst = &(block->data[0]); } /* write the data to the buffer */ *dst = *src; /* update pointers */ dst++; src++; /* decrement byte counter */ len--; } while (len > 0); /* still here so all is good */ return BLT_TRUE; } /*** end of FlashAddToBlock ***/
/**************************************************************************************** ** NAME: FlashWriteBlock ** PARAMETER: block pointer to flash block info structure to operate on. ** RETURN VALUE: BLT_TRUE if successful, BLT_FALSE otherwise. ** DESCRIPTION: Programs FLASH_WRITE_BLOCK_SIZE bytes to flash from the block->data ** array. ** ****************************************************************************************/ static blt_bool FlashWriteBlock(tFlashBlockInfo *block) { blt_int8u sector_num; blt_bool result = BLT_TRUE; blt_addr prog_addr; blt_int32u prog_data; blt_int32u word_cnt; /* check that address is actually within flash */ sector_num = FlashGetSector(block->base_addr); if (sector_num == FLASH_INVALID_SECTOR) { return BLT_FALSE; } /* unlock the flash array */ FlashUnlock(); /* check that the flash peripheral is not busy */ if ((FLASH->SR & FLASH_BSY_BIT) == FLASH_BSY_BIT) { /* lock the flash array again */ FlashLock(); /* could not perform erase operation */ return BLT_FALSE; } /* set the program bit to indicate that we are about to program data */ FLASH->CR |= FLASH_PG_BIT; /* program all words in the block one by one */ for (word_cnt=0; word_cnt<(FLASH_WRITE_BLOCK_SIZE/sizeof(blt_int32u)); word_cnt++) { prog_addr = block->base_addr + (word_cnt * sizeof(blt_int32u)); prog_data = *(volatile blt_int32u*)(&block->data[word_cnt * sizeof(blt_int32u)]); /* program the first half word */ *(volatile blt_int16u*)prog_addr = (blt_int16u)prog_data; /* wait for the program operation to complete */ while ((FLASH->SR & FLASH_BSY_BIT) == FLASH_BSY_BIT) { /* keep the watchdog happy */ CopService(); } /* program the second half word */ *(volatile blt_int16u*)(prog_addr+2) = (blt_int16u)(prog_data >> 16); /* wait for the program operation to complete */ while ((FLASH->SR & FLASH_BSY_BIT) == FLASH_BSY_BIT) { /* keep the watchdog happy */ CopService(); } /* verify that the written data is actually there */ if (*(volatile blt_int32u*)prog_addr != prog_data) { result = BLT_FALSE; break; } } /* reset the program bit to indicate that we are done programming data */ FLASH->CR &= ~FLASH_PG_BIT; /* lock the flash array */ FlashLock(); /* still here so all is okay */ return result; } /*** end of FlashWriteBlock ***/