#include "main.h" #include "ad0x0_i2c2.h" #include "ad0x0_i2c_ext.h" //#include "stm8s_delay.h" #define I2CX ((I2C_TypeDef *)I2C2_BASE) //#undef AD0X0_I2C2_DBG //#define AD0X0_I2C2_DBG //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //ВАЖНО!!! если включить, то процессинг коллбэков передачи\приема будет работать //через очередь фриртоса (возникнут 50-80 мкс задержки через каждые 5-10 команд //(в видео рассказано должно быть)) //#define AD0X0_USE_I2C2_PROCESS_THROUGH_XQUEUE //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! /*новая политика партии: включаем тока те ивенты, которые нужны для конкретных команд*/ __weak void ad0x0_i2c2_err_cb(void); //void ad0x0_i2c2_process(void); void ad0x0_i2c2_err(void); void ad0x0_i2c2_err2(char *_str); void ad0x0_i2c2_pop(void); /*2do: Разобраться что вызывается из прерывания ad0x0_i2c2_push - вызывать только из задач. В колбэках незя */ static ad0x0_i2c_desc_s i2c_desc; struct ad0x0_i2c_cmd_s ad0x0_i2c2_fifo[AD0X0_FIFO_COUNT]; volatile struct ad0x0_i2c_cmd_s *ad0x0_i2c2_pcurhwi=0,*ad0x0_i2c2_pcurswi=0; volatile uint32_t ad0x0_i2c2_wait_cycles=0,ad0x0_i2c2_wait_cycles_push=0; uint8_t (*ad0x0_i2c2_pfunc)(void); //extern xSemaphoreHandle xSemI2C2_01; volatile xQueueHandle xqi2c2_01=NULL; void ad0x0_i2c2_restart(void); xQueueHandle get_xqueue_i2c2(void){return xqi2c2_01;} void ad0x0_i2c2_xqRecieveHandler(void){ struct ad0x0_i2c_cmd_s *p=NULL; //Если в очереди нихера то выходим!!!!!!!!!!!!!!!!!!!!!!!!! if(xQueueReceive(xqi2c2_01,&p,0) != pdPASS)return; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! uint8_t ctype=p->ctype & 0x3f; switch(ctype){ case ADQ_DELAY_MS: osDelay(p->cbyte); ad0x0_i2c2_next(false); break; #ifdef AD0X0_USE_I2C2_PROCESS_THROUGH_XQUEUE case ADQ_HAL_ADDR_TX_BUF_SEQ_FIRST_EXT: case ADQ_HAL_ADDR_TX_BUF_STOP_EXT: if(!(ad0x0_i2c2_pcurhwi->cbyte & 0x80)){ ad0x0_i2c_ext_post_process(&i2c_desc,ad0x0_i2c2_pcurhwi->cbyte); ad0x0_i2c2_pcurhwi->cbyte|=0x80; } ad0x0_i2c2_pop(); if(!(ad0x0_i2c2_pcurhwi->ctype & ADQ_EMPTY)){//(очередь не пустая) ad0x0_i2c2_process(false); } break; #endif default: ad0x0_err(); } } static void set_events(uint16_t _ev){ //строка ниже, попробую перевести ее: "выключаем биты, которые надо выставить, кроме тех, которые должны остаться" // I2CX->CR2 &= (~(I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN)) | _ev; // I2CX->CR2 |= _ev | I2C_CR2_ITERREN; } /*эта тема не отлаживалась, ПРОВЕРИТЬ!!!!!!*/ static portFORCE_INLINE void xqSendProcess(uint8_t _from_isr){ char str[10]; static portBASE_TYPE xHigherPriorityTaskWoken; __enable_irq(); if(_from_isr){ xHigherPriorityTaskWoken=false; BaseType_t res=xQueueSendFromISR(xqi2c2_01,(void*)&ad0x0_i2c2_pcurhwi,&xHigherPriorityTaskWoken); if(res==pdTRUE){ __asm("nop"); //portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); }else if(res==errQUEUE_FULL){ sprintf(str,"%d",(int)res); ad0x0_i2c2_err2(str); } if( xHigherPriorityTaskWoken ) { /* Actual macro used here is port specific. */ portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); } }else{ BaseType_t res=xQueueSend(xqi2c2_01,(void*)&ad0x0_i2c2_pcurhwi,100); if(res==pdTRUE){ __asm("nop"); //taskYIELD(); }else if(res==errQUEUE_FULL){ sprintf(str,"%d",(int)res); ad0x0_i2c2_err2(str); } } } void ad0x0_i2c2_push(ADQ_t _ctype,uint8_t _cbyte){//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #ifdef ADDBG4_HIGH ADDBG4_HIGH; #endif while(!(ad0x0_i2c2_pcurswi->ctype & ADQ_EMPTY)){ osDelay(1); } if(ad0x0_i2c2_pcurswi->ctype & ADQ_EMPTY){ __disable_irq(); ad0x0_i2c2_pcurswi->ctype=_ctype; ad0x0_i2c2_pcurswi->cbyte=_cbyte; ad0x0_i2c2_pcurswi=ad0x0_i2c2_pcurswi->pnext; if((!(ad0x0_i2c2_pcurhwi->ctype & ADQ_PROCESSED)) ){ ad0x0_i2c2_process(false); } __enable_irq(); //xqSendProcess(); //ADQ_I2C_EV_ENABLE; }else ad0x0_err(); //ADQ_I2C_EV_ENABLE; #ifdef ADDBG4_HIGH ADDBG4_LOW; #endif } void ad0x0_i2c2_pop(void){//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if(!(ad0x0_i2c2_pcurhwi->ctype & ADQ_PROCESSED)){ //попытка выкинуть необработанный элемент ad0x0_i2c2_err(); } int was_masked=__disable_irq(); switch(ad0x0_i2c2_pcurhwi->ctype & 0x3f){ case ADQ_HAL_ADDR_TX_BUF_SEQ_FIRST_EXT: case ADQ_HAL_ADDR_RX_BUF_SEQ_LAST_EXT: case ADQ_HAL_ADDR_RX_BUF_SEQ_FIRST_EXT: case ADQ_HAL_ADDR_TX_BUF_STOP_EXT: case ADQ_USE_EXT: if(!(ad0x0_i2c2_pcurhwi->cbyte & 0x80)) { ad0x0_i2c_ext_release(ad0x0_i2c2_pcurhwi->cbyte); ad0x0_i2c2_pcurhwi->cbyte|=0x80; } break; case ADQ_DELAY_MS: break; } ad0x0_i2c2_pcurhwi->ctype|=0x80;//метим как выкинутую ad0x0_i2c2_pcurhwi=ad0x0_i2c2_pcurhwi->pnext; if(!was_masked)__enable_irq(); } void ad0x0_i2c2_pop_all(void){//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! int was_masked=__disable_irq(); while( !(ad0x0_i2c2_pcurhwi->ctype & ADQ_EMPTY) ){ switch(ad0x0_i2c2_pcurhwi->ctype & 0x3f){ case ADQ_HAL_ADDR_TX_BUF_SEQ_FIRST_EXT: case ADQ_HAL_ADDR_RX_BUF_SEQ_LAST_EXT: case ADQ_HAL_ADDR_RX_BUF_SEQ_FIRST_EXT: case ADQ_HAL_ADDR_TX_BUF_STOP_EXT: case ADQ_USE_EXT: if(!(ad0x0_i2c2_pcurhwi->cbyte & 0x80)) { ad0x0_i2c_ext_release(ad0x0_i2c2_pcurhwi->cbyte); ad0x0_i2c2_pcurhwi->cbyte|=0x80; } break; case ADQ_DELAY_MS: break; } ad0x0_i2c2_pcurhwi->ctype|=ADQ_EMPTY;//метим как выкинутую ad0x0_i2c2_pcurhwi=ad0x0_i2c2_pcurhwi->pnext; } if(ad0x0_i2c_ext_get_count()){ ad0x0_i2c_ext_get_count(); ad0x0_err(); } if(!was_masked)__enable_irq(); } void ad0x0_i2c2_next(uint8_t _from_isr){ ad0x0_i2c2_pop(); if(!(ad0x0_i2c2_pcurhwi->ctype & (ADQ_EMPTY|ADQS_PROCESSED))){//(очередь не пустая) ad0x0_i2c2_process(_from_isr); } } void ad0x0_i2c2_process(uint8_t _from_isr){ int was_masked=__disable_irq(); if(ad0x0_i2c2_pcurhwi->ctype & (ADQ_EMPTY|ADQS_PROCESSED)){//(очередь не пустая) //ad0x0_err(); __enable_irq(); return; } //тут мы шото меняем какие то флаги, а затем ждем прерывания для текущей команды #ifdef AD0X0_I2C2_DBG ADDBG2_HIGH; #endif //если тип не впишится в свитч, то комнда либо отброшена, либо обработана ранее switch(ad0x0_i2c2_pcurhwi->ctype){ case ADQ_HAL_ADDR_TX_BUF_SEQ_FIRST_EXT: if(!(ad0x0_i2c2_pcurhwi->cbyte & 0x80))ad0x0_i2c_ext_pre_process(&i2c_desc,ad0x0_i2c2_pcurhwi->cbyte); i2c_desc.last_hal_err=HAL_I2C_Master_Seq_Transmit_IT(i2c_desc.phi2c, i2c_desc.addr_w, i2c_desc.tx_pbuf, i2c_desc.pbuf_counter,I2C_FIRST_FRAME); if(HAL_OK != i2c_desc.last_hal_err){ i2c_desc.last_hal_state=HAL_I2C_GetState(i2c_desc.phi2c); } ad0x0_i2c2_pcurhwi->ctype|=ADQ_PROCESSED;//метим как обработанную __enable_irq(); break; case ADQ_HAL_ADDR_RX_BUF_SEQ_LAST_EXT: if(!(ad0x0_i2c2_pcurhwi->cbyte & 0x80)){ ad0x0_i2c_ext_pre_process(&i2c_desc,ad0x0_i2c2_pcurhwi->cbyte); } i2c_desc.last_hal_err=HAL_I2C_Master_Seq_Receive_IT(i2c_desc.phi2c, i2c_desc.addr_r, i2c_desc.rx_pbuf, i2c_desc.pbuf_counter,I2C_LAST_FRAME); //i2c_desc.last_hal_err=HAL_I2C_Master_Receive_IT(i2c_desc.phi2c, i2c_desc.addr_r, i2c_desc.rx_pbuf, i2c_desc.pbuf_counter); if(HAL_OK != i2c_desc.last_hal_err){ i2c_desc.last_hal_state=HAL_I2C_GetState(i2c_desc.phi2c); } ad0x0_i2c2_pcurhwi->ctype|=ADQ_PROCESSED;//метим как обработанную __enable_irq(); break; case ADQ_HAL_ADDR_TX_BUF_STOP_EXT: if(!(ad0x0_i2c2_pcurhwi->cbyte & 0x80)){ ad0x0_i2c_ext_pre_process(&i2c_desc,ad0x0_i2c2_pcurhwi->cbyte); } i2c_desc.last_hal_err=HAL_I2C_Master_Transmit_IT(i2c_desc.phi2c, i2c_desc.addr_w, i2c_desc.tx_pbuf, i2c_desc.pbuf_counter); if(HAL_OK != i2c_desc.last_hal_err){ i2c_desc.last_hal_state=HAL_I2C_GetState(i2c_desc.phi2c); } ad0x0_i2c2_pcurhwi->ctype|=ADQ_PROCESSED;//метим как обработанную __enable_irq(); break; case ADQ_DELAY_MS: //set_events(0); //HAL_Delay(ad0x0_i2c2_pcurhwi->cbyte); ad0x0_i2c2_pcurhwi->ctype|=ADQ_PROCESSED;//метим как обработанную __enable_irq(); #ifdef INC_FREERTOS_H //osDelay(ad0x0_i2c2_pcurhwi->cbyte); //задача, в которую это придет, затормозится на скока надо и вызовет поп и процесс xqSendProcess(_from_isr); #else ad0x0_timman_add(ad0x0_spi1_pcurhwi->cbyte,ad0x0_spi1_next); #endif break; case ADQ_USE_EXT: if(ad0x0_i2c2_pcurhwi->ctype & ADQ_PROCESSED){__enable_irq();ad0x0_i2c2_err();} else{ ad0x0_i2c2_pcurhwi->ctype|=ADQ_PROCESSED;//метим как обработанную __enable_irq(); uint8_t cb=ad0x0_i2c2_pcurhwi->cbyte; ad0x0_i2c2_pcurhwi->cbyte|=0x80; ad0x0_i2c_ext_pre_process(&i2c_desc,cb); ad0x0_i2c_ext_post_process(&i2c_desc,cb); ad0x0_i2c2_pop(); if(!(ad0x0_i2c2_pcurhwi->ctype & (ADQ_EMPTY|ADQS_PROCESSED))){//(очередь не пустая) ad0x0_i2c2_process(_from_isr); } //xqSendProcess(); } //__enable_irq(); break; default: ad0x0_i2c2_err(); //__ASM("nop"); } i2c_desc.last_hwi_process_tick=HAL_GetTick(); //while(herr); #ifdef AD0X0_I2C2_DBG ADDBG2_LOW; #endif } /*void ad0x0_i2c2_irq_err(void){ //я бы это не обрабатывал, если бы не пидорский гироскоп, который не прислал нак при адресе... //метим команду как необработанную и пробуем по новой uint8_t ctypex=ad0x0_i2c2_pcurhwi->ctype; uint32_t sr1=0;//,sr2=0; sr1=I2CX->SR1;// I2CX->SR2;// if(sr1 & I2C_SR1_ARLO){ I2CX->SR1 &= ~I2C_SR1_ARLO; }else switch(ctypex & 0x3f){ case ADQ_START_ADDR: if(sr1 & I2C_SR1_AF){ __disable_irq(); I2CX->SR1&= ~I2C_SR1_AF; I2CX->CR1 |= I2C_CR1_STOP; while((I2CX->CR1 & I2C_CR1_STOP)); ad0x0_i2c2_pcurhwi->ctype&=~ADQ_PROCESSED;//метим как НЕ обработанную ad0x0_i2c2_process(); } break; case ADQ_RX_PBUF_STOP_EXT: if(sr1 & I2C_SR1_BERR){ __disable_irq(); I2CX->SR1&= ~I2C_SR1_BERR; I2CX->CR1 |= I2C_CR1_STOP; while((I2CX->CR1 & I2C_CR1_STOP)); ad0x0_i2c2_pcurhwi->ctype&=~ADQ_PROCESSED;//метим как НЕ обработанную ad0x0_i2c2_process(); } break; default: ad0x0_i2c2_err(); } }*/ void ad0x0_i2c2_MasterRxCpltCallback(void){ AD_I2C_INT_HIGH uint8_t ctypex=ad0x0_i2c2_pcurhwi->ctype; switch(ctypex & 0x3f){ case ADQ_HAL_ADDR_RX_BUF_SEQ_FIRST_EXT: case ADQ_HAL_ADDR_RX_BUF_SEQ_LAST_EXT: #ifdef AD0X0_USE_I2C2_PROCESS_THROUGH_XQUEUE xqSendProcess(true); #else if(!(ad0x0_i2c2_pcurhwi->cbyte & 0x80)){ ad0x0_i2c_ext_post_process(&i2c_desc,ad0x0_i2c2_pcurhwi->cbyte); ad0x0_i2c2_pcurhwi->cbyte|=0x80; } ad0x0_i2c2_pop(); if(!(ad0x0_i2c2_pcurhwi->ctype & ADQ_EMPTY)){//(очередь не пустая) ad0x0_i2c2_process(true); } #endif break; default: ad0x0_i2c2_err(); } AD_I2C_INT_LOW } void ad0x0_i2c2_MasterTxCpltCallback(void){ AD_I2C_INT_HIGH uint8_t ctypex=ad0x0_i2c2_pcurhwi->ctype; switch(ctypex & 0x3f){ case ADQ_HAL_ADDR_TX_BUF_SEQ_FIRST_EXT: case ADQ_HAL_ADDR_TX_BUF_STOP_EXT: if(!(ad0x0_i2c2_pcurhwi->cbyte & 0x80)){ ad0x0_i2c_ext_post_process(&i2c_desc,ad0x0_i2c2_pcurhwi->cbyte); ad0x0_i2c2_pcurhwi->cbyte|=0x80; } #ifdef AD0X0_USE_I2C2_PROCESS_THROUGH_XQUEUE xqSendProcess(true); #else ad0x0_i2c2_pop(); if(!(ad0x0_i2c2_pcurhwi->ctype & ADQ_EMPTY)){//(очередь не пустая) ad0x0_i2c2_process(true); } #endif break; default: ad0x0_i2c2_err(); } AD_I2C_INT_LOW } void ad0x0_i2c2_ErrorCallback(void){ uint8_t ctypex=ad0x0_i2c2_pcurhwi->ctype; HAL_I2C_StateTypeDef hstate=HAL_I2C_GetState(i2c_desc.phi2c); uint32_t herr=HAL_I2C_GetError(i2c_desc.phi2c); switch(ctypex & 0x3f){ case ADQ_HAL_ADDR_TX_BUF_SEQ_FIRST_EXT: case ADQ_HAL_ADDR_TX_BUF_STOP_EXT: case ADQ_HAL_ADDR_RX_BUF_SEQ_LAST_EXT: case ADQ_HAL_ADDR_RX_BUF_SEQ_FIRST_EXT: //ad0x0_i2c2_pcurhwi->ctype&=~ADQ_PROCESSED;//метим как НЕ обработанную //ad0x0_i2c2_process(); //ad0x0_i2c_ext_release(ad0x0_i2c2_pcurhwi->cbyte); ad0x0_i2c2_restart(); break; default: ad0x0_i2c2_err(); } if(hstate==0){ } } void ad0x0_i2c2_restart(void){ ad0x0_i2c2_err(); /*i2c_desc.is_i2c_restarting=1; if(i2c_desc.pfunc_on_error)i2c_desc.pfunc_on_error(); ad0x0_timman_remove(ad0x0_i2c2_next); ad0x0_i2c2_pop_all(); I2C2->CR1 &= ~(I2C_CR1_SWRST); HAL_I2C_DeInit(i2c_desc.phi2c); HAL_I2C_Init(i2c_desc.phi2c); i2c_desc.is_i2c_restarting=0; if(i2c_desc.pfunc_on_i2c_restart)i2c_desc.pfunc_on_i2c_restart();*/ } void ad0x0_i2c2_AbortCpltCallback(void){ uint8_t ctypex=ad0x0_i2c2_pcurhwi->ctype; ad0x0_i2c2_err(); ad0x0_i2c2_pop(); if(!(ad0x0_i2c2_pcurhwi->ctype & ADQ_EMPTY)){//(очередь не пустая) ad0x0_i2c2_process(true); } //xqSendProcess(); } uint8_t ad0x0_i2c2_is_queue_ready(void){ //return ((ad0x0_i2c2_pcurhwi->ctype & ADQ_EMPTY) && (ad0x0_i2c2_pcurhwi->pnext->ctype & ADQ_EMPTY) && !(I2CX->SR1 & I2C_SR2_BUSY)); return ((ad0x0_i2c2_pcurhwi->ctype & ADQ_EMPTY) && (ad0x0_i2c2_pcurhwi->pnext->ctype & ADQ_EMPTY) && !i2c_desc.is_i2c_restarting); } void ad0x0_i2c2_initq(void){ ad0x0_i2c2_pcurhwi=ad0x0_i2c2_pcurswi=ad0x0_i2c2_fifo; ad0x0_i2c2_fifo[AD0X0_FIFO_COUNT-1].pnext=ad0x0_i2c2_fifo; ad0x0_i2c2_fifo[AD0X0_FIFO_COUNT-1].ctype=ADQ_EMPTY; ad0x0_i2c2_fifo[AD0X0_FIFO_COUNT-1].cbyte=0; for(uint16_t i=0;i<=AD0X0_FIFO_COUNT-2;i++){ ad0x0_i2c2_fifo[i].pnext=ad0x0_i2c2_fifo+i+1; ad0x0_i2c2_fifo[i].ctype=ADQ_EMPTY; ad0x0_i2c2_fifo[i].cbyte=0; } } void ad0x0_i2c2_err(void){ ad0x0_err(); } void ad0x0_i2c2_init(I2C_HandleTypeDef *_phi2c) { memset(&i2c_desc,0,sizeof(ad0x0_i2c_desc_s)); i2c_desc.phi2c=_phi2c; i2c_desc.i2cx=I2CX; i2c_desc.perrfunc=ad0x0_err; ad0x0_i2c2_initq(); i2c_desc.last_hwi_process_tick=HAL_GetTick(); xqi2c2_01 = xQueueCreate(1,sizeof(struct ad0x0_i2c_cmd_s *)); if(!xqi2c2_01)ad0x0_err(); //I2CX->CR1 |= I2C_CR1_PE; //I2CX->CR2 |= (I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN); //pins configuing in cubemx...main.c } void ad0x0_i2c2_set_restart_func(void (*_pfunc_on_error)(void), void (*_pfunc_on_i2c_restart)(void)) { i2c_desc.pfunc_on_error=_pfunc_on_error; i2c_desc.pfunc_on_i2c_restart=_pfunc_on_i2c_restart; } void ad0x0_i2c2_deinit(void) { //I2CX->CR2 &= ~(I2C_CR2_ITERREN|I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN); I2CX->CR1 &= ~I2C_CR1_PE; while(I2CX->CR1 & I2C_CR1_PE); ad0x0_i2c2_initq(); I2CX->CR1 |= I2C_CR1_PE; //I2CX->CR2 |= (I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN); //pins configuing in cubemx...main.c } uint8_t ad0x0_i2c2_get_ext_async2(uint8_t *_p_out_handle,void **_p_out_i2c_ext_t){ while( !ad0x0_i2c_ext_get(_p_out_handle, (ad0x0_i2c_ext_t**)_p_out_i2c_ext_t) ){ __enable_irq(); set_events(I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN); ad0x0_i2c2_wait_cycles++; osDelay(1); } return 1; } uint8_t ad0x0_i2c2_get_ext_setbuf(uint8_t *_tx_pbuf,uint8_t *_rx_pbuf, uint8_t _count){ //c_enter_ext++; uint8_t i; ad0x0_i2c_ext_t *pf; ad0x0_i2c2_get_ext_async2(&i,(void**)&pf); // if(pf->pSetTXRXBuf ||pf->_p_cb_func|| pf->calls_count)ad0x0_i2c2_err();//УБРАТЬ pf->pbuf_tx=_tx_pbuf; pf->pbuf_rx=_rx_pbuf; pf->pbuf_count=_count; //pf->i2c=I2; pf->p_pre_SetTXRXBuf=EXT_SetTXRXBuf_i2c;//ну я хз, пока делаем так... ПЕРЕДЕЛАТЬ!!!!!! return i; //ad0x0_i2c2_push(ADQ_USE_EXT,i); //c_enter_ext--; } void ad0x0_i2c2_push_ext_setfunc(uint8_t _sf_id,void (*_p_cb_func)(uint8_t _sf_id,ad0x0_i2c_desc_s *pdi2c,void *p_i2c_ext_t)){ //c_enter_ext++; uint8_t i; ad0x0_i2c_ext_t *pf; ad0x0_i2c2_get_ext_async2(&i,(void**)&pf); pf->sf_id=_sf_id; pf->_p_post_cb_func=_p_cb_func;//ну я хз, пока делаем так... ПЕРЕДЕЛАТЬ!!!!!! //pf->=SPIX; ad0x0_i2c2_push(ADQ_USE_EXT,i); //c_enter_ext--; } void ad0x0_i2c2_err2(char *_str){ if(strcmp(_str,"suka")==0){ __ASM("nop"); } ad0x0_i2c2_err(); }