985 lines
32 KiB
C
985 lines
32 KiB
C
/*********************************************************************************************************************
|
|
* Copyright (c) 2021, Infineon Technologies AG
|
|
*
|
|
*
|
|
* Distributed under the Boost Software License, Version 1.0.
|
|
*
|
|
*
|
|
* Boost Software License - Version 1.0 - August 17th, 2003
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person or organization
|
|
* obtaining a copy of the software and accompanying documentation covered by
|
|
* this license (the "Software") to use, reproduce, display, distribute,
|
|
* execute, and transmit the Software, and to prepare derivative works of the
|
|
* Software, and to permit third-parties to whom the Software is furnished to
|
|
* do so, all subject to the following:
|
|
*
|
|
* The copyright notices in the Software and this entire statement, including
|
|
* the above license grant, this restriction and the following disclaimer,
|
|
* must be included in all copies of the Software, in whole or in part, and
|
|
* all derivative works of the Software, unless such copies or derivative
|
|
* works are solely in the form of machine-executable object code generated by
|
|
* a source language processor.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
|
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
|
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*
|
|
*********************************************************************************************************************/
|
|
|
|
|
|
/********************************************************************************************************
|
|
* @file TLE926x.c
|
|
*
|
|
* @brief Implementation of main library functions
|
|
*
|
|
* @version V1.0.0
|
|
* @date
|
|
* @author Fedy Farhat
|
|
* @author Michael Schaffarczyk
|
|
********************************************************************************************************/
|
|
|
|
|
|
/* ================================================================================ */
|
|
/* ============================ HEADER FILES ================================ */
|
|
/* ================================================================================ */
|
|
|
|
#include "TLE926x.h"
|
|
#include "SBC_TLE926x.h"
|
|
#include <stdio.h>
|
|
#include "plib_port.h"
|
|
|
|
|
|
/* ================================================================================ */
|
|
/* ============================== Variables ================================= */
|
|
/* ================================================================================ */
|
|
#ifndef TRUE
|
|
#define TRUE 1
|
|
#endif
|
|
|
|
#ifndef FALSE
|
|
#define FALSE 0
|
|
#endif
|
|
|
|
static uint8_t wd_config;
|
|
/* -------------------------------- ISR Handling --------------------------------- */
|
|
|
|
|
|
static SBC_Func_Callback SBC_ISR_Callbacks[60];
|
|
static uint32_t SBC_ISR_Vectors[60];
|
|
static uint8_t SBC_ISR_ReadOutRegs[60];
|
|
static uint8_t SBC_ISR_ReadOutVals[60];
|
|
static uint8_t SBC_RegisteredCallbacks = 0;
|
|
static uint8_t SBC_RegisteredRedoutRegs = 0;
|
|
uint16_t SBC_Mode=0;
|
|
uint16_t SBC_Mode_VCC1=0;
|
|
uint16_t SBC_Mode_VCC2=0;
|
|
|
|
/* ================================================================================ */
|
|
/* =========================== Library Functions ============================ */
|
|
/* ================================================================================ */
|
|
|
|
|
|
/* -------------------------------- Main Functions ------------------------------- */
|
|
|
|
// trigger the Watchdog
|
|
SBC_ErrorCode sbc_wd_trigger(void) {
|
|
SBC_ErrorCode errCode;
|
|
// if (wd_config == (sbc_read_reg(SBC_WD_CTRL)&0xFF)) {
|
|
// return sbc_write_reg(SBC_WD_CTRL, wd_config, NULL);
|
|
// }
|
|
sbc_write_reg(SBC_WD_CTRL, wd_config, NULL);
|
|
|
|
// SBC_Mode_VCC2 = sbc_read_reg(SBC_SUP_STAT_1);
|
|
// SBC_Mode_VCC1 = sbc_read_reg(SBC_SUP_STAT_2);
|
|
// sbc_write_reg(SBC_M_S_CTRL,0x8,0);
|
|
// errCode.SBC_Register = SBC_WD_CTRL;
|
|
// errCode.flippedBitsMask = ((uint8_t)sbc_read_reg(SBC_WD_CTRL)) ^ wd_config;
|
|
// errCode.expectedValue = wd_config;
|
|
errCode.SBC_Register = 0;
|
|
errCode.flippedBitsMask = 0;
|
|
errCode.expectedValue = 0;
|
|
return errCode;
|
|
}
|
|
void sbc_trig_reset(void)
|
|
{
|
|
/*soft reset*/
|
|
//sbc_write_reg_field (SBC_M_S_CTRL, MODE_MASK, SBC_RESET, 0x00); // M_S_CTRL(0x81)
|
|
sbc_init();
|
|
}
|
|
|
|
// Read the addressed register
|
|
uint16_t sbc_read_reg(sbc_register_t sbc_register) {
|
|
/* Read and return data - Bit[15:8] = Status Information Field - Bit [7:0] Register data */
|
|
return SBC_SPI_TRANSFER16(SBC_READ_MASK & sbc_register, 0x00);
|
|
}
|
|
|
|
// Read register bit
|
|
uint8_t sbc_read_reg_field(sbc_register_t sbc_register, sbc_bit_mask_t bit_mask) {
|
|
uint8_t data = ((uint8_t)sbc_read_reg(sbc_register)) & 0xFFU;
|
|
return (data & bit_mask) >> SBC_BITPOSITION(bit_mask);
|
|
}
|
|
|
|
|
|
// Write value to a register
|
|
SBC_ErrorCode sbc_write_reg(sbc_register_t sbc_register, uint8_t SBC_Val, uint16_t * returnval) {
|
|
SBC_ErrorCode errCode;
|
|
uint16_t returndata = SBC_SPI_TRANSFER16(SBC_WRITE_BIT | sbc_register, SBC_Val);
|
|
if(returnval != NULL) {
|
|
*returnval = returndata;
|
|
}
|
|
|
|
// errCode.SBC_Register = sbc_register;
|
|
// errCode.flippedBitsMask = ((uint8_t)sbc_read_reg(sbc_register)) ^ SBC_Val;
|
|
// errCode.expectedValue = SBC_Val;
|
|
errCode.SBC_Register = 0;
|
|
errCode.flippedBitsMask = 0;
|
|
errCode.expectedValue = 0;
|
|
|
|
return errCode;
|
|
}
|
|
|
|
/*Write bit value in register*/
|
|
SBC_ErrorCode sbc_write_reg_field(sbc_register_t sbc_register, sbc_bit_mask_t bit_mask, uint8_t val, uint16_t * returnval) {
|
|
SBC_ErrorCode errCode;
|
|
|
|
/* Read data out of register to be manipulated */
|
|
uint16_t returndata = sbc_read_reg(sbc_register);
|
|
if(returnval != NULL) {
|
|
*returnval = returndata;
|
|
}
|
|
/* pick the first 8 bit of read SBC_Reg, meant register data [7:0]*/
|
|
uint8_t data = (uint8_t)returndata;
|
|
|
|
/* Set the used bit field to all 0 */
|
|
data &= ~(bit_mask);
|
|
|
|
/* Configure new data to bit field */
|
|
data |= (val << SBC_BITPOSITION(bit_mask));
|
|
|
|
(void)SBC_SPI_TRANSFER16(SBC_WRITE_BIT | sbc_register, data);
|
|
|
|
errCode.SBC_Register = sbc_register;
|
|
errCode.expectedValue = (val << SBC_BITPOSITION(bit_mask));
|
|
uint8_t actualValue = ((uint8_t)sbc_read_reg(sbc_register)) & bit_mask;
|
|
errCode.flippedBitsMask = errCode.expectedValue ^ actualValue;
|
|
|
|
return errCode;
|
|
}
|
|
|
|
void delay(uint32_t val)
|
|
{
|
|
volatile uint32_t temp = 0xFF;
|
|
|
|
while(val--)
|
|
{
|
|
while(temp--);
|
|
temp = 0xFF;
|
|
}
|
|
}
|
|
|
|
void CyclicTskSchM_TimerSync (void);
|
|
|
|
/* initialize SBC */
|
|
SBC_ErrorCode sbc_init(void) {
|
|
SBC_ErrorCode errCode;
|
|
uint8_t i;
|
|
uint8_t delay_cnt;
|
|
uint8_t WD_CTRL = CW_WD_CTRL;
|
|
uint8_t checksum = WD_CTRL;
|
|
uint16_t readback;
|
|
|
|
checksum = checksum ^ checksum >> 4;
|
|
checksum = checksum ^ checksum >> 2;
|
|
checksum = checksum ^ checksum >> 1;
|
|
|
|
|
|
if((checksum & 1) > 0) {
|
|
/* Set parity bit */
|
|
WD_CTRL = WD_CTRL | 0x80U; //
|
|
}
|
|
wd_config = WD_CTRL;
|
|
|
|
/* Describes initialization sequence.
|
|
init Sequence containing {reg_address, reg_value}*/
|
|
uint8_t initSequence[4][2] = {
|
|
{SBC_WD_CTRL, WD_CTRL},//0x04 TimeOut; 200ms period
|
|
{SBC_M_S_CTRL, CW_M_S_CTRL},//0x18 SBC normal;vcc3off;vcc2 on in normal;
|
|
{SBC_BUS_CTRL_1, CW_BUS_CTRL_1},//0x03 lin off; can normal
|
|
|
|
/* End Configuration */
|
|
{0x00U, 0x00U}
|
|
};
|
|
|
|
|
|
delay_cnt = 10;
|
|
do{
|
|
CyclicTskSchM_TimerSync();
|
|
}while(delay_cnt--);
|
|
|
|
|
|
|
|
/* Write all initialization items to Lite SBC
|
|
write the above defined reg_values inside the real registers on Lite SBC*/
|
|
i =0;
|
|
while(initSequence[i][0] != 0x00U || initSequence[i][1] != 0x00U) {
|
|
while((readback&0xff) != initSequence[i][1])
|
|
{
|
|
errCode = sbc_write_reg((sbc_register_t) initSequence[i][0],(sbc_register_t) initSequence[i][1], &readback);
|
|
delay(1);//test:16us
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
errCode.SBC_Register = 0x00;
|
|
errCode.flippedBitsMask = 0x00;
|
|
errCode.expectedValue = 0x00;
|
|
return errCode;
|
|
}
|
|
#if 0
|
|
/* initialize SBC */
|
|
SBC_ErrorCode sbc_init(void) {
|
|
SBC_ErrorCode errCode;
|
|
|
|
uint16_t famprod;
|
|
uint8_t sbc_family;
|
|
//uint8_t sbc_product;
|
|
uint8_t i;
|
|
uint8_t cond;
|
|
uint8_t delay_cnt;
|
|
|
|
uint8_t sbc_reset_init;
|
|
uint8_t sbc_init;
|
|
uint8_t sbc_init_cnt;
|
|
|
|
uint8_t WD_CTRL = CW_WD_CTRL;
|
|
//uint8_t SWK_ID3_CTRL, SWK_ID2_CTRL, SWK_ID1_CTRL, SWK_ID0_CTRL;
|
|
//uint8_t SWK_MASK_ID3_CTRL, SWK_MASK_ID2_CTRL, SWK_MASK_ID1_CTRL, SWK_MASK_ID0_CTRL;
|
|
uint8_t SWK_CAN_FD_CTRL = CW_SWK_CAN_FD_CTRL;
|
|
|
|
uint8_t checksum = WD_CTRL;
|
|
|
|
|
|
checksum = checksum ^ checksum >> 4;
|
|
checksum = checksum ^ checksum >> 2;
|
|
checksum = checksum ^ checksum >> 1;
|
|
|
|
|
|
if((checksum & 1) > 0) {
|
|
/* Set parity bit */
|
|
WD_CTRL = WD_CTRL | 0x80U; //
|
|
}
|
|
wd_config = WD_CTRL;
|
|
|
|
/* Check if ID is configured to be extended */
|
|
if((CW_SWK_ID0_CTRL & IDE_MASK ) == SBC_IDE_EXTENDED) {
|
|
|
|
} else {
|
|
|
|
}
|
|
|
|
|
|
/* DIS_ERR_CNT is set only when FD Tolerance is set.
|
|
Set DIS_ERR_CNT value to 1 if the value of CAN_FD_EN is 1 */
|
|
|
|
if((CW_SWK_CAN_FD_CTRL & CAN_FD_EN_MASK) == SBC_CAN_FD_EN_ENABLED) {
|
|
SWK_CAN_FD_CTRL |= SBC_DIS_ERR_CNT_DISABLED << SBC_BITPOSITION(DIS_ERR_CNT_MASK);
|
|
}
|
|
|
|
/* Describes initialization sequence.
|
|
init Sequence containing {reg_address, reg_value}*/
|
|
uint8_t initSequence[45][2] = {
|
|
{SBC_WD_CTRL, WD_CTRL},
|
|
{SBC_M_S_CTRL, CW_M_S_CTRL},
|
|
{SBC_BUS_CTRL_1, CW_BUS_CTRL_1},
|
|
{SBC_WK_CTRL_1, CW_WK_CTRL_1},
|
|
{0x00U, 0x00U},
|
|
{SBC_HW_CTRL, CW_HW_CTRL},
|
|
{SBC_BUS_CTRL_2, CW_BUS_CTRL_2},
|
|
{SBC_WK_CTRL_2, CW_WK_CTRL_2},
|
|
{SBC_WK_PUPD_CTRL, CW_WK_PUPD_CTRL},
|
|
{SBC_WK_FLT_CTRL, CW_WK_FLT_CTRL},
|
|
{SBC_TIMER1_CTRL, CW_TIMER1_CTRL},
|
|
{SBC_TIMER2_CTRL, CW_TIMER2_CTRL},
|
|
{SBC_SW_SD_CTRL, CW_SW_SD_CTRL},
|
|
{SBC_HS_CTRL_1, CW_HS_CTRL1},
|
|
{SBC_HS_CTRL_2, CW_HS_CTRL2},
|
|
{SBC_PWM1_CTRL, CW_PWM1_CTRL},
|
|
{SBC_PWM2_CTRL, CW_PWM2_CTRL},
|
|
{SBC_PWM_FREQ_CTRL, CW_PWM_FREQ_CTRL}, /* The desired duty cycle should be set first before GPIO is enabled as PWM HS or PWM LS. */
|
|
{SBC_GPIO_CTRL, CW_GPIO_CTRL},
|
|
|
|
/* -------------------------- SELECTIVE WAKE REGISTERS --------------------------- */
|
|
|
|
/* Configuring CDR */ // CDR = Clock and Data Recovery
|
|
{SBC_SWK_CDR_CTRL2, CW_SWK_CDR_CTRL2},
|
|
{SBC_SWK_BTL1_CTRL, CW_SWK_BTL1_CTRL},
|
|
{SBC_SWK_BTL2_CTRL, CW_SWK_BTL2_CTRL},
|
|
{SBC_SWK_CDR_LIMIT_HIGH, CW_SWK_CDR_LIMIT_HIGH_CTRL},
|
|
{SBC_SWK_CDR_LIMIT_LOW, CW_SWK_CDR_LIMIT_LOW_CTRL},
|
|
{SBC_SWK_CDR_CTRL1, ((SBC_SEL_FILT_TC16 << SBC_BITPOSITION(SELFILT_MASK)) | (SBC_CDR_EN_ENABLED << SBC_BITPOSITION(CDR_EN_MASK)))},
|
|
|
|
|
|
|
|
/* Set ID */
|
|
{SBC_SWK_ID3_CTRL, CW_SWK_ID3_CTRL},
|
|
{SBC_SWK_ID2_CTRL, CW_SWK_ID2_CTRL},
|
|
{SBC_SWK_ID1_CTRL, CW_SWK_ID1_CTRL},
|
|
{SBC_SWK_ID0_CTRL, CW_SWK_ID0_CTRL},
|
|
|
|
/* Set Mask */
|
|
{SBC_SWK_MASK_ID3_CTRL, CW_SWK_MASK_ID3_CTRL},
|
|
{SBC_SWK_MASK_ID2_CTRL, CW_SWK_MASK_ID2_CTRL},
|
|
{SBC_SWK_MASK_ID1_CTRL, CW_SWK_MASK_ID1_CTRL},
|
|
{SBC_SWK_MASK_ID0_CTRL, CW_SWK_MASK_ID0_CTRL},
|
|
|
|
/* Set Data */
|
|
|
|
{SBC_SWK_DATA7_CTRL, (uint8_t)(CW_SWK_DATA_H_CTRL >> 24)},
|
|
{SBC_SWK_DATA6_CTRL, (uint8_t)(CW_SWK_DATA_H_CTRL >> 16)},
|
|
{SBC_SWK_DATA5_CTRL, (uint8_t)(CW_SWK_DATA_H_CTRL >> 8)},
|
|
{SBC_SWK_DATA4_CTRL, (uint8_t)(CW_SWK_DATA_H_CTRL >> 0)},
|
|
{SBC_SWK_DATA3_CTRL, (uint8_t)(CW_SWK_DATA_L_CTRL >> 24)},
|
|
{SBC_SWK_DATA2_CTRL, (uint8_t)(CW_SWK_DATA_L_CTRL >> 16)},
|
|
{SBC_SWK_DATA1_CTRL, (uint8_t)(CW_SWK_DATA_L_CTRL >> 8)},
|
|
{SBC_SWK_DATA0_CTRL, (uint8_t)(CW_SWK_DATA_L_CTRL >> 0)},
|
|
|
|
|
|
|
|
/* Set DLC */
|
|
{SBC_SWK_DLC_CTRL, CW_SWK_DLC_CTRL},
|
|
|
|
{SBC_SWK_CAN_FD_CTRL, CW_SWK_CAN_FD_CTRL},
|
|
{SBC_BUS_CTRL_1, CW_BUS_CTRL_1},
|
|
/* End Configuration */
|
|
{0x00U, 0x00U}
|
|
};
|
|
|
|
/* Call SPI Init */
|
|
if(sbc_spi_init() != 0) {
|
|
errCode.SBC_Register = 0x00;
|
|
errCode.flippedBitsMask = 0x01;
|
|
errCode.expectedValue = 0x00;
|
|
return errCode;
|
|
};
|
|
|
|
|
|
/* Check if SBC is Mid-Range SBC */
|
|
famprod = sbc_read_reg(SBC_FAM_PROD_STAT);
|
|
sbc_family = (famprod & FAM_MASK) >> 8;
|
|
cond = (sbc_family == MID_RANGE_SBC_FAMILY) || (sbc_family == MID_RANGE_PLUS_SBC_FAMILY);
|
|
if (!cond) {
|
|
|
|
}
|
|
PORT_PinWrite(PORT_PIN_PA15, 1);
|
|
|
|
while(1)
|
|
{
|
|
sbc_reset_init = TRUE;
|
|
/*soft reset*/
|
|
sbc_write_reg_field (SBC_M_S_CTRL, MODE_MASK, SBC_RESET, 0x00); // M_S_CTRL(0x81)
|
|
delay_cnt = 10;
|
|
do{
|
|
CyclicTskSchM_TimerSync();
|
|
}while(delay_cnt--);
|
|
|
|
/* reset index */
|
|
i =0;
|
|
sbc_init_cnt = 0;
|
|
/* Write all initialization items to Lite SBC
|
|
write the above defined reg_values inside the real registers on Lite SBC*/
|
|
while(1)
|
|
{
|
|
sbc_init = TRUE;
|
|
while(initSequence[i][0] != 0x00U || initSequence[i][1] != 0x00U) {
|
|
errCode = sbc_write_reg((sbc_register_t) initSequence[i][0],(sbc_register_t) initSequence[i][1], NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
//return errCode;
|
|
sbc_init = FALSE;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if(sbc_init == TRUE)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
sbc_init_cnt ++;
|
|
if(sbc_init_cnt >= 10)
|
|
{
|
|
sbc_reset_init = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if(sbc_reset_init == TRUE)/*init ok*/
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
PORT_PinWrite(PORT_PIN_PA15, 0);
|
|
errCode.SBC_Register = 0x00;
|
|
errCode.flippedBitsMask = 0x00;
|
|
errCode.expectedValue = 0x00;
|
|
return errCode;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* -------------------------------- ISR Functions -------------------------------- */
|
|
|
|
/* Callback function*/
|
|
void sbc_register_callback(uint32_t vector_isr, void (*Callback_Handler)(uint8_t callbackHandler)) {
|
|
|
|
/* Save callback */
|
|
SBC_ISR_Callbacks[SBC_RegisteredCallbacks] = Callback_Handler;
|
|
|
|
/* Save callback vector */
|
|
|
|
SBC_ISR_Vectors[SBC_RegisteredCallbacks] = vector_isr;
|
|
|
|
/* Check if the register will be readout already to avoid double-readout later */
|
|
uint8_t RegFound = 0;
|
|
for (uint8_t i = 0; i < SBC_RegisteredRedoutRegs; i++) {
|
|
if (SBC_ISR_ReadOutRegs[i] == ( vector_isr >> 24)) {
|
|
|
|
|
|
RegFound = 1;
|
|
}
|
|
}
|
|
|
|
/* If readout status-reg was not found, register in the readout list */
|
|
if (RegFound == 0) {
|
|
SBC_ISR_ReadOutRegs[SBC_RegisteredRedoutRegs] = (uint8_t)( vector_isr>> 24);
|
|
SBC_RegisteredRedoutRegs++;
|
|
}
|
|
|
|
SBC_RegisteredCallbacks++;
|
|
}
|
|
|
|
|
|
SBC_ErrorCode SBC_ISR(void) {
|
|
SBC_ErrorCode errCode;
|
|
|
|
/* Readout all registered status-registers */
|
|
for (uint8_t i = 0; i < SBC_RegisteredRedoutRegs; i++) {
|
|
SBC_ISR_ReadOutVals[i] = (uint8_t) sbc_read_reg( (sbc_register_t) SBC_ISR_ReadOutRegs[i]);
|
|
}
|
|
|
|
/* Handle all interrupts */
|
|
|
|
for (uint8_t i = 0; i < SBC_RegisteredCallbacks; i++) {
|
|
/* Decode ISR Vector */
|
|
uint8_t Compare = (uint8_t)SBC_ISR_Vectors[i];
|
|
uint8_t FieldPos = (uint8_t)(SBC_ISR_Vectors[i] >> 8);
|
|
uint8_t FieldMsk = (uint8_t)(SBC_ISR_Vectors[i] >> 16);
|
|
uint8_t RegAddr = (uint8_t)(SBC_ISR_Vectors[i] >> 24);
|
|
|
|
/* Readback of associated status-bit */
|
|
uint8_t ReadBack = 0;
|
|
for (uint8_t j = 0; j < SBC_RegisteredRedoutRegs; j++) {
|
|
if (SBC_ISR_ReadOutRegs[j] == RegAddr) {
|
|
ReadBack = SBC_ISR_ReadOutVals[j];
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If compare-values matched -> proceed callback and clear field */
|
|
if (((ReadBack & FieldMsk) >> FieldPos) == Compare) {
|
|
SBC_ISR_Callbacks[i](ReadBack);
|
|
}
|
|
}
|
|
|
|
/* Clear all ISR related registers */
|
|
for (uint8_t i = 0; i < SBC_RegisteredRedoutRegs; i++) {
|
|
errCode = sbc_write_reg( (sbc_register_t) SBC_ISR_ReadOutRegs[i], 0x00U, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
}
|
|
|
|
errCode.SBC_Register = 0x00U;
|
|
errCode.flippedBitsMask = 0x00U;
|
|
errCode.expectedValue = 0x00U;
|
|
return errCode;
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------- API Calls ----------------------------------- */
|
|
/* enter Normal Mode*/
|
|
SBC_ErrorCode sbc_mode_normal(void) {
|
|
return sbc_write_reg_field(SBC_M_S_CTRL, MODE_MASK, SBC_NORMAL_MODE, NULL);
|
|
}
|
|
|
|
/* enter Stop Mode*/
|
|
SBC_ErrorCode sbc_mode_stop (void) {
|
|
return sbc_write_reg_field(SBC_M_S_CTRL, MODE_MASK, SBC_STOP_MODE, NULL);
|
|
}
|
|
|
|
/* enter Sleep Mode*/
|
|
SBC_ErrorCode sbc_mode_sleep(void) {
|
|
uint8_t registerReadOut;
|
|
|
|
SBC_ErrorCode errCode;
|
|
|
|
|
|
|
|
/* Check SBC in Normal Mode */
|
|
uint8_t readData = sbc_read_reg(SBC_M_S_CTRL);
|
|
readData >>= SBC_BITPOSITION(MODE_MASK);
|
|
|
|
if (readData != SBC_NORMAL_MODE) {
|
|
errCode = sbc_mode_normal();
|
|
return errCode;
|
|
}
|
|
|
|
/* If CAN PN is configured */
|
|
if(MATH_EN_PN != 0) {
|
|
|
|
/* Reading value of SWK_STAT. */
|
|
registerReadOut = (uint8_t)sbc_read_reg(SBC_SWK_STAT);
|
|
|
|
/* The selective wake routine should be aborted if sync is not set.
|
|
Note: for SYNC to be set the transceiver must have been in Normal Mode and */
|
|
if((registerReadOut & SYNC_MASK ) >> SBC_BITPOSITION(SYNC_MASK) != SYNC_VALID_FRAME_RECEIVED) {
|
|
errCode.SBC_Register = SBC_SWK_STAT;
|
|
errCode.flippedBitsMask = SYNC_MASK;
|
|
errCode.expectedValue = SYNC_VALID_FRAME_RECEIVED << SBC_BITPOSITION(SYNC_MASK);
|
|
return errCode;
|
|
}
|
|
|
|
|
|
/* Set SWK Configuration valid */
|
|
// set CFG_VAL = 1
|
|
|
|
errCode = sbc_write_reg_field(SBC_SWK_CTRL, CFG_VAL_MASK, SBC_CFG_VAL_VALID, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
|
|
|
|
/* Clear SYSERR bit */
|
|
|
|
errCode = sbc_write_reg_field(SBC_BUS_STAT_1, SYSERR_MASK, 0x00, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
|
|
/* Set CAN Mode to off and once again to desired configuration */
|
|
// CAN OFF
|
|
errCode = sbc_write_reg_field(SBC_BUS_CTRL_1, CAN_MASK, CAN_OFF, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
// CAN ON (with SWK)
|
|
errCode = sbc_write_reg_field(SBC_BUS_CTRL_1, CAN_MASK, CAN_WAKECAPABLE_SWK, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
|
|
/* Check SWK_STAT for SYNC == 1 && SWK_SET == 1 && WUF == 0 && WUP == 0. Ignore CANSIL */
|
|
registerReadOut = (uint8_t)sbc_read_reg(SBC_SWK_STAT);
|
|
if( ((SYNC_MASK & registerReadOut) == SYNC_MASK)
|
|
&& ((SWK_SET_MASK & registerReadOut) == SWK_SET_MASK)
|
|
&& ((WUP_MASK & registerReadOut) != WUP_MASK)
|
|
&& ((WUF_MASK & registerReadOut) != WUF_MASK)) {
|
|
/* Empty */
|
|
|
|
} else {
|
|
errCode.SBC_Register = SBC_SWK_STAT;
|
|
errCode.expectedValue = 0b01000100U;
|
|
errCode.flippedBitsMask = errCode.expectedValue ^ registerReadOut;
|
|
return errCode;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear Wake Status Registers, so that SBC can sleep. */
|
|
errCode = sbc_write_reg(SBC_WK_STAT_1, 0x00, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
errCode = sbc_write_reg(SBC_WK_STAT_2, 0x00, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
|
|
/* Select sleep mode */
|
|
sbc_write_reg_field(SBC_M_S_CTRL, MODE_MASK, SBC_SLEEP_MODE, NULL);
|
|
|
|
errCode.SBC_Register = 0x00U;
|
|
errCode.flippedBitsMask = 0x00U;
|
|
errCode.expectedValue = 0x00U;
|
|
return errCode;
|
|
}
|
|
|
|
/* configure HSx */
|
|
SBC_ErrorCode sbc_hsx_config(sbc_hsx_t hsX, sbc_hs_config_t hsConfig) {
|
|
SBC_ErrorCode errCode = {0,0,0};
|
|
|
|
switch (hsX) {
|
|
case HS1:
|
|
errCode = sbc_write_reg_field(SBC_HS_CTRL_1, HS1_MASK, hsConfig, NULL);
|
|
break;
|
|
case HS2:
|
|
errCode = sbc_write_reg_field(SBC_HS_CTRL_1, HS2_MASK, hsConfig, NULL);
|
|
break;
|
|
case HS3:
|
|
errCode = sbc_write_reg_field(SBC_HS_CTRL_2, HS3_MASK, hsConfig, NULL);
|
|
break;
|
|
case HS4:
|
|
errCode = sbc_write_reg_field(SBC_HS_CTRL_2, HS4_MASK, hsConfig, NULL);
|
|
break;
|
|
|
|
default:
|
|
return errCode;
|
|
}
|
|
return errCode;
|
|
}
|
|
|
|
|
|
|
|
/* CAN MODE*/
|
|
SBC_ErrorCode sbc_can_mode(sbc_can_t CANmode )
|
|
{
|
|
SBC_ErrorCode errCode;
|
|
errCode = sbc_write_reg_field(SBC_BUS_CTRL_1, CAN_MASK, CANmode, NULL);
|
|
|
|
return errCode;
|
|
}
|
|
|
|
|
|
/* LIN MODE */
|
|
SBC_ErrorCode sbc_lin_mode(sbc_lin_module_t linModule, sbc_lin_mode_t linMode) {
|
|
SBC_ErrorCode errCode = {0,0,0};
|
|
uint8_t mr_sbc_variant = sbc_read_reg(SBC_FAM_PROD_STAT) & PROD_MASK;
|
|
/* check if it is a variant with minimum 1 LIN interface*/
|
|
if (mr_sbc_variant & 0b1000) {
|
|
if (linModule == LIN1) {
|
|
errCode = sbc_write_reg_field(SBC_BUS_CTRL_1, LIN1_MASK, linMode, NULL);
|
|
} else {
|
|
/* cheack if it is a variant with 2 LIN interfaces*/
|
|
if (mr_sbc_variant & 0b1100) {
|
|
errCode = sbc_write_reg_field(SBC_BUS_CTRL_2, LIN2_MASK, linMode, NULL);
|
|
} else {
|
|
|
|
return errCode; // default value 0
|
|
}
|
|
}
|
|
} else {
|
|
|
|
return errCode; // default value 0
|
|
}
|
|
return errCode;
|
|
}
|
|
/* WRITE IN System status register*/
|
|
SBC_ErrorCode sbc_sys_stat_write(uint8_t status) {
|
|
return sbc_write_reg(SBC_SYS_STAT_CTRL, status, NULL);
|
|
}
|
|
|
|
/* Read register system status*/
|
|
uint8_t sbc_sys_stat_read(void) {
|
|
return sbc_read_reg(SBC_SYS_STAT_CTRL);
|
|
}
|
|
// disabling WD and entering stop mode
|
|
SBC_ErrorCode sbc_mode_stop_without_watchdog(void) {
|
|
SBC_ErrorCode errCode = sbc_write_reg_field(SBC_WK_CTRL_1, WD_STM_EN_1_MASK, WATCHDOG_DEACTIVED_IN_STOP_MODE, NULL);
|
|
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
errCode = sbc_write_reg_field(SBC_WD_CTRL, WD_STM_EN_0_MASK, WATCHDOG_DEACTIVED_IN_STOP_MODE, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
return sbc_mode_stop();
|
|
}
|
|
|
|
|
|
/* configure cyclic sense function*/
|
|
SBC_ErrorCode sbc_cyclicsense(sbc_timer_t timer, sbc_timer_per_t timerPeriod, sbc_timer_on_t timerOnTime, sbc_hsx_t hsX, sbc_wk_t wk, sbc_wk_pupd_t pupdConfig) {
|
|
SBC_ErrorCode errCode={0,0,0};
|
|
|
|
if (timer == TIMER1) {
|
|
errCode = sbc_write_reg_field(SBC_TIMER1_CTRL, TIMER1_ON_MASK, TIMER_ONTIME_OFF_LOW, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
switch (hsX)
|
|
{
|
|
case HS1:
|
|
errCode = sbc_write_reg_field(SBC_HS_CTRL_1, HS1_MASK, CONTROLLED_BY_TIMER1, NULL);
|
|
break;
|
|
case HS2:
|
|
errCode = sbc_write_reg_field(SBC_HS_CTRL_1, HS2_MASK, CONTROLLED_BY_TIMER1, NULL);
|
|
break;
|
|
case HS3:
|
|
errCode = sbc_write_reg_field(SBC_HS_CTRL_2, HS3_MASK, CONTROLLED_BY_TIMER1, NULL);
|
|
break;
|
|
case HS4:
|
|
errCode = sbc_write_reg_field(SBC_HS_CTRL_2, HS4_MASK, CONTROLLED_BY_TIMER1, NULL);
|
|
break;
|
|
default:
|
|
return errCode;
|
|
}
|
|
|
|
if(errCode.flippedBitsMask > 0){
|
|
return errCode;
|
|
}
|
|
switch (wk) {
|
|
case WK1:
|
|
errCode = sbc_write_reg_field(SBC_WK_FLT_CTRL, WK1_FLT_MASK, FILTER_ONTIME_END_TIMER1, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
errCode = sbc_write_reg_field(SBC_WK_PUPD_CTRL, WK1_PUPD_MASK, pupdConfig, NULL);
|
|
break;
|
|
case WK2:
|
|
errCode = sbc_write_reg_field(SBC_WK_FLT_CTRL, WK2_FLT_MASK, FILTER_ONTIME_END_TIMER1, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
errCode = sbc_write_reg_field(SBC_WK_PUPD_CTRL, WK2_PUPD_MASK, pupdConfig, NULL);
|
|
break;
|
|
case WK3:
|
|
errCode = sbc_write_reg_field(SBC_WK_FLT_CTRL, WK3_FLT_MASK, FILTER_ONTIME_END_TIMER1, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
errCode = sbc_write_reg_field(SBC_WK_PUPD_CTRL, WK3_PUPD_MASK, pupdConfig, NULL);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
|
|
errCode = sbc_write_reg_field(SBC_TIMER1_CTRL, TIMER1_PER_MASK, timerPeriod, NULL);
|
|
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
errCode = sbc_write_reg_field(SBC_TIMER1_CTRL, TIMER1_ON_MASK, timerOnTime, NULL);
|
|
}
|
|
else if (timer == TIMER2)
|
|
{
|
|
errCode = sbc_write_reg_field(SBC_TIMER2_CTRL, TIMER2_ON_MASK, TIMER_ONTIME_OFF_LOW, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
switch (hsX) {
|
|
case HS1:
|
|
errCode = sbc_write_reg_field(SBC_HS_CTRL_1, HS1_MASK, CONTROLLED_BY_TIMER2, NULL);
|
|
break;
|
|
case HS2:
|
|
errCode = sbc_write_reg_field(SBC_HS_CTRL_1, HS2_MASK, CONTROLLED_BY_TIMER2, NULL);
|
|
break;
|
|
case HS3:
|
|
errCode = sbc_write_reg_field(SBC_HS_CTRL_2, HS3_MASK, CONTROLLED_BY_TIMER2, NULL);
|
|
break;
|
|
case HS4:
|
|
errCode = sbc_write_reg_field(SBC_HS_CTRL_2, HS4_MASK, CONTROLLED_BY_TIMER2, NULL);
|
|
break;
|
|
default:
|
|
return errCode;
|
|
}
|
|
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
|
|
switch (wk)
|
|
{
|
|
case WK1:
|
|
errCode = sbc_write_reg_field(SBC_WK_FLT_CTRL, WK1_FLT_MASK, FILTER_ONTIME_END_TIMER2, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
errCode = sbc_write_reg_field(SBC_WK_PUPD_CTRL, WK1_PUPD_MASK, pupdConfig, NULL);
|
|
break;
|
|
case WK2:
|
|
errCode = sbc_write_reg_field(SBC_WK_FLT_CTRL, WK2_FLT_MASK, FILTER_ONTIME_END_TIMER2, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
errCode = sbc_write_reg_field(SBC_WK_PUPD_CTRL, WK2_PUPD_MASK, pupdConfig, NULL);
|
|
break;
|
|
case WK3:
|
|
errCode = sbc_write_reg_field(SBC_WK_FLT_CTRL, WK3_FLT_MASK, FILTER_ONTIME_END_TIMER2, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
errCode = sbc_write_reg_field(SBC_WK_PUPD_CTRL, WK3_PUPD_MASK, pupdConfig, NULL);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
errCode = sbc_write_reg_field(SBC_TIMER2_CTRL, TIMER2_PER_MASK, timerPeriod, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
errCode = sbc_write_reg_field(SBC_TIMER2_CTRL, TIMER2_ON_MASK, timerOnTime, NULL);
|
|
} else {
|
|
return errCode;
|
|
}
|
|
return errCode;
|
|
}
|
|
|
|
/* configure cyclic wake function*/
|
|
SBC_ErrorCode sbc_cyclicwake(sbc_timer_t timer, sbc_timer_per_t timer_period, sbc_timer_on_t timer_on_time) {
|
|
SBC_ErrorCode errCode={0,0,0};
|
|
|
|
if (timer == TIMER1) {
|
|
errCode = sbc_write_reg_field(SBC_WK_CTRL_1, TIMER1_WK_EN_MASK, TIMER_WAKE_DISABLED, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
errCode = sbc_write_reg_field(SBC_TIMER1_CTRL, TIMER1_PER_MASK, timer_period, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
errCode = sbc_write_reg_field(SBC_TIMER1_CTRL, TIMER1_ON_MASK, timer_on_time, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
errCode = sbc_write_reg_field(SBC_WK_CTRL_1, TIMER1_WK_EN_MASK, TIMER_WAKE_ENABLED, NULL);
|
|
}
|
|
else if (timer == TIMER2) {
|
|
errCode = sbc_write_reg_field(SBC_WK_CTRL_1, TIMER2_WK_EN_MASK, TIMER_WAKE_DISABLED, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
|
|
errCode = sbc_write_reg_field(SBC_TIMER2_CTRL, TIMER2_PER_MASK, timer_period, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
errCode = sbc_write_reg_field(SBC_TIMER2_CTRL, TIMER2_ON_MASK, timer_on_time, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
errCode = sbc_write_reg_field(SBC_WK_CTRL_1, TIMER2_WK_EN_MASK, TIMER_WAKE_ENABLED, NULL);
|
|
} else {
|
|
return errCode;
|
|
}
|
|
return errCode;
|
|
}
|
|
|
|
|
|
/* configure watchdog*/
|
|
SBC_ErrorCode sbc_configure_watchdog(sbc_wd_win_t wdWindow, sbc_wd_en_wk_bus_t wdEnableAfterBusWake, sbc_wd_timer_t wdTimer) {
|
|
SBC_ErrorCode errCode;
|
|
/* Calculate checksum */
|
|
uint8_t wd_ctrl = (wdWindow << SBC_BITPOSITION(WD_WIN_MASK))
|
|
| (wdEnableAfterBusWake << SBC_BITPOSITION(WD_EN_WK_BUS_MASK))
|
|
| (wdTimer << SBC_BITPOSITION(WD_TIMER_MASK));
|
|
uint8_t checksum = wd_ctrl;
|
|
|
|
|
|
|
|
checksum = checksum ^ checksum >> 4;
|
|
checksum = checksum ^ checksum >> 2;
|
|
checksum = checksum ^ checksum >> 1;
|
|
|
|
|
|
if((checksum & 1) > 0) {
|
|
/* Set parity bit */
|
|
wd_ctrl = wd_ctrl | 0x80U; //
|
|
}
|
|
errCode = sbc_write_reg(SBC_WD_CTRL, wd_ctrl, NULL);
|
|
if (errCode.flippedBitsMask == 0) {
|
|
|
|
/* Save new Watchdog configuration to global variable */
|
|
wd_config = wd_ctrl;
|
|
}
|
|
return errCode;
|
|
}
|
|
|
|
/* configure PWM*/
|
|
SBC_ErrorCode sbc_configure_pwm(sbc_pwm_t pwm, sbc_pwm_freq_t frequency, uint8_t dutyCycle) {
|
|
SBC_ErrorCode errCode={0,0,0};
|
|
switch (pwm) {
|
|
case PWM1:
|
|
errCode = sbc_write_reg(SBC_PWM1_CTRL, dutyCycle, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
errCode = sbc_write_reg_field(SBC_PWM_FREQ_CTRL, PWM1_FREQ_MASK, frequency, NULL);
|
|
break;
|
|
case PWM2:
|
|
errCode = sbc_write_reg(SBC_PWM2_CTRL, dutyCycle, NULL);
|
|
if(errCode.flippedBitsMask > 0) {
|
|
return errCode;
|
|
}
|
|
errCode = sbc_write_reg_field(SBC_PWM_FREQ_CTRL, PWM2_FREQ_MASK, frequency, NULL);
|
|
break;
|
|
|
|
default:
|
|
return errCode;
|
|
}
|
|
return errCode;
|
|
}
|
|
|
|
/* configure PWM percentage*/
|
|
SBC_ErrorCode sbc_configure_pwm_percentage(sbc_pwm_t pwm, sbc_pwm_freq_t frequency, double duty_cycle) {
|
|
return sbc_configure_pwm(pwm, frequency, (uint8_t)(duty_cycle*0xFFU));
|
|
}
|
|
|
|
/* Configure GPIO*/
|
|
SBC_ErrorCode sbc_configure_gpio(sbc_gpiox_t gpio, sbc_gpio_t gpio_config) {
|
|
SBC_ErrorCode errCode= {0,0,0};
|
|
switch (gpio) {
|
|
case GPIO1:
|
|
errCode = sbc_write_reg_field(SBC_GPIO_CTRL, GPIO1_MASK, gpio_config, NULL);
|
|
break;
|
|
case GPIO2:
|
|
errCode = sbc_write_reg_field(SBC_GPIO_CTRL, GPIO2_MASK, gpio_config, NULL);
|
|
break;
|
|
|
|
default:
|
|
return errCode;
|
|
}
|
|
|
|
return errCode;
|
|
}
|
|
|
|
|
|
/* Configure Failure Output*/
|
|
SBC_ErrorCode sbc_fo_x(uint8_t on) {
|
|
if (on) {
|
|
return sbc_write_reg_field(SBC_HW_CTRL, FO_ON_MASK, FO_ON_ACTIVE, NULL);
|
|
} else {
|
|
return sbc_write_reg_field(SBC_HW_CTRL, FO_ON_MASK, FO_ON_NOT_ACTIVE, NULL);
|
|
}
|
|
}
|
|
/* configure VCC2*/
|
|
SBC_ErrorCode sbc_switch_vcc2(sbc_vcc2_on_t vcc2_value) {
|
|
SBC_ErrorCode errCode;
|
|
|
|
errCode = sbc_write_reg_field(SBC_M_S_CTRL, VCC2_ON_MASK, vcc2_value, NULL);
|
|
|
|
return errCode;
|
|
}
|
|
/* configure VCC3*/
|
|
SBC_ErrorCode sbc_switch_vcc3(sbc_vcc3_on_t vcc3_value) {
|
|
SBC_ErrorCode errCode;
|
|
errCode = sbc_write_reg_field(SBC_M_S_CTRL, VCC3_ON_MASK , vcc3_value, NULL);
|
|
|
|
return errCode;
|
|
}
|