Post Go back to editing

writing flash via ospi

Category: Software
Product Number: ADSP-SC594
Software Version: 2.12.1

Hello Support Team Guy,

One of our customers are facing the two issues for ADSP-SC594.

  1. When writing data to the flash through the OSPI interface using Sc594, after continuous writing, the last portion of the data always fails to be written. It was found that accessing this part of the data through the memory window in CCES allows it to be written; otherwise, even waiting for a long time does not work. What could be the reason?

  2. When loading data from the flash, it can be read correctly with the emulator connected. However, after burning the program and restarting, the program fails to run normally. What could be the reason?

The below code is for the first issue.

bool saveMotorParaToFlash(uint16_t motor)    

{

      bool rt = false;

      rt = Flash_Init();

      if(!rt)

      {

            if(motor<AxisNum)

            {

               //erase the flash

                  if(Flash_Erase(gFlashOperation.MotorSectorOffset[motor],gFlashOperation.MotorSectorSize))

                  {

                       return false;

                  }

                  if(WriteData(gFlashOperation.MotorSectorOffset[motor], MotorPara_Size,1,addr_L2_Net_100M_Start + motor*MotorPara_Size, 1, true))

                  {

                       return false;

                  }

 

 

            }

            else //All Motor

            {

                     //erase the flash

                  if(Flash_Erase(gFlashOperation.MotorSectorOffset[0],gFlashOperation.MotorSectorSize*8))

                  {

 

                       return false;

                  }

 

 

                  for(int Axis = 0;Axis<AxisNum;Axis++)

                  {

                    if(WriteData(gFlashOperation.MotorSectorOffset[Axis], MotorPara_Size,1,addr_L2_Net_100M_Start + Axis*MotorPara_Size , 1, true))

                    {

                       return false;

                    }

 

                  }

 

            }

 

 

           return true;

 

      }

      else

      {

            return false;

      }

 

 

}

The below code is for the second issue.

bool loadMotorParaFromFlash(uint16_t motor)

{

      bool rt = false;

 

 

      rt = Flash_Init();

      if(!rt)

      {

 

            if(motor<AxisNum)

            {

                  if(ReadData(gFlashOperation.MotorSectorOffset[motor], MotorPara_Size,1,addr_L2_Net_100M_Start + motor*MotorPara_Size, 1))

                  {

 

                       return false;

                  }

                 

            }

            else //All Motor

            {

                  for(int Axis = 0;Axis<AxisNum;Axis++)

                  {

                       if(ReadData(gFlashOperation.MotorSectorOffset[Axis], MotorPara_Size,1,addr_L2_Net_100M_Start + Axis*MotorPara_Size, 1))

                       {

 

                             return false;

                       }

                        

                  }

 

            }

 

          return true;

 

      }

      else

      {

            return false;

      }

 

 The attachment is source code for operating  the OSPI Flash.

#include <drivers/ospi/adi_ospi.h>
#include <drivers/twi/adi_twi.h>
#include <services/dma/adi_dma.h>
#include <services/pwr/adi_pwr.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>

#include <sys/ADSP-SC594.h>
#include <sys/ADSP-SC594_cdef.h>
#include <adi_initialize.h>
#include "Header/ISSIFlash_OSPI.h"


//T  全局变量
__attribute__((aligned(32)))        uint8_t             StatusBuffer[STATUS_SIZE];
int 			AFP_Error 			= NO_ERR;			/* contains last error encountered */
ADI_OSPI_HANDLE hOspi;

// Flash_Init相关变量
uint32_t Result;
uint8_t  OSpiMemory[ADI_OSPI_MEMORY_SIZE];

uint8_t readBuffer1 [] = {0}; //T   存储读取结果的变量




/* busy wait with timeout */
bool FlashBusyWait(ADI_OSPI_HANDLE hOspi)
{
	uint16_t timeout;

	/* poll on the busy bit until it clears or we time out */
	for (timeout = 0; timeout < MAX_TIMEOUT; timeout++) {
		if (false == FlashTestSR1(hOspi, SR1_BUSY_BIT))
			break;
	}

	/* return timeout status */
	return (MAX_TIMEOUT == timeout);
}



/* return flash SR bit status as a boolean */
bool FlashTestSR1 (ADI_OSPI_HANDLE hOspi, uint8_t bit)
{
	ADI_OSPI_STIGCMD STIG_Command;
	ADI_OSPI_STIGCMD *pSTIG_Command = &STIG_Command;

	pSTIG_Command->CmdOpcode       = CMD_SR1_READ;
	pSTIG_Command->CmdOpcode2      = 0;
	pSTIG_Command->eBusMode        = ADI_OSPI_STIG_SINGLE;
	pSTIG_Command->eTransferMode   = ADI_OSPI_TRANSFERMODE_STR;
	pSTIG_Command->NumOfDummyCycles= 0;
	pSTIG_Command->ModeDataEnable  = 0;
	pSTIG_Command->ModeData		   = 0;
	pSTIG_Command->eDataMode	   = ADI_OSPI_STIG_READDATA_EN;
	pSTIG_Command->DataSize		   = 1;
	pSTIG_Command->AddressEnable   = 0;
	pSTIG_Command->AddrSize		   = ADI_OSPI_CMD_ADDR_SIZE_1;
	pSTIG_Command->Address         = 0;
	pSTIG_Command->pBuffer         = StatusBuffer;

	while (1) {

		/* Launch the command to read flash Status register */
		if(adi_ospi_StigCommand(hOspi, pSTIG_Command) != ADI_OSPI_SUCCESS)
			break;

		return (StatusBuffer[0] & bit);
	}

	/* failure */
	return true;
}



/* prepare the flash for writing */
bool FlashWriteEnable(ADI_OSPI_HANDLE hOspi)
{
	ADI_OSPI_STIGCMD STIG_Command;
	ADI_OSPI_STIGCMD *pSTIG_Command = &STIG_Command;

	pSTIG_Command->CmdOpcode       = CMD_WRITE_ENABLE;
	pSTIG_Command->CmdOpcode2      = 0;
	pSTIG_Command->eBusMode        = ADI_OSPI_STIG_SINGLE;
	pSTIG_Command->eTransferMode   = ADI_OSPI_TRANSFERMODE_STR;
	pSTIG_Command->NumOfDummyCycles= 0;
	pSTIG_Command->ModeDataEnable  = 0;
	pSTIG_Command->ModeData		   = 0;
	pSTIG_Command->eDataMode	   = ADI_OSPI_STIG_NODATA;
	pSTIG_Command->DataSize		   = 0;
	pSTIG_Command->AddressEnable   = 0;
	pSTIG_Command->AddrSize		   = ADI_OSPI_CMD_ADDR_SIZE_1;
	pSTIG_Command->Address         = 0;
	pSTIG_Command->pBuffer         = 0;

	while (1) {

		/* verify not busy */
		if (FlashBusyWait(hOspi))
			break;

		/* Send WREN command to flash */
		if(adi_ospi_StigCommand(hOspi, pSTIG_Command) != ADI_OSPI_SUCCESS)
			break;

		/* verify not busy */
		if (FlashBusyWait(hOspi))
			break;

		/* verify flash is write-enabled */
		if (true != FlashTestSR1(hOspi, SR1_WEL_BIT))
			break;

		return false;  //T  成功
	}

	return true;       //T  失败
}



/* erase a 4k-byte block on the flash, assumes address is aligned to sector start boundary */
bool FlashEraseSector(ADI_OSPI_HANDLE hOspi, uint32_t Address)
{
	ADI_OSPI_STIGCMD STIG_Command;
	ADI_OSPI_STIGCMD *pSTIG_Command = &STIG_Command;

	pSTIG_Command->CmdOpcode       = CMD_SECTOR_ERASE;     //T  擦除扇区的指令,扇区大小为4KB
	pSTIG_Command->CmdOpcode2      = 0;
	pSTIG_Command->eBusMode        = ADI_OSPI_STIG_SINGLE;
	pSTIG_Command->eTransferMode   = ADI_OSPI_TRANSFERMODE_STR;
	pSTIG_Command->NumOfDummyCycles= 0;
	pSTIG_Command->ModeData		   = 0;
	pSTIG_Command->eDataMode	   = ADI_OSPI_STIG_NODATA;
	pSTIG_Command->DataSize		   = 0;
	pSTIG_Command->AddressEnable   = 1;
	pSTIG_Command->AddrSize		   = ADI_OSPI_CMD_ADDR_SIZE_3;
	pSTIG_Command->Address         = Address;
	pSTIG_Command->pBuffer         = 0;

	while (1) {

		// assert flash write enable state
		if (FlashWriteEnable(hOspi))
			break;

		// sector erase sequence
		if(adi_ospi_StigCommand(hOspi, pSTIG_Command) != ADI_OSPI_SUCCESS)
			break;

		// wait with timeout
		if (FlashBusyWait(hOspi))
			break;

		// verify flash is write-disabled
		if (false != FlashTestSR1(hOspi, SR1_WEL_BIT))
			break;

		return false;   //T  擦除成功

	}

	return true;        //T  擦除失败
}



bool ConfigureOSPI(ADI_OSPI_HANDLE hOspi)
{
	while (1) {

		//T  配置波特率
		if(adi_ospi_ConfigBaud(hOspi, ADI_OSPI_BAUD_DIV_BY_16))     break;

		//T  更新读取捕获延迟
		if (adi_ospi_UpdateReadDelay(hOspi, 4))						break;

		//if(adi_ospi_ConfigChipselect(hOspi,ADI_OSPI_CHIPSEL_1))      break;


		return true;   //T  配置成功

	}

	return false;        //T  配置失败
}



bool Flash_Init(){


	memset(OSpiMemory, 0, sizeof(OSpiMemory));  //T 运行时全部置0

	// Open OSPI
	if(adi_ospi_Open((uint8_t *)OSpiMemory, ADI_OSPI_MEMORY_SIZE, OSPI_ADI_MDMANOTUSED, (ADI_DMA_STREAM_ID)7, &hOspi))
	{
		AFP_Error = SETUP_ERROR;
		return true;
	}

	 // configure SPI
	if (!ConfigureOSPI(hOspi))
	{
		AFP_Error = SETUP_ERROR;
		return true;
	}

   for(uint32_t i = 0;i<500000;i++)
   {
	   ;

   }


	return false;   //T  初始化完成
}



bool Flash_Close()
{
	ADI_OSPI_RESULT rt;

	if(hOspi)
	{

	  adi_ospi_EnterXipmode(hOspi,true);
	   rt = adi_ospi_Close(hOspi);

	   if(rt != ADI_OSPI_SUCCESS)
	   {
		   return true;  //失败
	   }
	}
	return false;  //成功
}

/**
 *****************************************************************************
 *! 从 Address开始擦除 Select_Count 个 4KB 空间
 *
 * @param	Address       要擦除的起始地址,需要对齐4字节(地址值是0x04的整数倍,包括0x00)
 * @param	Sector_Count  要擦除的4KB扇区的数量
 *
 * @return  返回true代表擦除失败,返回false代表擦除成功
 */
bool Flash_Erase(uint32_t Address, uint32_t Sector_Count){

	FlashWriteEnable(hOspi);

	for(int i=0; i<Sector_Count; i++){
		bool era_result = FlashEraseSector(hOspi, FLASHBASEADDR+Address + 4096*i);

		if(era_result == true){
			return true;         //! 擦除失败,返回1
		}
	}
	return false;                //! 擦除成功,返回0
}







/**
 *****************************************************************************
 * T        往Flash里面写入数据
 *
 * @param	ulStart		要写入数据的起始地址
 * @param	lCount		要写入数据的数量
 * @param	lStride		两次写入时位置的差值,一般设置为1,表示连续写入
 * @param	*pnData		用来存放待写入数据的地址(数组)
 * @param	ValueSize	每个数据的字节数 (1, 2, or 4),一般设置为1
 * @param	AFP_Verify	如果值是1,则进行验证,看是否正确写入;反之则不验证
 *
 * @return				返回0表示写入成功,返回1表示写入失败
 */
ERROR_CODE WriteData(unsigned long ulStart, long lCount, long lStride, int *pnData, int ValueSize, bool AFP_Verify)
{
	ADI_OSPI_DAC_CMD DAC_Command;
	ADI_OSPI_DAC_CMD *pDAC_Command = &DAC_Command;
	int result = 0;
	uint8_t *buf = (uint8_t *) pnData;
	uint8_t *pFlashDest = (uint8_t *)(FLASHBASEADDR + ulStart);    //T  用于写入
	uint8_t *pFlashSource = (uint8_t *)(FLASHBASEADDR + ulStart);  //T  用于验证
	uint32_t uLocalCount = lCount;

	if (lStride == 1)
		ValueSize = 1;

	if (lStride < ValueSize)
		return WRITE_ERROR;

	if (ValueSize != 1 && ValueSize != 2 && ValueSize != 4)
		return WRITE_ERROR;

	/* Prepare the OSPI DAC command for program operation */

	pDAC_Command->CmdOpcode 		= CMD_SINGLE_MODE_WRITE;
	pDAC_Command->eBusMode			= ADI_OSPI_SINGLE;
	pDAC_Command->CmdOpcode2 		= 0;
	pDAC_Command->eTransferMode		= ADI_OSPI_TRANSFERMODE_STR;
	pDAC_Command->eOperatingMode	= OSPI_ADI_COREMODE;
	pDAC_Command->eAddrSize			= ADI_OSPI_CMD_ADDR_SIZE_3;
	pDAC_Command->NumOfDummyCycles	= 0;
	pDAC_Command->ModeDataEnable    = 0;
	pDAC_Command->ModeData			= 0;
	pDAC_Command->pSource			= (uint8_t *)buf;
	pDAC_Command->pDestination      = (uint8_t *)(FLASHBASEADDR + ulStart);
	pDAC_Command->nCount			= lCount;


	if (lStride == 1)
	{
		/* complete data can be written in one shot, OSPI automatically polls flash for page program completion*/
		result = adi_ospi_DirectWrite( hOspi, pDAC_Command );
		if (result)
			return WRITE_ERROR;

		/* Wait for OSPI controller to be idle after last 256 block has been written
		 * this is to ensure flash is done with program operation for last 256-byte write*/
		while(adi_ospi_GetState(hOspi) != ADI_OSPI_CONTROLLER_IS_IDLE ){};
	}
	else
	{
		pDAC_Command->pSource			= NULL;
		pDAC_Command->pDestination      = NULL;
		pDAC_Command->nCount			= 0;

		result = adi_ospi_DirectWrite( hOspi, pDAC_Command );
		if (result)
			return NOT_READ_ERROR;

		long i, j;

		for (i = 0; i < lCount; )
		{
			/* Perform the writes as per the stride (memory mapped OSPI reads)*/
			for (j = 0; j < ValueSize; j++, i++)
			{
				*pFlashDest++ = *buf++;
			}

			/* update the flash address as per stride */
			pFlashDest += (lStride - ValueSize);
		}
	}


	/* If verify operation is requested */
	if (result == 0 && AFP_Verify == TRUE)
	{
		/* Use a small buffer to reduce memory usage.  */
		uint8_t buf2[4];
		long i , j;

		/* Prepare the OSPI DAC command for readback */

		pDAC_Command->CmdOpcode 		= CMD_SINGLE_FAST_READ;
		pDAC_Command->eBusMode			= ADI_OSPI_SINGLE;
		pDAC_Command->NumOfDummyCycles	= 8;

		pDAC_Command->CmdOpcode2 		= 0;
		pDAC_Command->eTransferMode		= ADI_OSPI_TRANSFERMODE_STR;
		pDAC_Command->eOperatingMode	= OSPI_ADI_COREMODE;
		pDAC_Command->eAddrSize			= ADI_OSPI_CMD_ADDR_SIZE_3;
		pDAC_Command->ModeDataEnable    = 0;
		pDAC_Command->ModeData			= 0;
		pDAC_Command->pSource			= NULL;
		pDAC_Command->pDestination      = NULL;
		pDAC_Command->nCount			= 0;

		/* Configure the controller for Read operation. Actual reads done outside API */
		result = adi_ospi_DirectRead( hOspi, pDAC_Command );
		if (result)
			return NOT_READ_ERROR;


		/* Reintialize the pointer to buffer */

		buf = (uint8_t *) pnData;

		for (i = 0; i < lCount;  )
		{
			for(j = 0; j < ValueSize; j++, i++)
			{
				buf2[j] = *pFlashSource++;
			}

			if (memcmp (buf, buf2, ValueSize))
				return VERIFY_WRITE;

			pFlashSource += (lStride - ValueSize);
			buf += ValueSize;
		}
	}

	return (result ? WRITE_ERROR : NO_ERR);
}



/**
 *****************************************************************************
 * T        从Flash里面读取数据
 *
 * @param	ulStart		要读取数据的起始地址
 * @param	lCount		要读取数据的数量
 * @param	lStride		两次读取时位置的差值,一般设置为1,代表连续读取
 * @param	*pnData		用来存放读取数据的地址(数组)
 * @param	ValueSize	每个数据的字节数 (1, 2, or 4),一般设置为1
 *
 * @return				value if any error occurs during reading
 */
ERROR_CODE ReadData(unsigned long ulStart, long lCount, long lStride, int *pnData, int ValueSize)
{
	ADI_OSPI_DAC_CMD DAC_Command;
	ADI_OSPI_DAC_CMD *pDAC_Command = &DAC_Command;
	int result = 0;
	uint8_t *buf = (uint8_t *)pnData;
	uint8_t *pFlashSource = (uint8_t *)(FLASHBASEADDR + ulStart);

	/* See the comment for AFP_ValueSize.  */
	if (lStride == 1)
		ValueSize = 1;

	if (lStride < ValueSize)
		return NOT_READ_ERROR;

	if (ValueSize != 1 && ValueSize != 2 && ValueSize != 4)
		return NOT_READ_ERROR;


	/* Prepare the OSPI DAC command for Read operation */
	pDAC_Command->CmdOpcode 		= CMD_SINGLE_FAST_READ;
	pDAC_Command->eBusMode			= ADI_OSPI_SINGLE;
	pDAC_Command->NumOfDummyCycles	= 8;

	pDAC_Command->CmdOpcode2 		= 0;
	pDAC_Command->eTransferMode		= ADI_OSPI_TRANSFERMODE_STR;
	pDAC_Command->eOperatingMode	= OSPI_ADI_COREMODE;
	pDAC_Command->eAddrSize			= ADI_OSPI_CMD_ADDR_SIZE_3;
	pDAC_Command->ModeDataEnable    = 0;
	pDAC_Command->ModeData			= 0;
	pDAC_Command->pSource			= (uint8_t *)(FLASHBASEADDR + ulStart);
	pDAC_Command->pDestination      = (uint8_t *)buf;
	pDAC_Command->nCount			= lCount;

	//T   如果步长为 1,OSPI 读取 API 可以直接读取所有数据
	if (lStride == 1)
	{
		result = adi_ospi_DirectRead( hOspi, pDAC_Command );

		/* Verify the idle or busy */
	    while(adi_ospi_GetState(hOspi) != ADI_OSPI_CONTROLLER_IS_IDLE ){};        //T  更改
	}

	//T   如果步长不是 1,则仅使用 OSPI 读取 API 来设置控制器以进行读取,实际读取操作在 API 之外完成。
	else
	{
		pDAC_Command->pSource			= NULL;
		pDAC_Command->pDestination      = NULL;
		pDAC_Command->nCount			= 0;

		result = adi_ospi_DirectRead( hOspi, pDAC_Command );
		if (result)
			return NOT_READ_ERROR;

		long i, j;

		for (i = 0; i < lCount; )
		{
			/* Perform the reads as per the stride (memory mapped OSPI reads)*/
			for (j = 0; j < ValueSize; j++, i++)
			{
				*buf++ = *pFlashSource++;
			}

			/* update the flash address as per stride */
			pFlashSource += (lStride - ValueSize);
		}
	}

	return (result ? NOT_READ_ERROR : NO_ERR);
}

Thread Notes