Пишу код для stm32, практикую использование конечных автоматов и решил посмотреть как далеко я смогу зайти с автоматами. Написал вот такую функцию, в прерывании отслеживаю три флага готовности и только после того как все три сработали выхожу из функции.
/* State machine states */
#define SMRCC_DE_INIT_LOCKFREE 0
#define SMRCC_SET_SYS_CLOCL 1
/* rcc_deinit_lockfree flags to prevent magical numbers*/
#define RCC_DEINIT_RESET 0
#define RCC_DEINIT_HSIRDY 1
#define RCC_DEINIT_HSERDY 1
#define RCC_DEINIT_PLLRDY 1
#define RCC_DEINIT_READY 3
static volatile uint8_t SMRCC_state;
static volatile uint8_t de_init_complete;
void RCC_CRS_IRQHandler(void) {
switch(SMRCC_state) {
/* RCC_de_init state */
case SMRCC_DE_INIT_LOCKFREE:
switch(RCC->CIR & (RCC_CIR_HSERDYF | RCC_CIR_HSIRDYF | RCC_CIR_PLLRDYF)) {
case RCC_CIR_HSIRDYF:
RCC->CIR |= RCC_CIR_HSIRDYC;
de_init_complete += RCC_DEINIT_HSIRDY;
RCC->CIR &= ~RCC_CIR_HSIRDYC;
break;
case RCC_CIR_HSERDYF:
RCC->CIR |= RCC_CIR_HSERDYC;
de_init_complete += RCC_DEINIT_HSERDY;
RCC->CIR &= ~RCC_CIR_HSERDYC;
break;
case RCC_CIR_PLLRDYF:
RCC->CIR |= RCC_CIR_PLLRDYC;
de_init_complete += RCC_DEINIT_PLLRDY;
RCC->CIR &= ~RCC_CIR_PLLRDYC;
break;
}
break;
}
}
void rcc_deinit_lockfree(void) {
de_init_complete = RCC_DEINIT_RESET;
NVIC_EnableIRQ(RCC_CRS_IRQn);
/* Enable interrupts on HSIRDY, HSERDY, PLLRDY */
RCC->CIR |= (RCC_CIR_HSIRDYIE | RCC_CIR_HSERDYIE | RCC_CIR_PLLRDYIE);
/*Enable HSI*/
RCC->CR |= RCC_CR_HSION;
RCC->CR &= ~RCC_CR_PLLON;
/* Disable CSS and HSE */
RCC->CR &= ~(RCC_CR_CSSON | RCC_CR_HSEON);
RCC->CFGR = 0x00; /* Also this will set SW to HSI */
RCC->CFGR2 = 0x00;
RCC->CFGR3 = 0x00;
while(de_init_complete != RCC_DEINIT_READY) {}
/* Disable interrupts on HSIRDY, HSERDY, PLLRDY */
RCC->CIR &= ~(RCC_CIR_HSIRDYIE | RCC_CIR_HSERDYIE | RCC_CIR_PLLRDYIE);
NVIC_DisableIRQ(RCC_CRS_IRQn);
de_init_complete = RCC_DEINIT_RESET;
}
У меня есть пара вопросов и сомнений в моем подходе в этом коде. Первое надо ли ресетить RCC_CIR_HSIRDYC
, RCC_CIR_HSERDYC
и тд (в даташите я про это не нашел). Нормально ли так много кода держать в прерывании (у меня один конечный автомат, в RCC_CRS_IRQHandler, на всю работу с rcc)?
А вот теперь то, что мне не нравиться:de_init_complete += RCC_DEINIT_HSIRDY;
и компания с while(de_init_complete != RCC_DEINIT_READY) {}
. Мне кажется это каким-то костыльным решением, которое может сломаться, как это сделать по-человечески?