/** * ISR for CAN. Normal Tx operation * * @param unit CAN controller number( from 0 ) */ static void Can_TxIsr(int unit) { CAN_HW_t *canHw= GetController(unit); const Can_ControllerConfigType *canHwConfig= CAN_GET_CONTROLLER_CONFIG(Can_Global.channelMap[unit]); Can_UnitType *canUnit = CAN_GET_PRIVATE_DATA(unit); const Can_HardwareObjectType *hohObj; // Loop over all the Hoh's hohObj= canHwConfig->Can_Hoh; --hohObj; do { ++hohObj; if (hohObj->CanObjectType == CAN_OBJECT_TYPE_TRANSMIT) { CanIf_TxConfirmation(canUnit->swPduHandle); canUnit->swPduHandle = 0; // Is this really necessary ?? // Clear Tx interrupt CAN_ClearITPendingBit(canHw,CAN_IT_RQCP0); CAN_ClearITPendingBit(canHw,CAN_IT_RQCP1); CAN_ClearITPendingBit(canHw,CAN_IT_RQCP2); } } while ( !hohObj->Can_EOL); }
/** * Function that finds the Hoh( HardwareObjectHandle ) from a Hth * A HTH may connect to one or several HOH's. Just find the first one. * * @param hth The transmit handle * @returns Ptr to the Hoh */ LOCAL const Can_HardwareObjectType * Can_FindHoh( Can_Arc_HTHType hth , uint32* controller) { const Can_HardwareObjectType *hohObj; const Can_ObjectHOHMapType *map; const Can_ControllerConfigType *canHwConfig; map = &Can_Global.CanHTHMap[hth]; #if(CAN_DEV_ERROR_DETECT == STD_ON) // Verify that this is the correct map if (map->CanHOHRef->CanObjectId != hth) { Det_ReportError(MODULE_ID_CAN, 0, CAN_WRITE_SERVICE_ID, CAN_E_PARAM_HANDLE); } #endif canHwConfig= CAN_GET_CONTROLLER_CONFIG(Can_Global.channelMap[map->CanControllerRef]); hohObj = map->CanHOHRef; // Verify that this is the correct Hoh type if ( hohObj->CanObjectType == CAN_OBJECT_TYPE_TRANSMIT) { *controller = map->CanControllerRef; return hohObj; } #if(CAN_DEV_ERROR_DETECT == STD_ON) Det_ReportError(MODULE_ID_CAN, 0, CAN_WRITE_SERVICE_ID, CAN_E_PARAM_HANDLE); #endif return NULL; }
// Unitialize the module EXPORT void Can_DeInit() { Can_UnitType *canUnit; int configId; const Can_ControllerConfigType *canHwConfig; uint32 ctlrId; for (configId=0; configId < CAN_CTRL_CONFIG_CNT; configId++) { canHwConfig = CAN_GET_CONTROLLER_CONFIG(configId); ctlrId = canHwConfig->CanControllerId; canUnit = CAN_GET_PRIVATE_DATA(ctlrId); canUnit->state = CANIF_CS_UNINIT; Can_DisableControllerInterrupts(ctlrId); canUnit->lock_cnt = 0; // Clear stats memset(&canUnit->stats, 0, sizeof(Can_StatisticsType)); } Can_Global.config = NULL; Can_Global.driverState = CAN_UNINIT; return; }
/* ####################### FUNCTIONs ########################### */ EXPORT void Can_Init(const Can_ConfigType* Config) { Can_UnitType *canUnit; const Can_ControllerConfigType *canHwConfig; const Can_HardwareObjectType* hoh; uint8 ctlrId; int configId; #if(CAN_DEV_ERROR_DETECT == STD_ON) if(CAN_UNINIT != Can_Global.driverState) { Det_ReportError(MODULE_ID_CAN,0,CAN_INIT_SERVICE_ID,CAN_E_TRANSITION); return; } if(NULL == Config) { Det_ReportError(MODULE_ID_CAN,0,CAN_INIT_SERVICE_ID,CAN_E_PARAM_POINTER); return; } #endif /* save config */ Can_Global.config = Config; Can_Global.driverState = CAN_READY; Can_Hw_Init(Config); for (configId=0; configId < CAN_CTRL_CONFIG_CNT; configId++) { canHwConfig = CAN_GET_CONTROLLER_CONFIG(configId); ctlrId = canHwConfig->CanControllerId; // Assign the configuration channel used later.. Can_Global.channelMap[ctlrId] = configId; Can_Global.configured |= (1<<ctlrId); canUnit = CAN_GET_PRIVATE_DATA(ctlrId); canUnit->state = CANIF_CS_STOPPED; canUnit->lock_cnt = 0; // Clear stats memset(&canUnit->stats, 0, sizeof(Can_StatisticsType)); //This can be done by CanIf //Can_InitController(ctlrId, canHwConfig); // Loop through all Hohs and map them into the HTHMap hoh = canHwConfig->Can_Hoh; hoh--; do { hoh++; if (hoh->CanObjectType == CAN_OBJECT_TYPE_TRANSMIT) { Can_Global.CanHTHMap[hoh->CanObjectId].CanControllerRef = canHwConfig->CanControllerId; Can_Global.CanHTHMap[hoh->CanObjectId].CanHOHRef = hoh; } } while (!hoh->Can_EOL); } }
EXPORT Can_ReturnType Can_Hw_Write( Can_HwHandleType/* Can_HTHType */ hth, const Can_PduType *pduInfo ) { Can_ReturnType rv = CAN_OK; CAN_HW_t *canHw; const Can_HardwareObjectType *hohObj; const Can_ControllerConfigType *canHwConfig; uint32 controller; imask_t state; hohObj = Can_FindHoh(hth, &controller); if (hohObj == NULL) return CAN_NOT_OK; Can_UnitType *canUnit = CAN_GET_PRIVATE_DATA(controller); canHw = GetController(controller); Irq_Save(state); CanTxMsg TxMessage; TxMessage.RTR=CAN_RTR_DATA; TxMessage.DLC=pduInfo->length; memcpy(TxMessage.Data, pduInfo->sdu, pduInfo->length); if (hohObj->CanIdType == CAN_ID_TYPE_EXTENDED) { TxMessage.IDE=CAN_ID_EXT; TxMessage.ExtId=pduInfo->id; } else { TxMessage.IDE=CAN_ID_STD; TxMessage.StdId=pduInfo->id; } // check for any free box if(CAN_Transmit(canHw,&TxMessage) != CAN_NO_MB) { canHwConfig = CAN_GET_CONTROLLER_CONFIG(Can_Global.channelMap[controller]); if( canHwConfig->CanTxProcessing == CAN_PROCESS_TYPE_INTERRUPT ) { /* Turn on the tx interrupt mailboxes */ CAN_ITConfig(canHw,CAN_IT_TME, ENABLE); } // Increment statistics canUnit->stats.txSuccessCnt++; // Store pdu handle in unit to be used by TxConfirmation canUnit->swPduHandle = pduInfo->swPduHandle; } else { rv = CAN_BUSY; } Irq_Restore(state); return rv; }
/** * ISR for CAN. Normal Rx/operation * * @param unit CAN controller number( from 0 ) */ static void Can_RxIsr(int unit) { CAN_HW_t *canHw= GetController(unit); const Can_ControllerConfigType *canHwConfig= CAN_GET_CONTROLLER_CONFIG(Can_Global.channelMap[unit]); Can_UnitType *canUnit = CAN_GET_PRIVATE_DATA(unit); const Can_HardwareObjectType *hohObj; CanRxMsg RxMessage; RxMessage.StdId=0x00; RxMessage.ExtId=0x00; RxMessage.IDE=0; RxMessage.DLC=0; RxMessage.FMI=0; RxMessage.Data[0]=0x00; RxMessage.Data[1]=0x00; CAN_Receive(canHw,CAN_FIFO0, &RxMessage); // Loop over all the Hoh's hohObj= canHwConfig->Can_Hoh; --hohObj; do { ++hohObj; if (hohObj->CanObjectType == CAN_OBJECT_TYPE_RECEIVE) { Can_IdType id=0; // According to autosar MSB shuould be set if extended if (RxMessage.IDE != CAN_ID_STD) { id = RxMessage.ExtId; id |= 0x80000000; } else { id = RxMessage.StdId; } CanIf_RxIndication(hohObj->CanObjectId, id, RxMessage.DLC, (uint8 *)&RxMessage.Data[0] ); // Next layer will copy // Increment statistics canUnit->stats.rxSuccessCnt++; } } while ( !hohObj->Can_EOL); }
EXPORT void Can_Hw_EnableControllerInterrupts( uint8 controller ) { imask_t state; Can_UnitType *canUnit; CAN_HW_t *canHw; const Can_ControllerConfigType *canHwConfig; canUnit = CAN_GET_PRIVATE_DATA(controller); VALIDATE_NO_RV( (canUnit->state!=CANIF_CS_UNINIT), 0x5, CAN_E_UNINIT ); Irq_Save(state); if( canUnit->lock_cnt > 1 ) { // IRQ should still be disabled so just decrement counter canUnit->lock_cnt--; Irq_Restore(state); return; } else if (canUnit->lock_cnt == 1) { canUnit->lock_cnt = 0; } Irq_Restore(state); canHw = GetController(controller); canHwConfig = CAN_GET_CONTROLLER_CONFIG(Can_Global.channelMap[controller]); if( canHwConfig->CanRxProcessing == CAN_PROCESS_TYPE_INTERRUPT ) { /* Turn on the rx interrupt */ CAN_ITConfig(canHw, CAN_IT_FMP0, ENABLE); } if( canHwConfig->CanTxProcessing == CAN_PROCESS_TYPE_INTERRUPT ) { /* Turn on the tx interrupt mailboxes */ CAN_ITConfig(canHw, CAN_IT_TME, ENABLE); } // BusOff here represents all errors and warnings if( canHwConfig->CanBusOffProcessing == CAN_PROCESS_TYPE_INTERRUPT ) { /* Turn on the bus off/tx warning/rx warning and error and rx */ CAN_ITConfig(canHw, CAN_IT_BOF | CAN_IT_ERR | CAN_IT_WKU, ENABLE); } return; }
EXPORT Std_ReturnType Can_Hw_InitController(uint8 controller,const Can_ControllerConfigType* config) { CAN_HW_t *canHw; uint8_t tq; uint8_t tqSync; uint8_t tq1; uint8_t tq2; uint32_t clock; Can_UnitType *canUnit; uint8 cId = controller; const Can_ControllerConfigType *canHwConfig; const Can_HardwareObjectType *hohObj; canUnit = CAN_GET_PRIVATE_DATA(controller); canHw = GetController(cId); canHwConfig = CAN_GET_CONTROLLER_CONFIG(Can_Global.channelMap[cId]); // Start this baby up CAN_DeInit(canHw); /* CAN filter init. We set up two filters - one for the master (CAN1) and * one for the slave (CAN2) * * CAN_SlaveStartBank(n) denotes which filter is the first of the slave. * * The filter registers reside in CAN1 and is shared to CAN2, so we only need * to set up this once. */ // We let all frames in and do the filtering in software. CAN_FilterInitTypeDef CAN_FilterInitStructure; CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000; CAN_FilterInitStructure.CAN_FilterIdLow=0x0000; CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000; CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000; CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0; CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; // Init filter 0 (CAN1/master) CAN_FilterInitStructure.CAN_FilterNumber=0; CAN_FilterInit(&CAN_FilterInitStructure); // Init filter 1 (CAN2/slave) CAN_FilterInitStructure.CAN_FilterNumber=1; CAN_FilterInit(&CAN_FilterInitStructure); // Set which filter to use for CAN2. CAN_SlaveStartBank(1); // acceptance filters hohObj = canHwConfig->Can_Hoh; --hohObj; do { ++hohObj; if (hohObj->CanObjectType == CAN_OBJECT_TYPE_RECEIVE) { // TODO Hw filtering } }while( !hohObj->Can_EOL ); // Clock calucation // ------------------------------------------------------------------- // // * 1 TQ = Sclk period( also called SCK ) // * Ftq = Fcanclk / ( PRESDIV + 1 ) = Sclk // ( Fcanclk can come from crystal or from the peripheral dividers ) // // --> // TQ = 1/Ftq = (PRESDIV+1)/Fcanclk --> PRESDIV = (TQ * Fcanclk - 1 ) // TQ is between 8 and 25 clock = McuE_GetSystemClock()/2; tqSync = config->CanControllerPropSeg + 1; tq1 = config->CanControllerSeg1 + 1; tq2 = config->CanControllerSeg2 + 1; tq = tqSync + tq1 + tq2; CAN_InitTypeDef CAN_InitStructure; CAN_StructInit(&CAN_InitStructure); /* CAN cell init */ CAN_InitStructure.CAN_TTCM=DISABLE; CAN_InitStructure.CAN_ABOM=ENABLE; CAN_InitStructure.CAN_AWUM=ENABLE; CAN_InitStructure.CAN_NART=DISABLE; CAN_InitStructure.CAN_RFLM=DISABLE; CAN_InitStructure.CAN_TXFP=DISABLE; if(config->Can_Loopback){ CAN_InitStructure.CAN_Mode=CAN_Mode_LoopBack; }else{ CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; } CAN_InitStructure.CAN_SJW=config->CanControllerPropSeg; CAN_InitStructure.CAN_BS1=config->CanControllerSeg1; CAN_InitStructure.CAN_BS2=config->CanControllerSeg2; CAN_InitStructure.CAN_Prescaler= clock/(config->CanControllerBaudRate*1000*tq); if(CANINITOK != CAN_Init(canHw,&CAN_InitStructure)) { return E_NOT_OK; } canUnit->state = CANIF_CS_STOPPED; Can_EnableControllerInterrupts(cId); return E_OK; }
EXPORT void Can_Hw_Init(const Can_ConfigType* Config) { int configId; NVIC_InitTypeDef NVIC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; const Can_ControllerConfigType *canHwConfig; /* All CAN ISR use the same priority */ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; for (configId=0; configId < CAN_CTRL_CONFIG_CNT; configId++) { canHwConfig = CAN_GET_CONTROLLER_CONFIG(configId); // Note! // Could install handlers depending on HW objects to trap more errors // in configuration switch( canHwConfig->CanControllerId ) { #ifndef STM32F10X_CL case CAN_CTRL_1: { INSTALL_HANDLERS(Can_1, CAN1_SCE_IRQn, USB_LP_CAN1_RX0_IRQn, USB_HP_CAN1_TX_IRQn); /* GPIO clock enable */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO |RCC_APB2Periph_GPIOD, ENABLE); /* CAN1 Periph clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); /* Configure CAN pin: RX */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//GPIO_Pin_CAN_RX; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOD, &GPIO_InitStructure); /* Configure CAN pin: TX */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//GPIO_Pin_CAN_TX; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOD, &GPIO_InitStructure); /* USE PD0 -->Rx PD1 -->Tx*/ GPIO_PinRemapConfig(GPIO_Remap2_CAN1 , ENABLE); /* Enable CAN1 SCE interrupt IRQ */ NVIC_InitStructure.NVIC_IRQChannel = CAN1_SCE_IRQn; NVIC_Init(&NVIC_InitStructure); /* Enable CAN1 RX0 interrupt IRQ channel */ NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn; NVIC_Init(&NVIC_InitStructure); /* Enable CAN1 TX interrupt IRQ channel */ NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_TX0_IRQn; NVIC_Init(&NVIC_InitStructure); break; } #else case CAN_CTRL_1: { INSTALL_HANDLERS(Can_1, CAN1_SCE_IRQn, CAN1_RX0_IRQn, CAN1_TX_IRQn); /* GPIO clock enable */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO |RCC_APB2Periph_GPIOD, ENABLE); /* CAN1 Periph clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); /* Configure CAN pin: RX */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//GPIO_Pin_CAN_RX; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOD, &GPIO_InitStructure); /* Configure CAN pin: TX */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//GPIO_Pin_CAN_TX; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOD, &GPIO_InitStructure); /* USE PD0 -->Rx PD1 -->Tx*/ GPIO_PinRemapConfig(GPIO_Remap2_CAN1 , ENABLE); /* Enable CAN1 SCE interrupt IRQ */ NVIC_InitStructure.NVIC_IRQChannel = CAN1_SCE_IRQn; NVIC_Init(&NVIC_InitStructure); /* Enable CAN1 RX0 interrupt IRQ channel */ NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn; NVIC_Init(&NVIC_InitStructure); /* Enable CAN1 TX interrupt IRQ channel */ NVIC_InitStructure.NVIC_IRQChannel = CAN1_TX_IRQn; NVIC_Init(&NVIC_InitStructure); break; } case CAN_CTRL_2: { INSTALL_HANDLERS(Can_2, CAN2_SCE_IRQn, CAN2_RX0_IRQn, CAN2_TX_IRQn); /* GPIO clock enable */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO |RCC_APB2Periph_GPIOB, ENABLE); /* CAN2 Periph clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2, ENABLE); /* Configure CAN pin: RX */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//GPIO_Pin_CAN_RX; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOB, &GPIO_InitStructure); /* Configure CAN pin: TX */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//GPIO_Pin_CAN_TX; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); /* USE PB5 -->Rx PB6 -->Tx*/ GPIO_PinRemapConfig(GPIO_Remap_CAN2 , ENABLE); /* Enable CAN2 SCE interrupt IRQ */ NVIC_InitStructure.NVIC_IRQChannel = CAN2_SCE_IRQn; NVIC_Init(&NVIC_InitStructure); /* Enable CAN2 RX0 interrupt IRQ channel */ NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX0_IRQn; NVIC_Init(&NVIC_InitStructure); /* Enable CAN2 TX interrupt IRQ channel */ NVIC_InitStructure.NVIC_IRQChannel = CAN2_TX_IRQn; NVIC_Init(&NVIC_InitStructure); break; } #endif default: AR_ASSERT(0); } } return; }