Exemplo n.º 1
0
msc_Return_TypeDef MSC_WriteWord(uint32_t *address, void const *data, int numBytes)
{
  int wordCount;
  int numWords;
  int pageWords;
  uint32_t* pData;
  msc_Return_TypeDef retval = mscReturnOk;

  /* Check alignment (Must be aligned to words) */
  EFM_ASSERT(((uint32_t) address & 0x3) == 0);

  /* Check number of bytes. Must be divisable by four */
  EFM_ASSERT((numBytes & 0x3) == 0);

  /* Enable writing to the MSC */
  MSC->WRITECTRL |= MSC_WRITECTRL_WREN;

  /* Convert bytes to words */
  numWords = numBytes >> 2;

  /* The following loop splits the data into chunks corresponding to flash pages.
     The address is loaded only once per page, because the hardware automatically
     increments the address internally for each data load inside a page. */
  for (wordCount = 0, pData = (uint32_t*) data; wordCount < numWords; )
  {
    /* First we load address. The address is auto-incremented within a page.
       Therefore the address phase is only needed once for each page. */
    retval = MscLoadAddress(address+wordCount);
    if (mscReturnOk != retval)
      return retval;

    /* Compute the number of words to write to the current page. */
    pageWords =
      (FLASH_PAGE_SIZE -
       (((uint32_t) (address + wordCount)) & (FLASH_PAGE_SIZE-1)))
      / sizeof(uint32_t);
    if (pageWords > numWords-wordCount)
      pageWords = numWords-wordCount;

    /* Now write the data in the current page. */
    retval = MscLoadData(pData, pageWords);
    if (mscReturnOk != retval) goto msc_write_word_exit;

    wordCount += pageWords;
    pData += pageWords;
  }

 msc_write_word_exit:

  /* Disable writing to the MSC */
  MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;

#if (defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)) && (2==WORDS_PER_DATA_PHASE)
  /* Turn off double word write cycle support. */
  MSC->WRITECTRL &= ~MSC_WRITECTRL_WDOUBLE;
#endif

  return retval;
}
Exemplo n.º 2
0
msc_Return_TypeDef MSC_WriteWord(uint32_t *address, void const *data, int numBytes)
{
  int wordCount;
  int numWords;
#if defined(_EFM32_TINY_FAMILY) || defined (_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
  int pageWords;
  uint32_t* pData;
#endif
  msc_Return_TypeDef retval = mscReturnOk;

  /* Check alignment (Must be aligned to words) */
  EFM_ASSERT(((uint32_t) address & 0x3) == 0);

  /* Check number of bytes. Must be divisable by four */
  EFM_ASSERT((numBytes & 0x3) == 0);

  /* Enable writing to the MSC */
  MSC->WRITECTRL |= MSC_WRITECTRL_WREN;

  /* Convert bytes to words */
  numWords = numBytes >> 2;

#if (defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)) && (2==WORDS_PER_DATA_PHASE)

  /* For the Giant and Wonder families we want to use the double word write
   * feature in order to improve the speed. The devices with flash size
   * larger than 512KiBytes support double word write cycles. The address is
   * loaded by the software for the first word, and automatically incremented
   * by the hardware for the second word. However this will not work across a
   * page boundary, so we need to align the address of double word write
   * cycles to an even address.
   */

  if ((((uint32_t) address) % FLASH_PAGE_SIZE + numBytes)
      > FLASH_PAGE_SIZE)
  {
    if (((uint32_t) address) & 0x7)
    {
      MSC->WRITECTRL &= ~MSC_WRITECTRL_WDOUBLE;
      retval = MscLoadAddress(address);
      if (mscReturnOk != retval) goto msc_write_word_exit;
      retval = MscLoadData((uint32_t *) data, 1);
      if (mscReturnOk != retval) goto msc_write_word_exit;
      data = (void *) ((uint32_t) data + sizeof(uint32_t));
      address++;
      numWords--;
    }
  }

  /* If there is an odd number of words remaining to be written,
   * we write the last word now because this has to be written
   * as a single word and will simplify the for() loop below writing
   * double words. */

  if (numWords & 0x1)
  {
    MSC->WRITECTRL &= ~MSC_WRITECTRL_WDOUBLE;
    retval = MscLoadAddress(address + numWords - 1);
    if (mscReturnOk != retval) goto msc_write_word_exit;
    retval = MscLoadData(((uint32_t *) data) + numWords - 1, 1);
    if (mscReturnOk != retval) goto msc_write_word_exit;
    numWords--;
  }

  MSC->WRITECTRL |= MSC_WRITECTRL_WDOUBLE;

#endif /* (defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)) && (2==WORDS_PER_DATA_PHASE) */

#if defined(_EFM32_TINY_FAMILY) || defined (_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)

  pData = (uint32_t*) data;

  /* The following loop splits the data into chunks corresponding to flash pages.
     The address is loaded only once per page, because the hardware automatically
     increments the address internally for each data load inside a page. */
  for (wordCount = 0; wordCount < numWords; )
  {
    /* First we load address. The address is auto-incremented within a page.
       Therefore the address phase is only needed once for each page. */
    retval = MscLoadAddress(address + wordCount);
    if (mscReturnOk != retval) goto msc_write_word_exit;

    /* Compute the number of words to write to the current page. */
    pageWords =
      (FLASH_PAGE_SIZE - ((uint32_t) (address + wordCount)) % FLASH_PAGE_SIZE) /
      sizeof(uint32_t);
    if (pageWords > numWords-wordCount)
      pageWords = numWords-wordCount;
    wordCount += pageWords;

    /* Now program the data in this page. */
    for (; pageWords; pData+=WORDS_PER_DATA_PHASE, pageWords-=WORDS_PER_DATA_PHASE)
    {
      retval = MscLoadData(pData, WORDS_PER_DATA_PHASE);
      if (mscReturnOk != retval)
        goto msc_write_word_exit;
    }
  }

#else /* _EFM32_GECKO_FAMILY  */

  for (wordCount = 0; wordCount < numWords; wordCount++)
  {
    retval = MscLoadAddress(address + wordCount);
    if (mscReturnOk != retval)
      goto msc_write_word_exit;
    retval = MscLoadData(((uint32_t *) data) + wordCount, 1);
    if (mscReturnOk != retval)
      goto msc_write_word_exit;
  }

#endif

 msc_write_word_exit:

  /* Disable writing to the MSC */
  MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;

#if (defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)) && (2==WORDS_PER_DATA_PHASE)
  /* Turn off double word write cycle support. */
  MSC->WRITECTRL &= ~MSC_WRITECTRL_WDOUBLE;
#endif

  return retval;
}