Exemplo n.º 1
0
/** Waits while the target's NVM controller is busy performing an operation, exiting if the
 *  timeout period expires.
 *
 *  \return Boolean \c true if the NVM controller became ready within the timeout period, \c false otherwise
 */
bool XMEGANVM_WaitWhileNVMControllerBusy(void)
{
	/* Preload the pointer register with the NVM STATUS register address to check the BUSY flag */
	XPROGTarget_SendByte(PDI_CMD_ST(PDI_POINTER_DIRECT, PDI_DATASIZE_4BYTES));
	XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_STATUS);

	/* Poll the NVM STATUS register while the NVM controller is busy */
	for (;;)
	{
		/* Fetch the current status value via the pointer register (without auto-increment afterwards) */
		XPROGTarget_SendByte(PDI_CMD_LD(PDI_POINTER_INDIRECT, PDI_DATASIZE_1BYTE));

		uint8_t StatusRegister = XPROGTarget_ReceiveByte();

		/* We might have timed out waiting for the status register read response, check here */
		if (TimeoutTicksRemaining == 0){
		  return false;
		}

		/* Check to see if the BUSY flag is still set */
		if (!(StatusRegister & (1 << 7))) {
		  return true;
		}
	}
}
Exemplo n.º 2
0
/** Sends the given pointer address to the target's TPI pointer register */
static void TINYNVM_SendPointerAddress(const uint16_t AbsoluteAddress)
{
	/* Send the given 16-bit address to the target, LSB first */
	XPROGTarget_SendByte(TPI_CMD_SSTPR | 0);
	XPROGTarget_SendByte(AbsoluteAddress & 0xFF);
	XPROGTarget_SendByte(TPI_CMD_SSTPR | 1);
	XPROGTarget_SendByte(AbsoluteAddress >> 8);
}
Exemplo n.º 3
0
/** Sends the given 32-bit absolute address to the target.
 *
 *  \param[in] AbsoluteAddress  Absolute address to send to the target
 */
static void XMEGANVM_SendAddress(const uint32_t AbsoluteAddress)
{
	/* Send the given 32-bit address to the target, LSB first */
	XPROGTarget_SendByte(((uint8_t*)&AbsoluteAddress)[0]);
	XPROGTarget_SendByte(((uint8_t*)&AbsoluteAddress)[1]);
	XPROGTarget_SendByte(((uint8_t*)&AbsoluteAddress)[2]);
	XPROGTarget_SendByte(((uint8_t*)&AbsoluteAddress)[3]);
}
Exemplo n.º 4
0
/** Removes access to the target's NVM controller and physically disables the target's physical TPI interface. */
void TINYNVM_DisableTPI(void)
{
	TINYNVM_WaitWhileNVMBusBusy();

	/* Clear the NVMEN bit in the TPI STATUS register to disable TPI mode */
	XPROGTarget_SendByte(TPI_CMD_SSTCS | TPI_STATUS_REG);
	XPROGTarget_SendByte(0x00);

	XPROGTarget_DisableTargetTPI();
}
Exemplo n.º 5
0
/** Handler for the XPROG ENTER_PROGMODE command to establish a connection with the attached device. */
static void XPROGProtocol_EnterXPROGMode(void)
{
    Endpoint_ClearOUT();
    Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM);
    Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);

    bool NVMBusEnabled = false;

    if (XPROG_SelectedProtocol == XPRG_PROTOCOL_PDI)
    {
        /* Enable PDI programming mode with the attached target */
        XPROGTarget_EnableTargetPDI();

        /* Store the RESET key into the RESET PDI register to keep the XMEGA in reset */
        XPROGTarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG);
        XPROGTarget_SendByte(PDI_RESET_KEY);

        /* Lower direction change guard time to 0 USART bits */
        XPROGTarget_SendByte(PDI_CMD_STCS | PDI_CTRL_REG);
        XPROGTarget_SendByte(0x07);

        /* Enable access to the XPROG NVM bus by sending the documented NVM access key to the device */
        XPROGTarget_SendByte(PDI_CMD_KEY);
        for (uint8_t i = sizeof(PDI_NVMENABLE_KEY); i > 0; i--)
            XPROGTarget_SendByte(PDI_NVMENABLE_KEY[i - 1]);

        /* Wait until the NVM bus becomes active */
        NVMBusEnabled = XMEGANVM_WaitWhileNVMBusBusy();
    }
    else if (XPROG_SelectedProtocol == XPRG_PROTOCOL_TPI)
    {
        /* Enable TPI programming mode with the attached target */
        XPROGTarget_EnableTargetTPI();

        /* Lower direction change guard time to 0 USART bits */
        XPROGTarget_SendByte(TPI_CMD_SSTCS | TPI_CTRL_REG);
        XPROGTarget_SendByte(0x07);

        /* Enable access to the XPROG NVM bus by sending the documented NVM access key to the device */
        XPROGTarget_SendByte(TPI_CMD_SKEY);
        for (uint8_t i = sizeof(TPI_NVMENABLE_KEY); i > 0; i--)
            XPROGTarget_SendByte(TPI_NVMENABLE_KEY[i - 1]);

        /* Wait until the NVM bus becomes active */
        NVMBusEnabled = TINYNVM_WaitWhileNVMBusBusy();
    }

    Endpoint_Write_Byte(CMD_XPROG);
    Endpoint_Write_Byte(XPRG_CMD_ENTER_PROGMODE);
    Endpoint_Write_Byte(NVMBusEnabled ? XPRG_ERR_OK : XPRG_ERR_FAILED);
    Endpoint_ClearIN();
}
Exemplo n.º 6
0
/** Removes access to the target's NVM controller and physically disables the target's physical PDI interface. */
void XMEGANVM_DisablePDI(void)
{
	XMEGANVM_WaitWhileNVMBusBusy();

	/* Clear the RESET key in the RESET PDI register to allow the XMEGA to run */
	XPROGTarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG);
	XPROGTarget_SendByte(0x00);

	/* Do it twice to make sure it takes effect (silicon bug?) */
	XPROGTarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG);
	XPROGTarget_SendByte(0x00);

	XPROGTarget_DisableTargetPDI();
}
Exemplo n.º 7
0
/** Waits while the target's NVM controller is busy performing an operation, exiting if the
 *  timeout period expires.
 *
 *  \return Boolean true if the NVM controller became ready within the timeout period, false otherwise
 */
bool XMEGANVM_WaitWhileNVMControllerBusy(void)
{
	/* Poll the NVM STATUS register while the NVM controller is busy */
	while (TimeoutMSRemaining)
	{
		/* Send a LDS command to read the NVM STATUS register to check the BUSY flag */
		XPROGTarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2));
		XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_STATUS);
		
		uint8_t StatusRegister = XPROGTarget_ReceiveByte();

		/* We might have timed out waiting for the status register read response, check here */
		if (!(TimeoutMSRemaining))
		  return false;

		/* Check to see if the BUSY flag is still set */
		if (!(StatusRegister & (1 << 7)))
		{
			TimeoutMSRemaining = COMMAND_TIMEOUT_MS;
			return true;
		}
	}
	
	return false;
}
Exemplo n.º 8
0
/** Removes access to the target's NVM controller and physically disables the target's physical TPI interface. */
void TINYNVM_DisableTPI(void)
{
	TINYNVM_WaitWhileNVMBusBusy();

	do
	{
		/* Clear the NVMEN bit in the TPI STATUS register to disable TPI mode */
		XPROGTarget_SendByte(TPI_CMD_SSTCS | TPI_STATUS_REG);
		XPROGTarget_SendByte(0x00);

		/* Read back the STATUS register, check to see if it took effect */
		XPROGTarget_SendByte(TPI_CMD_SLDCS | PDI_RESET_REG);
	} while (XPROGTarget_ReceiveByte() != 0x00);

	XPROGTarget_DisableTargetTPI();
}
Exemplo n.º 9
0
/** Enables the physical TPI interface on the target and enables access to the internal NVM controller.
 *
 *  \return Boolean true if the TPI interface was enabled successfully, false otherwise
 */
bool TINYNVM_EnableTPI(void)
{
	/* Enable TPI programming mode with the attached target */
	XPROGTarget_EnableTargetTPI();

	/* Lower direction change guard time to 32 USART bits */
	XPROGTarget_SendByte(TPI_CMD_SSTCS | TPI_CTRL_REG);
	XPROGTarget_SendByte(0x02);

	/* Enable access to the XPROG NVM bus by sending the documented NVM access key to the device */
	XPROGTarget_SendByte(TPI_CMD_SKEY);
	for (uint8_t i = sizeof(TPI_NVMENABLE_KEY); i > 0; i--)
	  XPROGTarget_SendByte(TPI_NVMENABLE_KEY[i - 1]);

	/* Wait until the NVM bus becomes active */
	return TINYNVM_WaitWhileNVMBusBusy();
}
Exemplo n.º 10
0
Arquivo: XMEGANVM.c Projeto: trtg/lufa
/** Sends the given 32-bit absolute address to the target.
 *
 *  \param[in] AbsoluteAddress  Absolute address to send to the target
 */
static void XMEGANVM_SendAddress(const uint32_t AbsoluteAddress)
{
	/* Send the given 32-bit address to the target, LSB first */
	XPROGTarget_SendByte(AbsoluteAddress &  0xFF);
	XPROGTarget_SendByte(AbsoluteAddress >> 8);
	XPROGTarget_SendByte(AbsoluteAddress >> 16);
	XPROGTarget_SendByte(AbsoluteAddress >> 24);
}
Exemplo n.º 11
0
/** Writes byte addressed memory to the target's memory spaces.
 *
 *  \param[in]  WriteCommand  Command to send to the device to write each memory byte
 *  \param[in]  WriteAddress  Address to write to within the target's address space
 *  \param[in]  Byte          Byte to write to the target
 *
 *  \return Boolean true if the command sequence complete successfully
 */
bool XMEGANVM_WriteByteMemory(const uint8_t WriteCommand, const uint32_t WriteAddress, const uint8_t Byte)
{
	/* Wait until the NVM controller is no longer busy */
	if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
	  return false;

	/* Send the memory write command to the target */
	XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
	XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
	XPROGTarget_SendByte(WriteCommand);
	
	/* Send new memory byte to the memory to the target */
	XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
	XMEGANVM_SendAddress(WriteAddress);
	XPROGTarget_SendByte(Byte);
	
	return true;
}
Exemplo n.º 12
0
Arquivo: XMEGANVM.c Projeto: trtg/lufa
/** Removes access to the target's NVM controller and physically disables the target's physical PDI interface. */
void XMEGANVM_DisablePDI(void)
{
	XMEGANVM_WaitWhileNVMBusBusy();

	/* Clear the RESET key in the RESET PDI register to allow the XMEGA to run - must perform this until the
	 * change takes effect, as in some cases it takes multiple writes (silicon bug?).
	 */
	do
	{
		/* Clear reset register */
		XPROGTarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG);
		XPROGTarget_SendByte(0x00);

		/* Read back the reset register, check to see if it took effect */
		XPROGTarget_SendByte(PDI_CMD_LDCS | PDI_RESET_REG);
	} while (XPROGTarget_ReceiveByte() != 0x00);

	XPROGTarget_DisableTargetPDI();
}
Exemplo n.º 13
0
/** Erases a specific memory space of the target.
 *
 *  \param[in] EraseCommand  NVM erase command to send to the device
 *  \param[in] Address  Address inside the memory space to erase
 *
 *  \return Boolean true if the command sequence complete successfully
 */
bool XMEGANVM_EraseMemory(const uint8_t EraseCommand, const uint32_t Address)
{
	/* Wait until the NVM controller is no longer busy */
	if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
	  return false;
	  
	/* Send the memory erase command to the target */
	XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
	XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
	XPROGTarget_SendByte(EraseCommand);
	
	/* Chip erase is handled separately, since it's procedure is different to other erase types */
	if (EraseCommand == XMEGA_NVM_CMD_CHIPERASE)
	{
		/* Set CMDEX bit in NVM CTRLA register to start the chip erase */
		XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
		XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CTRLA);
		XPROGTarget_SendByte(1 << 0);		
	}
	else
	{
		/* Other erase modes just need us to address a byte within the target memory space */
		XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
		XMEGANVM_SendAddress(Address);
		XPROGTarget_SendByte(0x00);
	}
	
	/* Wait until the NVM bus is ready again */
	if (!(XMEGANVM_WaitWhileNVMBusBusy()))
	  return false;
	  
	return true;
}
Exemplo n.º 14
0
/** Reads memory from the target's memory spaces.
 *
 *  \param[in]  ReadAddress  Start address to read from within the target's address space
 *  \param[out] ReadBuffer   Buffer to store read data into
 *  \param[in]  ReadSize     Number of bytes to read
 *
 *  \return Boolean true if the command sequence complete successfully
 */
bool XMEGANVM_ReadMemory(const uint32_t ReadAddress, uint8_t* ReadBuffer, uint16_t ReadSize)
{
	/* Wait until the NVM controller is no longer busy */
	if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
	  return false;
	
	/* Send the READNVM command to the NVM controller for reading of an arbitrary location */
	XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
	XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
	XPROGTarget_SendByte(XMEGA_NVM_CMD_READNVM);

	/* Load the PDI pointer register with the start address we want to read from */
	XPROGTarget_SendByte(PDI_CMD_ST | (PDI_POINTER_DIRECT << 2) | PDI_DATSIZE_4BYTES);
	XMEGANVM_SendAddress(ReadAddress);

	/* Send the REPEAT command with the specified number of bytes to read */
	XPROGTarget_SendByte(PDI_CMD_REPEAT | PDI_DATSIZE_1BYTE);
	XPROGTarget_SendByte(ReadSize - 1);
		
	/* Send a LD command with indirect access and postincrement to read out the bytes */
	XPROGTarget_SendByte(PDI_CMD_LD | (PDI_POINTER_INDIRECT_PI << 2) | PDI_DATSIZE_1BYTE);
	while (ReadSize-- && TimeoutMSRemaining)
	  *(ReadBuffer++) = XPROGTarget_ReceiveByte();
	
	return (TimeoutMSRemaining != 0);
}
Exemplo n.º 15
0
/** Erases the target's memory space.
 *
 *  \param[in] EraseCommand  NVM erase command to send to the device
 *  \param[in] Address       Address inside the memory space to erase
 *
 *  \return Boolean true if the command sequence complete successfully
 */
bool TINYNVM_EraseMemory(const uint8_t EraseCommand,
                         const uint16_t Address)
{
	/* Wait until the NVM controller is no longer busy */
	if (!(TINYNVM_WaitWhileNVMControllerBusy()))
	  return false;

	/* Set the NVM control register to the target memory erase command */
	TINYNVM_SendWriteNVMRegister(XPROG_Param_NVMCMDRegAddr);
	XPROGTarget_SendByte(EraseCommand);

	/* Write to a high byte location within the target address space to start the erase process */
	TINYNVM_SendPointerAddress(Address | 0x0001);
	XPROGTarget_SendByte(TPI_CMD_SST | TPI_POINTER_INDIRECT);
	XPROGTarget_SendByte(0x00);

	/* Wait until the NVM controller is no longer busy */
	if (!(TINYNVM_WaitWhileNVMControllerBusy()))
	  return false;

	return true;
}
Exemplo n.º 16
0
/** Writes word addressed memory to the target's memory spaces.
 *
 *  \param[in] WriteAddress  Start address to write to within the target's address space
 *  \param[in] WriteBuffer   Buffer to source data from
 *  \param[in] WriteLength   Total number of bytes to write to the device (must be an integer multiple of 2)
 *
 *  \return Boolean true if the command sequence complete successfully
 */
bool TINYNVM_WriteMemory(const uint16_t WriteAddress,
                         uint8_t* WriteBuffer,
                         uint16_t WriteLength)
{
	/* Wait until the NVM controller is no longer busy */
	if (!(TINYNVM_WaitWhileNVMControllerBusy()))
	  return false;

	/* Must have an integer number of words to write - if extra byte, word-align via a dummy high byte */
	if (WriteLength & 0x01)
	  WriteBuffer[WriteLength++] = 0xFF;

	/* Set the NVM control register to the WORD WRITE command for memory writing */
	TINYNVM_SendWriteNVMRegister(XPROG_Param_NVMCMDRegAddr);
	XPROGTarget_SendByte(TINY_NVM_CMD_WORDWRITE);

	/* Send the address of the location to write to */
	TINYNVM_SendPointerAddress(WriteAddress);

	while (WriteLength)
	{
		/* Wait until the NVM controller is no longer busy */
		if (!(TINYNVM_WaitWhileNVMControllerBusy()))
		  return false;

		/* Write the low byte of data to the target */
		XPROGTarget_SendByte(TPI_CMD_SST | TPI_POINTER_INDIRECT_PI);
		XPROGTarget_SendByte(*(WriteBuffer++));

		/* Write the high byte of data to the target */
		XPROGTarget_SendByte(TPI_CMD_SST | TPI_POINTER_INDIRECT_PI);
		XPROGTarget_SendByte(*(WriteBuffer++));

		/* Need to decrement the write length twice, since we wrote a whole two-byte word */
		WriteLength -= 2;
	}

	return true;
}
Exemplo n.º 17
0
/** Reads memory from the target's memory spaces.
 *
 *  \param[in]  ReadAddress  Start address to read from within the target's address space
 *  \param[out] ReadBuffer   Buffer to store read data into
 *  \param[in]  ReadSize     Length of the data to read from the device
 *
 *  \return Boolean true if the command sequence complete successfully
 */
bool TINYNVM_ReadMemory(const uint16_t ReadAddress,
                        uint8_t* ReadBuffer,
                        uint16_t ReadSize)
{
	/* Wait until the NVM controller is no longer busy */
	if (!(TINYNVM_WaitWhileNVMControllerBusy()))
	  return false;

	/* Set the NVM control register to the NO OP command for memory reading */
	TINYNVM_SendWriteNVMRegister(XPROG_Param_NVMCMDRegAddr);
	XPROGTarget_SendByte(TINY_NVM_CMD_NOOP);

	/* Send the address of the location to read from */
	TINYNVM_SendPointerAddress(ReadAddress);

	while (ReadSize-- && TimeoutTicksRemaining)
	{
		/* Read the byte of data from the target */
		XPROGTarget_SendByte(TPI_CMD_SLD | TPI_POINTER_INDIRECT_PI);
		*(ReadBuffer++) = XPROGTarget_ReceiveByte();
	}

	return (TimeoutTicksRemaining > 0);
}
Exemplo n.º 18
0
/** Retrieves the CRC value of the given memory space.
 *
 *  \param[in]  CRCCommand  NVM CRC command to issue to the target
 *  \param[out] CRCDest     CRC Destination when read from the target
 *
 *  \return Boolean \c true if the command sequence complete successfully
 */
bool XMEGANVM_GetMemoryCRC(const uint8_t CRCCommand,
                           uint32_t* const CRCDest)
{
	*CRCDest = 0;

	/* Wait until the NVM controller is no longer busy */
	if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
	  return false;

	/* Set the NVM command to the correct CRC read command */
	XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
	XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
	XPROGTarget_SendByte(CRCCommand);

	/* Set CMDEX bit in NVM CTRLA register to start the CRC generation */
	XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
	XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CTRLA);
	XPROGTarget_SendByte(XMEGA_NVM_BIT_CTRLA_CMDEX);

	/* Wait until the NVM bus is ready again */
	if (!(XMEGANVM_WaitWhileNVMBusBusy()))
	  return false;

	/* Wait until the NVM controller is no longer busy */
	if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
	  return false;

	/* Load the PDI pointer register with the DAT0 register start address */
	XPROGTarget_SendByte(PDI_CMD_ST(PDI_POINTER_DIRECT, PDI_DATASIZE_4BYTES));
	XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_DAT0);

	/* Send the REPEAT command to grab the CRC bytes */
	XPROGTarget_SendByte(PDI_CMD_REPEAT(PDI_DATASIZE_1BYTE));
	XPROGTarget_SendByte(XMEGA_CRC_LENGTH_BYTES - 1);

	/* Read in the CRC bytes from the target */
	XPROGTarget_SendByte(PDI_CMD_LD(PDI_POINTER_INDIRECT_PI, PDI_DATASIZE_1BYTE));
	for (uint8_t i = 0; i < XMEGA_CRC_LENGTH_BYTES; i++)
	  ((uint8_t*)CRCDest)[i] = XPROGTarget_ReceiveByte();

	return (TimeoutTicksRemaining > 0);
}
Exemplo n.º 19
0
/** Busy-waits while the NVM controller is busy performing a NVM operation, such as a FLASH page read.
 *
 *  \return Boolean true if the NVM controller became ready within the timeout period, false otherwise
 */
bool TINYNVM_WaitWhileNVMBusBusy(void)
{
	/* Poll the STATUS register to check to see if NVM access has been enabled */
	for (;;)
	{
		/* Send the SLDCS command to read the TPI STATUS register to see the NVM bus is active */
		XPROGTarget_SendByte(TPI_CMD_SLDCS | TPI_STATUS_REG);

		uint8_t StatusRegister = XPROGTarget_ReceiveByte();

		/* We might have timed out waiting for the status register read response, check here */
		if (!(TimeoutTicksRemaining))
		  return false;

		/* Check the status register read response to see if the NVM bus is enabled */
		if (StatusRegister & TPI_STATUS_NVM)
		  return true;
	}
}
Exemplo n.º 20
0
/** Busy-waits while the NVM controller is busy performing a NVM operation, such as a FLASH page read or CRC
 *  calculation.
 *
 *  \return Boolean true if the NVM controller became ready within the timeout period, false otherwise
 */
bool XMEGANVM_WaitWhileNVMBusBusy(void)
{
	/* Poll the STATUS register to check to see if NVM access has been enabled */
	while (TimeoutMSRemaining)
	{
		/* Send the LDCS command to read the PDI STATUS register to see the NVM bus is active */
		XPROGTarget_SendByte(PDI_CMD_LDCS | PDI_STATUS_REG);
		
		uint8_t StatusRegister = XPROGTarget_ReceiveByte();
		
		/* We might have timed out waiting for the status register read response, check here */
		if (!(TimeoutMSRemaining))
		  return false;
		
		/* Check the status register read response to see if the NVM bus is enabled */
		if (StatusRegister & PDI_STATUS_NVM)
		{
			TimeoutMSRemaining = COMMAND_TIMEOUT_MS;
			return true;
		}
	}
	
	return false;
}
Exemplo n.º 21
0
Arquivo: XMEGANVM.c Projeto: trtg/lufa
/** Enables the physical PDI interface on the target and enables access to the internal NVM controller.
 *
 *  \return Boolean true if the PDI interface was enabled successfully, false otherwise
 */
bool XMEGANVM_EnablePDI(void)
{
	/* Enable PDI programming mode with the attached target */
	XPROGTarget_EnableTargetPDI();

	/* Store the RESET key into the RESET PDI register to keep the XMEGA in reset */
	XPROGTarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG);
	XPROGTarget_SendByte(PDI_RESET_KEY);

	/* Lower direction change guard time to 32 USART bits */
	XPROGTarget_SendByte(PDI_CMD_STCS | PDI_CTRL_REG);
	XPROGTarget_SendByte(0x02);

	/* Enable access to the XPROG NVM bus by sending the documented NVM access key to the device */
	XPROGTarget_SendByte(PDI_CMD_KEY);
	for (uint8_t i = sizeof(PDI_NVMENABLE_KEY); i > 0; i--)
	  XPROGTarget_SendByte(PDI_NVMENABLE_KEY[i - 1]);

	/* Wait until the NVM bus becomes active */
	return XMEGANVM_WaitWhileNVMBusBusy();
}
Exemplo n.º 22
0
/** Handler for the XPROG LEAVE_PROGMODE command to terminate the PDI programming connection with
 *  the attached device.
 */
static void XPROGProtocol_LeaveXPROGMode(void)
{
    Endpoint_ClearOUT();
    Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM);
    Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);

    if (XPROG_SelectedProtocol == XPRG_PROTOCOL_PDI)
    {
        XMEGANVM_WaitWhileNVMBusBusy();

        /* Clear the RESET key in the RESET PDI register to allow the XMEGA to run */
        XPROGTarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG);
        XPROGTarget_SendByte(0x00);

        /* Do it twice to make sure it takes affect (silicon bug?) */
        XPROGTarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG);
        XPROGTarget_SendByte(0x00);

        XPROGTarget_DisableTargetPDI();
    }
    else
    {
        TINYNVM_WaitWhileNVMBusBusy();

        /* Clear the NVMEN bit in the TPI CONTROL register to disable TPI mode */
        XPROGTarget_SendByte(TPI_CMD_SSTCS | TPI_CTRL_REG);
        XPROGTarget_SendByte(0x00);

        XPROGTarget_DisableTargetTPI();
    }

    Endpoint_Write_Byte(CMD_XPROG);
    Endpoint_Write_Byte(XPRG_CMD_LEAVE_PROGMODE);
    Endpoint_Write_Byte(XPRG_ERR_OK);
    Endpoint_ClearIN();
}
Exemplo n.º 23
0
/** Writes page addressed memory to the target's memory spaces.
 *
 *  \param[in]  WriteBuffCommand  Command to send to the device to write a byte to the memory page buffer
 *  \param[in]  EraseBuffCommand  Command to send to the device to erase the memory page buffer
 *  \param[in]  WritePageCommand  Command to send to the device to write the page buffer to the destination memory
 *  \param[in]  PageMode          Bitfield indicating what operations need to be executed on the specified page
 *  \param[in]  WriteAddress      Start address to write the page data to within the target's address space
 *  \param[in]  WriteBuffer       Buffer to source data from
 *  \param[in]  WriteSize         Number of bytes to write
 *
 *  \return Boolean true if the command sequence complete successfully
 */
bool XMEGANVM_WritePageMemory(const uint8_t WriteBuffCommand, const uint8_t EraseBuffCommand,
                              const uint8_t WritePageCommand, const uint8_t PageMode, const uint32_t WriteAddress,
                              const uint8_t* WriteBuffer, uint16_t WriteSize)
{
	if (PageMode & XPRG_PAGEMODE_ERASE)
	{
		/* Wait until the NVM controller is no longer busy */
		if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
		  return false;

		/* Send the memory buffer erase command to the target */
		XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
		XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
		XPROGTarget_SendByte(EraseBuffCommand);

		/* Set CMDEX bit in NVM CTRLA register to start the buffer erase */
		XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
		XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CTRLA);
		XPROGTarget_SendByte(1 << 0);
	}

	if (WriteSize)
	{
		/* Wait until the NVM controller is no longer busy */
		if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
		  return false;

		/* Send the memory buffer write command to the target */
		XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
		XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
		XPROGTarget_SendByte(WriteBuffCommand);

		/* Load the PDI pointer register with the start address we want to write to */
		XPROGTarget_SendByte(PDI_CMD_ST | (PDI_POINTER_DIRECT << 2) | PDI_DATSIZE_4BYTES);
		XMEGANVM_SendAddress(WriteAddress);

		/* Send the REPEAT command with the specified number of bytes to write */
		XPROGTarget_SendByte(PDI_CMD_REPEAT | PDI_DATSIZE_1BYTE);
		XPROGTarget_SendByte(WriteSize - 1);
			
		/* Send a ST command with indirect access and postincrement to write the bytes */
		XPROGTarget_SendByte(PDI_CMD_ST | (PDI_POINTER_INDIRECT_PI << 2) | PDI_DATSIZE_1BYTE);
		while (WriteSize--)
		  XPROGTarget_SendByte(*(WriteBuffer++));
	}
	
	if (PageMode & XPRG_PAGEMODE_WRITE)
	{
		/* Wait until the NVM controller is no longer busy */
		if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
		  return false;

		/* Send the memory write command to the target */
		XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
		XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
		XPROGTarget_SendByte(WritePageCommand);
		
		/* Send the address of the first page location to write the memory page */
		XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
		XMEGANVM_SendAddress(WriteAddress);
		XPROGTarget_SendByte(0x00);
	}

	return true;
}
Exemplo n.º 24
0
/** Sends a SOUT command to the target with the specified I/O address, ready for the data byte to be read.
 *
 *  \param[in] Address  6-bit I/O address to read from in the target's I/O memory space
 */
static void TINYNVM_SendWriteNVMRegister(const uint8_t Address)
{
	/* The TPI command for reading from the I/O space uses strange addressing, where the I/O address's upper
	 * two bits of the 6-bit address are shifted left once */
	XPROGTarget_SendByte(TPI_CMD_SOUT | ((Address & 0x30) << 1) | (Address & 0x0F));
}
Exemplo n.º 25
0
/** Erases a specific memory space of the target.
 *
 *  \param[in] EraseCommand  NVM erase command to send to the device
 *  \param[in] Address       Address inside the memory space to erase
 *
 *  \return Boolean true if the command sequence complete successfully
 */
bool XMEGANVM_EraseMemory(const uint8_t EraseCommand, const uint32_t Address)
{
	/* Wait until the NVM controller is no longer busy */
	if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
	  return false;

	/* EEPROM and Chip erasures are triggered differently to FLASH section erasures */
	if (EraseCommand == XMEGA_NVM_CMD_CHIPERASE)
	{
		/* Send the memory erase command to the target */
		XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
		XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
		XPROGTarget_SendByte(EraseCommand);

		/* Set CMDEX bit in NVM CTRLA register to start the erase sequence */
		XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
		XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CTRLA);
		XPROGTarget_SendByte(1 << 0);
	}
	else if (EraseCommand == XMEGA_NVM_CMD_ERASEEEPROM)
	{
		/* Send the EEPROM page buffer erase command to the target */
		XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
		XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
		XPROGTarget_SendByte(XMEGA_NVM_CMD_ERASEEEPROMPAGEBUFF);

		/* Set CMDEX bit in NVM CTRLA register to start the buffer erase */
		XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
		XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CTRLA);
		XPROGTarget_SendByte(1 << 0);

		/* Wait until the NVM controller is no longer busy */
		if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
		  return false;

		/* Send the EEPROM memory buffer write command to the target */
		XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
		XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
		XPROGTarget_SendByte(XMEGA_NVM_CMD_LOADEEPROMPAGEBUFF);

		/* Load the PDI pointer register with the EEPROM page start address */
		XPROGTarget_SendByte(PDI_CMD_ST | (PDI_POINTER_DIRECT << 2) | PDI_DATSIZE_4BYTES);
		XMEGANVM_SendAddress(Address);

		/* Send the REPEAT command with the specified number of bytes to write */
		XPROGTarget_SendByte(PDI_CMD_REPEAT | PDI_DATSIZE_1BYTE);
		XPROGTarget_SendByte(XPROG_Param_EEPageSize - 1);

		/* Send a ST command with indirect access and post-increment to tag each byte in the EEPROM page buffer */
		XPROGTarget_SendByte(PDI_CMD_ST | (PDI_POINTER_INDIRECT_PI << 2) | PDI_DATSIZE_1BYTE);
		for (uint8_t PageByte = 0; PageByte < XPROG_Param_EEPageSize; PageByte++)
		  XPROGTarget_SendByte(0x00);

		/* Send the memory erase command to the target */
		XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
		XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
		XPROGTarget_SendByte(EraseCommand);

		/* Set CMDEX bit in NVM CTRLA register to start the EEPROM erase sequence */
		XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
		XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CTRLA);
		XPROGTarget_SendByte(1 << 0);
	}
	else
	{
		/* Send the memory erase command to the target */
		XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
		XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
		XPROGTarget_SendByte(EraseCommand);

		/* Other erase modes just need us to address a byte within the target memory space */
		XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
		XMEGANVM_SendAddress(Address);
		XPROGTarget_SendByte(0x00);
	}

	/* Wait until the NVM bus is ready again */
	if (!(XMEGANVM_WaitWhileNVMBusBusy()))
	  return false;

	return true;
}