It is recommended that application, which make use of the SAM C21 Diagnostic Library, be
architected as a state-machine. During diagnostics it will sometimes be necessary to do
software resets during the POST diagnostics; ensure a clean state of registers for the
SFR Reset calls; and a prestine state for peripheral modules that have their own
mini-state machines internally, such as RSTC and WDT. The state-machine architecture is
capable of supported those needs.
To maintain the reset state across resets, the reset state should be kept in a persistent
variable as follows:
RESET_STATES __attribute__((section(".persist"))) reset_state;
Just before each software reset occurs (by calling NVIC_SystemReset()),
the state variable is advanced to the next state, so after the reset occurs execution
will continue there and jump past code already executed.
Note: that for the SAMC21J18A/E18A processors, a
software reset takes about 10 ms. Resets should be minimized as much as possible to
decrease the overall boot time.
Within each state, a lower level function is called to actually run the tests, e.g.
DIAG_DMAC_SFRPost() and DIAG_DMAC_Post() for the
DMAC peripheral (shown below). The result of each test is stored in a persistent array
called diag_test_status.
The diagnostics are called from main() by calling
DIAG_RunPOST(). This must be called before the
SYS_Initialize() call. Because of the software resets,
DIAG_RunPOST() will be called repeatily but will never return until
the POST diagnostics are complete (state RESET_STATE_RUN). At that
point, SYS_Initialize() is called to perform the normal application
initialization, and if desired, the results of the tests that were saved off in
diag_test_status can be displayed to a terminal via printf’s.
We recommend establishing the following files: main.c , diag.h, and diag.c. A post file
is also recommended for each peripherial to call specific functions within the
peripheral diagnostic API. Post_DMAC.c is included as an example.
Table 2-4. | File | Code Example |
|---|
| main.c |
extern DIAG_TEST_STATUS
__attribute__((section(".persist"))) diag_test_status[NUM_DIAG_TESTS];
extern DIAG_TEST_STATUS
__attribute__((section(".persist"))) core_status;
int main ( void )
{
DIAG_RunPOST();
SYS_Initialize ( NULL ); // access to sercom for reporting
printf("\f\r\nPOST results:\r\n\r\n");
printf("\tCore \t\t= %d\r\n",core_status);
printf("\tDIVAS \t\t= %d\r\n",
diag_test_status[DIAG_DIVAS_RESULT]);
printf("\tDMAC \t\t= %d\r\n",diag_test_status[DIAG_DMAC_RESULT]);
printf("\tPM \t\t= %d\r\n",diag_test_status[DIAG_PM_RESULT]);
/*
* remainder of your application
*/
}
|
| diag.h |
typedef enum
{
/* Application's reset states */
RESET_STATE_RUN = 0,
RESET_STATE_DMAC = 0xd0db17e0;
RESET_STATE_MID_POST = 0x166cf399,
/*
* additional enums
*/
} RESET_STATES;
enum diag_test
{
DIAG_DIVAS_RESULT;
DIAG_DMAC_RESULT;
DIAG_PM_RESULT;
/*
* additional enums
*/
NUM_DIAG_TESTS;
}
|
| diag.c |
#include "diag_post.h"
#include "definitions.h"
#include "diagnostic/core/diag_core.h"
DIAG_TEST_STATUS
__attribute__((section(".persist")))diag_test_status[NUM_DIAG_TESTS];
DIAG_TEST_STATUS
__attribute__((section(".persist"))) core_status;
RESET_STATES
__attribute__((section(".persist"))) reset_state;
void DIAG_RunPOST(void)
{
DIAG_SetPOSTComplete(false);
NVMCTRL_REGS->NVMCTRL_CTRLB = NVMCTRL_CTRLB_RWS(3);
NVIC_Initialize();
DIAG_OSCCTRL_Initialize(48000000, 5.0); // Initialize Main Oscillator
switch (reset_state)
{
/* first state after power on reset is default */
default:
/* intialize status */
int i;
for (i = 0; i < NUM_DIAG_TESTS; i++)
{
diag_test_status[i] = DIAG_TEST_NOT_EXECUTED;
}
/* run Core diagnostics first */
DIAG_CORE_M0p_STL_Init(DIAG_CONTEXT_OOR);
core_status = DIAG_CORE_M0p_STL(DIAG_CONTEXT_OOR);
reset_state = RESET_STATE_DMAC;
/* do a software reset */
NVIC_SystemReset();
}
/* run DMAC */
case RESET_STATE_DMAC:
{
diag_test_status[DIAG_DMAC_RESULT] = DIAG_DMAC_SFRPost();
if (DIAG_TEST_PASSED == diag_test_status[DIAG_DMAC_RESULT])
{
diag_test_status[DIAG_DMAC_RESULT] = DIAG_DMAC_Post();
}
diag_test_status[DIAG_DIVAS_RESULT] = DIAG_DIVAS_Post();
/*
* etc. etc. – many more states not shown
*/
reset_state = RESET_STATE_MID_POST;
NVIC_SystemReset();
}
/* run MID post tests */
case RESET_STATE_MID_POST:
{
diag_test_status[DIAG_PM_RESULT] = DIAG_PM_SFRPost();
/*
* etc. etc. – many more states not shown
*/
reset_state = RESET_STATE_HARMONY_POST;
/* perform a software reset */
NVIC_SystemReset();
}
/* startup harmony application */
case RESET_STATE_HARMONY_POST:
{
DIAG_SetPOSTComplete(true);
/* in case reset occurs, will start over with tests */
reset_state = RESET_STATE_RUN;
}
break;
}
}
|
| Post_DMAC.c |
DIAG_TEST_STATUS DIAG_DMAC_SFRPost()
{
DIAG_TEST_STATUS result;
result = DIAG_DMAC_SFRReset(NULL,0,false);
if (result == DIAG_TEST_PASSED)
{
result = DIAG_DMAC_SFRWriteRead(NULL,0,false);
}
return result;
}
DIAG_TEST_STATUS DIAG_DMAC_Post()
{
DIAG_TEST_STATUS result;
result = DIAG_DMAC_Transfer(DMAC_CHANNEL_9);
if (result == DIAG_TEST_PASSED)
{
result = DIAG_DMAC_Interrupts(DMAC_CHANNEL_9);
if (result == DIAG_TEST_PASSED)
{
result = DIAG_DMAC_LinkedList(DMAC_CHANNEL_9);
}
}
return result;
}
|