diff --git a/docs/MSD_COMMANDS.md b/docs/MSD_COMMANDS.md index 6b5903597..b70a555ac 100644 --- a/docs/MSD_COMMANDS.md +++ b/docs/MSD_COMMANDS.md @@ -82,3 +82,8 @@ data fast enough from DAPLink and an overflow occurs the text ```SRS0 & RCM_SRS0_WAKEUP_MASK) { + btn_pressed = false; + } + else { + btn_pressed = gpio_get_reset_btn(); + } + + return btn_pressed; +} diff --git a/source/board/microbitv2/IO_Config_Override.h b/source/board/microbitv2/IO_Config_Override.h new file mode 100644 index 000000000..2859c5eb1 --- /dev/null +++ b/source/board/microbitv2/IO_Config_Override.h @@ -0,0 +1,167 @@ +/** + * @file IO_Config_Override.h + * @brief Alternative IO for KL27Z based Hardware Interface Circuit + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __IO_CONFIG_H__ +#define __IO_CONFIG_H__ + +#include "MKL27Z4.h" +#include "compiler.h" +#include "daplink.h" + +// This GPIO configuration is only valid for the KL27 HIC +COMPILER_ASSERT(DAPLINK_HIC_ID == DAPLINK_HIC_ID_KL27Z); + + +// Debug Port I/O Pins + +// SWCLK Pin PTC6 +#define PIN_SWCLK_PORT PORTC +#define PIN_SWCLK_GPIO FGPIOC +#define PIN_SWCLK_BIT (6) +#define PIN_SWCLK (1<C1 |= MCG_C1_IRCLKEN_MASK | MCG_C1_IREFSTEN_MASK; + + /* Select the clock source for the FlexIO + 00 - Clock disabled + 01 - MCGPCLK clock + 10 - OSCERCLK clock + 11 - MCGIRCLK clock + */ + CLOCK_SetFlexio0Clock(3U); + + /* Init flexio, use default configure + * Enable in Doze and fast access mode + * Enable in debug mode + */ + FLEXIO_GetDefaultConfig(&fxioUserConfig); + fxioUserConfig.enableInDoze = true; + FLEXIO_Init(DEMO_FLEXIO_BASEADDR, &fxioUserConfig); +} + +void flexio_pwm_set_dutycycle(uint8_t duty) +{ + uint32_t freq_Hz = DEMO_FLEXIO_FREQUENCY; + + assert((freq_Hz <= FLEXIO_MAX_FREQUENCY) && (freq_Hz >= FLEXIO_MIN_FREQUENCY)); + + uint32_t lowerValue = 0; /* Number of clock cycles in high logic state in one period */ + uint32_t upperValue = 0; /* Number of clock cycles in low logic state in one period */ + uint32_t sum = 0; /* Number of clock cycles in one period */ + flexio_timer_config_t fxioTimerConfig; + + /* Check parameter */ + if (duty >= 255) + { + duty = 254; + PIN_RED_LED_GPIO->PDDR |= PIN_RED_LED; + PIN_RED_LED_GPIO->PSOR = PIN_RED_LED; + PORT_SetPinMux(PIN_RED_LED_PORT, PIN_RED_LED_BIT, kPORT_MuxAsGpio); + } + else if (duty == 0) + { + duty = 1; + PIN_RED_LED_GPIO->PDDR |= PIN_RED_LED; + PIN_RED_LED_GPIO->PCOR = PIN_RED_LED; + PORT_SetPinMux(PIN_RED_LED_PORT, PIN_RED_LED_BIT, kPORT_MuxAsGpio); + } + else { + flexio_pwm_init_pins(); + } + + /* Configure the timer DEMO_FLEXIO_TIMER_CH for generating PWM */ + fxioTimerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(0U); + fxioTimerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal; + fxioTimerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow; + fxioTimerConfig.pinConfig = kFLEXIO_PinConfigOutput; + fxioTimerConfig.pinPolarity = kFLEXIO_PinActiveHigh; + fxioTimerConfig.pinSelect = DEMO_FLEXIO_OUTPUTPIN; /* Set pwm output */ + fxioTimerConfig.timerMode = kFLEXIO_TimerModeDisabled; + fxioTimerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset; + fxioTimerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput; + fxioTimerConfig.timerDisable = kFLEXIO_TimerDisableNever; + fxioTimerConfig.timerEnable = kFLEXIO_TimerEnabledAlways; + fxioTimerConfig.timerReset = kFLEXIO_TimerResetNever; + fxioTimerConfig.timerStart = kFLEXIO_TimerStartBitDisabled; + fxioTimerConfig.timerStop = kFLEXIO_TimerStopBitDisabled; + + /* Calculate timer lower and upper values of TIMCMP */ + /* Calculate the nearest integer value for sum, using formula round(x) = (2 * floor(x) + 1) / 2 */ + /* sum = DEMO_FLEXIO_CLOCK_FREQUENCY / freq_H */ + sum = (DEMO_FLEXIO_CLOCK_FREQUENCY * 2 / freq_Hz + 1) / 2; + /* Calculate the nearest integer value for lowerValue, the high period of the pwm output */ + /* lowerValue = sum * duty / 255 */ + lowerValue = (sum * duty / 127 + 1) / 2; + /* Calculate upper value, the low period of the pwm output */ + upperValue = sum - lowerValue; + fxioTimerConfig.timerCompare = ((upperValue - 1) << 8U) | (lowerValue - 1); + + FLEXIO_SetTimerConfig(DEMO_FLEXIO_BASEADDR, DEMO_FLEXIO_TIMER_CH, &fxioTimerConfig); + + /* Set Timer mode to kFLEXIO_TimerModeDual8BitPWM to start timer */ + DEMO_FLEXIO_BASEADDR->TIMCTL[DEMO_FLEXIO_TIMER_CH] |= FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitPWM); +} + +void flexio_pwm_init_pins(void) +{ + PORT_SetPinMux(PIN_RED_LED_PORT, PIN_RED_LED_BIT, kPORT_MuxAlt6); +} + +void flexio_pwm_deinit_pins(void) +{ + PORT_SetPinMux(PIN_RED_LED_PORT, PIN_RED_LED_BIT, kPORT_PinDisabledOrAnalog); +} diff --git a/source/board/microbitv2/flexio_pwm.h b/source/board/microbitv2/flexio_pwm.h new file mode 100644 index 000000000..d4cd36708 --- /dev/null +++ b/source/board/microbitv2/flexio_pwm.h @@ -0,0 +1,40 @@ +/** + * @file flexio_pwm.h + * @brief + * + * DAPLink Interface Firmware + * Copyright 2020 NXP + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLEXIO_PWM_H_ +#define FLEXIO_PWM_H_ + +#include "IO_Config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void flexio_pwm_init(void); +void flexio_pwm_init_pins(void); +void flexio_pwm_deinit_pins(void); +void flexio_pwm_set_dutycycle(uint8_t duty); + +#ifdef __cplusplus +} +#endif + +#endif /* FLEXIO_PWM_H_ */ diff --git a/source/board/microbitv2/i2c_commands.c b/source/board/microbitv2/i2c_commands.c new file mode 100644 index 000000000..f3e42b159 --- /dev/null +++ b/source/board/microbitv2/i2c_commands.c @@ -0,0 +1,683 @@ +/** + * @file i2c_commands.c + * @brief Microbit appliation layer for I2C operations + * + * DAPLink Interface Firmware + * Copyright 2020 NXP + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "i2c_commands.h" +#include "fsl_i2c.h" +#include "fsl_clock.h" +#include "fsl_port.h" +#include "fsl_flash.h" +#include "settings.h" // for config_get_overflow_detect +#include "main_interface.h" +#include "pwr_mon.h" +#include "power.h" +#include "microbitv2.h" + +/* I2C source clock */ +#define I2C_SLAVE_BASEADDR I2C1 +#define I2C_SLAVE_CLK_SRC I2C1_CLK_SRC +#define I2C_SLAVE_CLK_FREQ CLOCK_GetFreq(I2C1_CLK_SRC) + +#define I2C_SLAVE_LOWER_ADDR_7BIT (0x70U) +#define I2C_SLAVE_UPPER_ADDR_7BIT (0x72U) +#define I2C_DATA_LENGTH (1024U + 8U) + + +static uint8_t g_slave_TX_buff[I2C_DATA_LENGTH]; +static uint8_t g_slave_RX_buff[I2C_DATA_LENGTH]; +i2c_slave_handle_t g_s_handle; +static volatile bool g_SlaveCompletionFlag = false; +static volatile bool g_SlaveRxFlag = false; +static uint8_t address_match = 0; +static uint32_t transferredCount = 0; + +static i2cWriteCallback_t pfWriteCommsCallback = NULL; +static i2cReadCallback_t pfReadCommsCallback = NULL; +static i2cWriteCallback_t pfWriteFlashCallback = NULL; +static i2cReadCallback_t pfReadFlashCallback = NULL; + +extern uint8_t i2c_wake_timeout; +extern bool i2c_allow_sleep; +extern uint16_t board_id_hex; +extern power_source_t power_source; +extern main_usb_connect_t usb_state; +extern app_power_mode_t interface_power_mode; +extern bool power_led_sleep_state_on; +extern bool automatic_sleep_on; +extern main_shutdown_state_t main_shutdown_state; +extern bool do_remount; +extern flashConfig_t gflashConfig; +extern flash_config_t g_flash; + + +static void i2c_write_comms_callback(uint8_t* pData, uint8_t size); +static void i2c_read_comms_callback(uint8_t* pData, uint8_t size); +static void i2c_write_flash_callback(uint8_t* pData, uint8_t size); +static void i2c_read_flash_callback(uint8_t* pData, uint8_t size); + +static void i2c_slave_callback(I2C_Type *base, i2c_slave_transfer_t *xfer, void *userData) { + switch (xfer->event) + { + /* Address match event */ + case kI2C_SlaveAddressMatchEvent: + xfer->data = NULL; + xfer->dataSize = 0; + // fsl_i2c.c IRQ updated in fsl_i2c_mod.c to include I2C D register + address_match = *(uint8_t*)userData >> 1; + i2c_wake_timeout = 3; // 3 * 30ms tick = 90ms timeout + break; + /* Transmit request */ + case kI2C_SlaveTransmitEvent: + /* Update information for transmit process */ + xfer->data = g_slave_TX_buff; + xfer->dataSize = I2C_DATA_LENGTH; + g_SlaveRxFlag = false; + break; + + /* Receive request */ + case kI2C_SlaveReceiveEvent: + /* Update information for received process */ + // Hack: Default driver can't differentiate between RX or TX on + // completion event, so we set a flag here. Can't process more + // than I2C_DATA_LENGTH bytes on RX + memset(&g_slave_RX_buff, 0, sizeof(g_slave_RX_buff)); + xfer->data = g_slave_RX_buff; + xfer->dataSize = I2C_DATA_LENGTH; + g_SlaveRxFlag = true; + break; + + /* Transfer done */ + case kI2C_SlaveCompletionEvent: + g_SlaveCompletionFlag = true; + xfer->data = NULL; + xfer->dataSize = 0; + transferredCount = xfer->transferredCount; + + // Default driver couldn't differentiate between RX or TX completion + // Check flag set in kI2C_SlaveReceiveEvent + + // Ignore NOP cmd in I2C Write + if (!(g_SlaveRxFlag && g_slave_RX_buff[0] == 0x00)) { + main_board_event(); + } + + i2c_allow_sleep = false; + break; + + default: + g_SlaveCompletionFlag = false; + break; + } +} +// Hook function executed in the main task +void board_custom_event() { + + if (g_SlaveRxFlag) { + if (pfWriteCommsCallback && address_match == I2C_SLAVE_NRF_KL_COMMS) { + pfWriteCommsCallback(&g_slave_RX_buff[0], transferredCount); + } + if (pfWriteFlashCallback && address_match == I2C_SLAVE_FLASH) { + pfWriteFlashCallback(&g_slave_RX_buff[0], transferredCount); + } + } else { + if (pfReadCommsCallback && address_match == I2C_SLAVE_NRF_KL_COMMS) { + pfReadCommsCallback(&g_slave_TX_buff[0], transferredCount); + } + if (pfReadFlashCallback && address_match == I2C_SLAVE_FLASH) { + pfReadFlashCallback(&g_slave_TX_buff[0], transferredCount); + } + } + i2c_allow_sleep = true; +} + +static void i2c_init_pins(void) { + /* Port C Clock Gate Control: Clock enabled */ + CLOCK_EnableClock(kCLOCK_PortC); + + /* PORTC1 is configured as I2C1_SCL */ + PORT_SetPinMux(PORTC, 1U, kPORT_MuxAlt2); + + /* PORTC2 is configured as I2C1_SDA */ + PORT_SetPinMux(PORTC, 2U, kPORT_MuxAlt2); +} + +static int32_t i2c_start_transfer(void) { + memset(&g_s_handle, 0, sizeof(g_s_handle)); + + I2C_SlaveTransferCreateHandle(I2C_SLAVE_BASEADDR, &g_s_handle, + i2c_slave_callback, &address_match); + + /* Set up slave transfer. */ + I2C_SlaveTransferNonBlocking(I2C_SLAVE_BASEADDR, &g_s_handle, + kI2C_SlaveCompletionEvent | kI2C_SlaveAddressMatchEvent); + + // i2c handle will be busy until an address match + g_s_handle.isBusy = false; + + return 1; +} + +void i2c_initialize(void) { + i2c_slave_config_t slaveConfig; + + i2c_init_pins(); + + I2C_SlaveGetDefaultConfig(&slaveConfig); + + slaveConfig.addressingMode = kI2C_RangeMatch; + slaveConfig.slaveAddress = I2C_SLAVE_LOWER_ADDR_7BIT; + slaveConfig.upperAddress = I2C_SLAVE_UPPER_ADDR_7BIT; + slaveConfig.enableWakeUp = true; + + I2C_SlaveInit(I2C_SLAVE_BASEADDR, &slaveConfig, I2C_SLAVE_CLK_FREQ); + + NVIC_SetPriority(I2C1_IRQn, 0x00); /* set highest priority */ + + i2c_start_transfer(); + + i2c_registerWriteCallback(i2c_write_comms_callback, I2C_SLAVE_NRF_KL_COMMS); + i2c_registerReadCallback(i2c_read_comms_callback, I2C_SLAVE_NRF_KL_COMMS); + i2c_registerWriteCallback(i2c_write_flash_callback, I2C_SLAVE_FLASH); + i2c_registerReadCallback(i2c_read_flash_callback, I2C_SLAVE_FLASH); + + return; +} + +void i2c_deinitialize(void) { + I2C_SlaveDeinit(I2C_SLAVE_BASEADDR); + return ; +} + +status_t i2c_registerWriteCallback(i2cWriteCallback_t writeCallback, uint8_t slaveAddress) +{ + status_t status = kStatus_Success; + + switch (slaveAddress){ + case I2C_SLAVE_NRF_KL_COMMS: + pfWriteCommsCallback = writeCallback; + break; + case I2C_SLAVE_HID: + break; + case I2C_SLAVE_FLASH: + pfWriteFlashCallback = writeCallback; + break; + default: + status = kStatus_Fail; + break; + } + + return status; +} + +status_t i2c_registerReadCallback(i2cReadCallback_t readCallback, uint8_t slaveAddress) +{ + status_t status = kStatus_Success; + + switch (slaveAddress) { + case I2C_SLAVE_NRF_KL_COMMS: + pfReadCommsCallback = readCallback; + break; + case I2C_SLAVE_HID: + break; + case I2C_SLAVE_FLASH: + pfReadFlashCallback = readCallback; + break; + default: + status = kStatus_Fail; + break; + } + + return status; +} + +void i2c_clearBuffer (void) { + memset(&g_slave_TX_buff, 0, sizeof(g_slave_TX_buff)); +} + +void i2c_fillBuffer (uint8_t* data, uint32_t position, uint32_t size) { + if ((position + size) > I2C_DATA_LENGTH) { + return; + } + + for (uint32_t i = 0; i < size; i++) { + g_slave_TX_buff[position + i] = data[i]; + } +} + +static void i2c_write_comms_callback(uint8_t* pData, uint8_t size) { + i2cCommand_t* pI2cCommand = (i2cCommand_t*) pData; + i2cCommand_t i2cResponse = {0}; + bool assert_interrupt = true; + + switch (pI2cCommand->cmdId) { + case gReadRequest_c: + i2cResponse.cmdId = gReadResponse_c; + i2cResponse.cmdData.readRspCmd.propertyId = pI2cCommand->cmdData.readReqCmd.propertyId; + switch (pI2cCommand->cmdData.readReqCmd.propertyId) { + case gDAPLinkBoardVersion_c: + i2cResponse.cmdData.readRspCmd.dataSize = sizeof(board_id_hex); + memcpy(&i2cResponse.cmdData.readRspCmd.data, &board_id_hex, sizeof(board_id_hex)); + break; + case gI2CProtocolVersion_c: { + uint16_t i2c_version = 1; + i2cResponse.cmdData.readRspCmd.dataSize = sizeof(i2c_version); + memcpy(&i2cResponse.cmdData.readRspCmd.data, &i2c_version, sizeof(i2c_version)); + } + break; + case gDAPLinkVersion_c: { + uint16_t daplink_version = DAPLINK_VERSION; + i2cResponse.cmdData.readRspCmd.dataSize = sizeof(daplink_version); + memcpy(&i2cResponse.cmdData.readRspCmd.data, &daplink_version, sizeof(daplink_version)); + } + break; + case gPowerState_c: + power_source = pwr_mon_get_power_source(); + i2cResponse.cmdData.readRspCmd.dataSize = sizeof(power_source); + memcpy(&i2cResponse.cmdData.readRspCmd.data, &power_source, sizeof(power_source)); + break; + case gPowerConsumption_c: { + uint32_t vin_voltage_uv = pwr_mon_get_vin_mv() * 1000; + uint32_t vbat_voltage_uv = pwr_mon_get_vbat_mv() * 1000; + i2cResponse.cmdData.readRspCmd.dataSize = sizeof(vin_voltage_uv) + sizeof(vbat_voltage_uv); + memcpy(&i2cResponse.cmdData.readRspCmd.data[0], &vbat_voltage_uv, sizeof(vbat_voltage_uv)); + memcpy(&i2cResponse.cmdData.readRspCmd.data[sizeof(vbat_voltage_uv)], &vin_voltage_uv, sizeof(vin_voltage_uv)); + } + break; + case gUSBEnumerationState_c: + i2cResponse.cmdData.readRspCmd.dataSize = sizeof(usb_state); + memcpy(&i2cResponse.cmdData.readRspCmd.data, &usb_state, sizeof(usb_state)); + break; + case gPowerMode_c: + i2cResponse.cmdId = gErrorResponse_c; + i2cResponse.cmdData.errorRspCmd.errorCode = gErrorReadDisallowed_c; + break; + default: + i2cResponse.cmdId = gErrorResponse_c; + i2cResponse.cmdData.errorRspCmd.errorCode = gErrorUnknownProperty_c; + break; + } + break; + case gReadResponse_c: + i2cResponse.cmdId = gErrorResponse_c; + i2cResponse.cmdData.errorRspCmd.errorCode = gErrorCommandDisallowed_c; + break; + case gWriteRequest_c: + switch (pI2cCommand->cmdData.writeReqCmd.propertyId) { + case gDAPLinkBoardVersion_c: + case gI2CProtocolVersion_c: + case gDAPLinkVersion_c: + case gPowerState_c: + case gPowerConsumption_c: + case gUSBEnumerationState_c: + i2cResponse.cmdId = gErrorResponse_c; + i2cResponse.cmdData.errorRspCmd.errorCode = gErrorWriteDisallowed_c; + break; + case gPowerMode_c: + if (pI2cCommand->cmdData.writeReqCmd.dataSize == 1) { + if (pI2cCommand->cmdData.writeReqCmd.data[0] == kAPP_PowerModeVlls0) { + interface_power_mode = kAPP_PowerModeVlls0; + i2cResponse.cmdId = gWriteResponse_c; + i2cResponse.cmdData.writeRspCmd.propertyId = pI2cCommand->cmdData.writeReqCmd.propertyId; + } else { + i2cResponse.cmdId = gErrorResponse_c; + i2cResponse.cmdData.errorRspCmd.errorCode = gErrorWriteFail_c; + } + } else { + i2cResponse.cmdId = gErrorResponse_c; + i2cResponse.cmdData.errorRspCmd.errorCode = gErrorWrongPropertySize_c; + } + break; + case gPowerLedSleepState_c: + if (pI2cCommand->cmdData.writeReqCmd.dataSize == 1) { + if (pI2cCommand->cmdData.writeReqCmd.data[0] != 0) { + power_led_sleep_state_on = true; + } + else { + power_led_sleep_state_on = false; + } + i2cResponse.cmdId = gWriteResponse_c; + i2cResponse.cmdData.writeRspCmd.propertyId = pI2cCommand->cmdData.writeReqCmd.propertyId; + } else { + i2cResponse.cmdId = gErrorResponse_c; + i2cResponse.cmdData.errorRspCmd.errorCode = gErrorWrongPropertySize_c; + } + break; + case gAutomaticSleep_c: + if (pI2cCommand->cmdData.writeReqCmd.dataSize == 1) { + if (pI2cCommand->cmdData.writeReqCmd.data[0] != 0) { + automatic_sleep_on = true; + } + else { + automatic_sleep_on = false; + } + i2cResponse.cmdId = gWriteResponse_c; + i2cResponse.cmdData.writeRspCmd.propertyId = pI2cCommand->cmdData.writeReqCmd.propertyId; + } else { + i2cResponse.cmdId = gErrorResponse_c; + i2cResponse.cmdData.errorRspCmd.errorCode = gErrorWrongPropertySize_c; + } + break; + default: + i2cResponse.cmdId = gErrorResponse_c; + i2cResponse.cmdData.errorRspCmd.errorCode = gErrorUnknownProperty_c; + break; + } + break; + case gWriteResponse_c: + break; + case gErrorResponse_c: + break; + case gNopCmd_c: + assert_interrupt = false; + break; + default: + i2cResponse.cmdId = gErrorResponse_c; + i2cResponse.cmdData.errorRspCmd.errorCode = gErrorUnknownCommand_c; + break; + } + + if (assert_interrupt) { + i2c_fillBuffer((uint8_t*) &i2cResponse, 0, sizeof(i2cResponse)); + // Response ready, assert COMBINED_SENSOR_INT + PORT_SetPinMux(COMBINED_SENSOR_INT_PORT, COMBINED_SENSOR_INT_PIN, kPORT_MuxAsGpio); + } +} + +static void i2c_read_comms_callback(uint8_t* pData, uint8_t size) { + i2cCommand_t* pI2cCommand = (i2cCommand_t*) pData; + + switch (pI2cCommand->cmdId) { + case gWriteResponse_c: + switch (pI2cCommand->cmdData.writeRspCmd.propertyId) { + case gPowerMode_c: + main_shutdown_state = MAIN_SHUTDOWN_REQUESTED; + break; + } + break; + } + + i2c_clearBuffer(); + + // Release COMBINED_SENSOR_INT + PORT_SetPinMux(COMBINED_SENSOR_INT_PORT, COMBINED_SENSOR_INT_PIN, kPORT_PinDisabledOrAnalog); +} + +static bool file_extension_allowed(const vfs_filename_t filename) +{ + const char *valid_extensions[] = { + "BIN", + "TXT", + "CSV", + "HTM", + "WAV", + }; + uint32_t i; + + // Check for invalid starting characters + for (i = 0; i < (sizeof((valid_extensions))/sizeof((valid_extensions)[0])); i++) { + if (0 == memcmp(&filename[8], valid_extensions[i], 3)) { + return true; + } + } + + // Some checks failed so file extension is invalid + return false; +} + +static uint32_t erase_storage_sector(uint32_t adr) +{ + int status = FLASH_Erase(&g_flash, adr, g_flash.PFlashSectorSize, kFLASH_apiEraseKey); + if (status == kStatus_Success) + { + status = FLASH_VerifyErase(&g_flash, adr, g_flash.PFlashSectorSize, kFLASH_marginValueNormal); + } + return status; +} + +static uint32_t program_storage_page(uint32_t adr, uint32_t sz, uint8_t *buf) +{ + /* Verify data is word aligned */ + util_assert(!((uint32_t)buf & 0x3)); + + int status = FLASH_Program(&g_flash, adr, (uint32_t *) buf, sz); + if (status == kStatus_Success) + { + // Must use kFlashMargin_User, or kFlashMargin_Factory for verify program + status = FLASH_VerifyProgram(&g_flash, adr, sz, + (uint32_t *) buf, kFLASH_marginValueUser, + NULL, NULL); + } + return status; +} + +static void i2c_write_flash_callback(uint8_t* pData, uint8_t size) { + i2cFlashCmd_t* pI2cCommand = (i2cFlashCmd_t*) pData; + + uint32_t status = 0; + + uint32_t storage_address = pI2cCommand->cmdData.write.addr2 << 16 | + pI2cCommand->cmdData.write.addr1 << 8 | + pI2cCommand->cmdData.write.addr0 << 0; + uint32_t address = storage_address + FLASH_STORAGE_ADDRESS; + uint32_t length = __REV(pI2cCommand->cmdData.write.length); + uint32_t data = (uint32_t) pI2cCommand->cmdData.write.data; + + i2c_clearBuffer(); + + switch (pI2cCommand->cmdId) { + case gFlashDataWrite_c: + /* Validate length field matches with I2C Write data */ + if (size == length + 8) { + /* Address range and alignment validation done inside program_storage_page() */ + status = program_storage_page(address, length, (uint8_t *) data); + + if (0 != status) { + pI2cCommand->cmdId = gFlashError_c; + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + } + else { + /* Fill TX Buffer with received command args */ + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, sizeof(i2cFlashCmd_t) - 1024); + /* Fill TX Buffer with Flash Data Written */ + i2c_fillBuffer((uint8_t*) address, sizeof(i2cFlashCmd_t) - 1024, length); + } + } else { + pI2cCommand->cmdId = gFlashError_c; + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + } + break; + case gFlashDataRead_c: { + /* Do address range validation */ + if (address + length > (FLASH_CONFIG_ADDRESS + FLASH_INTERFACE_SIZE)) { + pI2cCommand->cmdId = gFlashError_c; + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + } else { + /* Fill TX Buffer with received command args */ + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, sizeof(i2cFlashCmd_t) - 1024); + /* Fill TX Buffer with Flash Data Read */ + i2c_fillBuffer((uint8_t*) address, sizeof(i2cFlashCmd_t) - 1024, length); + } + } + break; + case gFlashDataErase_c: { + uint32_t address = pI2cCommand->cmdData.erase.sAddr2 << 16 | + pI2cCommand->cmdData.erase.sAddr1 << 8 | + pI2cCommand->cmdData.erase.sAddr0 << 0; + uint32_t start_addr = address + FLASH_STORAGE_ADDRESS; + + address = pI2cCommand->cmdData.erase.eAddr2 << 16 | + pI2cCommand->cmdData.erase.eAddr1 << 8 | + pI2cCommand->cmdData.erase.eAddr0 << 0; + uint32_t end_addr = address + FLASH_STORAGE_ADDRESS; + + /* Do address range validation */ + if (start_addr % DAPLINK_SECTOR_SIZE == 0 && + end_addr % DAPLINK_SECTOR_SIZE == 0 && + start_addr <= end_addr && + start_addr < (FLASH_CONFIG_ADDRESS + FLASH_INTERFACE_SIZE) && + end_addr < (FLASH_CONFIG_ADDRESS + FLASH_INTERFACE_SIZE)) { + for (uint32_t addr = start_addr; addr <= end_addr && status == 0; addr += DAPLINK_SECTOR_SIZE) { + status = erase_storage_sector(addr); + } + + if (status != 0) { + pI2cCommand->cmdId = gFlashError_c; + } + } else { + pI2cCommand->cmdId = gFlashError_c; + } + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + + } + break; + case gFlashCfgFileName_c: + if (size == 1) { + /* If size is 1 (only cmd id), this means it's a read */ + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + i2c_fillBuffer((uint8_t*) &gflashConfig.fileName, 1, sizeof(gflashConfig.fileName)); + } else if (size == 12) { + /* If size is 12 (cmd id + 11B data), this means it's a write */ + /* Validate 8.3 filename */ + if (filename_valid((char *) pI2cCommand->cmdData.data)) { + // Check allowed extensions (.bin, .txt, .csv, .htm, .wav) + if (file_extension_allowed((char *) pI2cCommand->cmdData.data)) { + memcpy(gflashConfig.fileName, pI2cCommand->cmdData.data, 11); + } + // If disallowed extension is requested, .bin will be used + else { + memcpy(gflashConfig.fileName, pI2cCommand->cmdData.data, 8); + memcpy(&gflashConfig.fileName[8], "BIN", 3); + } + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + i2c_fillBuffer((uint8_t*) &gflashConfig.fileName, 1, sizeof(gflashConfig.fileName)); + } + else { + // Send error if invalid filename + pI2cCommand->cmdId = gFlashError_c; + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + } + } else { + pI2cCommand->cmdId = gFlashError_c; + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + } + break; + case gFlashCfgFileSize_c: + if (size == 1) { + /* If size is 1 (only cmd id), this means it's a read */ + uint32_t tempFileSize = __REV(gflashConfig.fileSize); + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + i2c_fillBuffer((uint8_t*) &tempFileSize, 1, sizeof(gflashConfig.fileSize)); + } else if (size == 5) { + /* If size is 5 (cmd id + 4B data), this means it's a write */ + uint32_t tempFileSize = pI2cCommand->cmdData.data[0] << 24 | + pI2cCommand->cmdData.data[1] << 16 | + pI2cCommand->cmdData.data[2] << 8 | + pI2cCommand->cmdData.data[3] << 0; + + /* Validate file size */ + if (tempFileSize <= (FLASH_INTERFACE_SIZE - FLASH_CONFIG_SIZE)) { + gflashConfig.fileSize = tempFileSize; + tempFileSize = __REV(gflashConfig.fileSize); + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + i2c_fillBuffer((uint8_t*) &tempFileSize, 1, sizeof(gflashConfig.fileSize)); + } else { + pI2cCommand->cmdId = gFlashError_c; + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + } + } else { + pI2cCommand->cmdId = gFlashError_c; + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + } + break; + case gFlashCfgFileVisible_c: + if (size == 1) { + /* If size is 1 (only cmd id), this means it's a read */ + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + i2c_fillBuffer((uint8_t*) &gflashConfig.fileVisible, 1, sizeof(gflashConfig.fileVisible)); + } else if (size == 2) { + /* If size is 2 (cmd id + 1B data), this means it's a write */ + gflashConfig.fileVisible = pI2cCommand->cmdData.data[0]; + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + i2c_fillBuffer((uint8_t*) &gflashConfig.fileVisible, 1, sizeof(gflashConfig.fileVisible)); + } else { + pI2cCommand->cmdId = gFlashError_c; + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + } + break; + case gFlashCfgWrite_c: + // Check first is config is already present in flash + // If differences are found, erase and write new config + if (0 != memcmp(&gflashConfig, (void *)FLASH_CONFIG_ADDRESS, sizeof(flashConfig_t))) { + status = erase_storage_sector(FLASH_CONFIG_ADDRESS); + + if (status != 0) { + pI2cCommand->cmdId = gFlashError_c; + } + else { + status = program_storage_page(FLASH_CONFIG_ADDRESS, sizeof(flashConfig_t), (uint8_t *) &gflashConfig); + } + } + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + break; + case gFlashCfgErase_c: + // Erase flash sector containing flash config + status = erase_storage_sector(FLASH_CONFIG_ADDRESS); + + if (status != 0) { + pI2cCommand->cmdId = gFlashError_c; + } + else { + // Return flash config (RAM) to default values + gflashConfig.key = CFG_KEY; + memcpy(gflashConfig.fileName, FLASH_CFG_FILENAME, 11); + gflashConfig.fileSize = FLASH_CFG_FILESIZE; + gflashConfig.fileVisible = FLASH_CFG_FILEVISIBLE; + } + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + break; + case gFlashStorageSize_c: + pI2cCommand->cmdData.data[0] = (FLASH_INTERFACE_SIZE - FLASH_CONFIG_SIZE)/1024; + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 2); + break; + case gFlashSectorSize_c: + pI2cCommand->cmdData.data[0] = (DAPLINK_SECTOR_SIZE >> 8) & 0xFF; + pI2cCommand->cmdData.data[1] = DAPLINK_SECTOR_SIZE & 0xFF; + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 3); + break; + case gFlashRemountMSD_c: + do_remount = true; + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + break; + default: + pI2cCommand->cmdId = gFlashError_c; + i2c_fillBuffer((uint8_t*) pI2cCommand, 0, 1); + break; + } + + // Response ready, assert COMBINED_SENSOR_INT + PORT_SetPinMux(COMBINED_SENSOR_INT_PORT, COMBINED_SENSOR_INT_PIN, kPORT_MuxAsGpio); +} + +static void i2c_read_flash_callback(uint8_t* pData, uint8_t size) { + i2c_clearBuffer(); + + // Release COMBINED_SENSOR_INT + PORT_SetPinMux(COMBINED_SENSOR_INT_PORT, COMBINED_SENSOR_INT_PIN, kPORT_PinDisabledOrAnalog); +} diff --git a/source/board/microbitv2/i2c_commands.h b/source/board/microbitv2/i2c_commands.h new file mode 100644 index 000000000..f18436210 --- /dev/null +++ b/source/board/microbitv2/i2c_commands.h @@ -0,0 +1,198 @@ +/** + * @file i2c_commands.h + * @brief + * + * DAPLink Interface Firmware + * Copyright 2020 NXP + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef I2C_COMMANDS_H +#define I2C_COMMANDS_H + +#include + +#include "cmsis_compiler.h" +#include "virtual_fs.h" +#include "fsl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define I2C_SLAVE_NRF_KL_COMMS (0x70U) +#define I2C_SLAVE_HID (0x71U) +#define I2C_SLAVE_FLASH (0x72U) + +/*! i2c command Id type enumeration */ +typedef enum cmdId_tag { + gNopCmd_c = 0x00, + gReadRequest_c = 0x10, + gReadResponse_c = 0x11, + gWriteRequest_c = 0x12, + gWriteResponse_c = 0x13, + gErrorResponse_c = 0x20 +} cmdId_t; + +/*! property Id type enumeration */ +typedef enum propertyId_tag { + gDAPLinkBoardVersion_c = 0x01, + gI2CProtocolVersion_c = 0x02, + gDAPLinkVersion_c = 0x03, + gPowerState_c = 0x04, + gPowerConsumption_c = 0x05, + gUSBEnumerationState_c = 0x06, + gPowerMode_c = 0x07, + gPowerLedSleepState_c = 0x08, + gUserEvent_c = 0x09, + gAutomaticSleep_c = 0x0A +} propertyId_t; + +/*! user event type enumeration */ +typedef enum userEventType_tag { + gWakeFromResetButton_c = 0x01, + gWakeFromWakeOnEdge_c = 0x02, + gResetButtonLongPress_c = 0x03, +} userEventType_t; + +/*! property Id type enumeration */ +typedef enum errorCode_tag { + gErrorSuccess = 0x30, + gErrorIncompleteCommand_c = 0x31, + gErrorUnknownCommand_c = 0x32, + gErrorCommandDisallowed_c = 0x33, + gErrorUnknownProperty_c = 0x34, + gErrorWrongPropertySize_c = 0x35, + gErrorReadDisallowed_c = 0x36, + gErrorWriteDisallowed_c = 0x37, + gErrorWriteFail_c = 0x38 +} errorCode_t; + +typedef __PACKED_STRUCT readReqCmd_tag { + uint8_t propertyId; +} readReqCmd_t; + +#define MAX_PROPERTY_SIZE 8 + +typedef __PACKED_STRUCT readRspCmd_tag { + uint8_t propertyId; + uint8_t dataSize; + uint8_t data[MAX_PROPERTY_SIZE]; +} readRspCmd_t; + +typedef __PACKED_STRUCT writeReqCmd_tag { + uint8_t propertyId; + uint8_t dataSize; + uint8_t data[MAX_PROPERTY_SIZE]; +} writeReqCmd_t; + +typedef __PACKED_STRUCT writeRspCmd_tag { + uint8_t propertyId; +} writeRspCmd_t; + +typedef __PACKED_STRUCT errorRspCmd_tag { + uint8_t errorCode; +} errorRspCmd_t; + +/*! i2c command structure*/ +typedef __PACKED_STRUCT i2cCommand_tag { + uint8_t cmdId; + __PACKED_UNION { + readReqCmd_t readReqCmd; + readRspCmd_t readRspCmd; + writeReqCmd_t writeReqCmd; + writeRspCmd_t writeRspCmd; + errorRspCmd_t errorRspCmd; + } cmdData; +} i2cCommand_t; + +typedef __PACKED_STRUCT flashConfig_tag { + uint32_t key; // Magic key to indicate a valid record + vfs_filename_t fileName; + uint32_t fileSize; + bool fileVisible; +} flashConfig_t; + +/*! Flash interface command type */ +typedef enum flashCmdId_tag { + gFlashCfgFileName_c = 0x01, + gFlashCfgFileSize_c = 0x02, + gFlashCfgFileVisible_c = 0x03, + gFlashCfgWrite_c = 0x04, + gFlashCfgErase_c = 0x05, + gFlashStorageSize_c = 0x06, + gFlashSectorSize_c = 0x07, + gFlashRemountMSD_c = 0x08, + gFlashDataRead_c = 0x0A, + gFlashDataWrite_c = 0x0B, + gFlashDataErase_c = 0x0C, + gFlashError_c = 0x20 +} flashCmdId_t; + +typedef __PACKED_STRUCT flashDataWriteCmd_tag { + uint8_t addr2; + uint8_t addr1; + uint8_t addr0; + uint32_t length; + uint8_t data[1024]; +} flashDataWriteCmd_t; + +typedef __PACKED_STRUCT flashDataEraseCmd_tag { + uint8_t sAddr2; + uint8_t sAddr1; + uint8_t sAddr0; + uint8_t pad; + uint8_t eAddr2; + uint8_t eAddr1; + uint8_t eAddr0; +} flashDataEraseCmd_t; + +/*! i2c command structure*/ +typedef __PACKED_STRUCT i2cFlashCmd_tag { + uint8_t cmdId; + __PACKED_UNION { + flashDataWriteCmd_t write; + flashDataWriteCmd_t read; + flashDataEraseCmd_t erase; + uint8_t data[1024]; + } cmdData; +} i2cFlashCmd_t; + +/*! i2c Write Callback prototype */ +typedef void (*i2cWriteCallback_t) +( + uint8_t* pData, + uint8_t size +); + +/*! i2c Read Callback prototype */ +typedef void (*i2cReadCallback_t) +( + uint8_t* pData, + uint8_t size +); + +void i2c_initialize(void); +void i2c_deinitialize(void); +status_t i2c_registerWriteCallback(i2cWriteCallback_t writeCallback, uint8_t slaveAddress); +status_t i2c_registerReadCallback(i2cReadCallback_t readCallback, uint8_t slaveAddress); +void i2c_clearBuffer(void); +void i2c_fillBuffer(uint8_t* data, uint32_t position, uint32_t size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/board/microbitv2/led_error_app.c b/source/board/microbitv2/led_error_app.c new file mode 100644 index 000000000..32de07e70 --- /dev/null +++ b/source/board/microbitv2/led_error_app.c @@ -0,0 +1,198 @@ +/** + * @file led_error_app.c + * @brief + * + * DAPLink Interface Firmware + * Copyright 2020 Micro:bit Educational Foundation + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Program to display error code 0-999 on LEDs: face,E,digit,digit,digit + +unsigned int g_led_error_bin_len = 2016; + +// Offset of 2 byte error code, low byte first +unsigned int g_led_error_bin_code = 1908; + +unsigned char g_led_error_bin_data[] = { + 0x00, 0x00, 0x02, 0x20, 0xb5, 0x02, 0x00, 0x00, 0xdd, 0x02, 0x00, 0x00, + 0xdf, 0x02, 0x00, 0x00, 0xe1, 0x02, 0x00, 0x00, 0xe3, 0x02, 0x00, 0x00, + 0xe5, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x02, 0x00, 0x00, + 0xe9, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xeb, 0x02, 0x00, 0x00, + 0xed, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, + 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, + 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, + 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, + 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, + 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, + 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, + 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, + 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, + 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, + 0xef, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, + 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, + 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xef, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xb5, 0x05, 0x4c, + 0x23, 0x78, 0x33, 0xb9, 0x04, 0x4b, 0x13, 0xb1, 0x04, 0x48, 0xaf, 0xf3, + 0x00, 0x80, 0x01, 0x23, 0x23, 0x70, 0x10, 0xbd, 0x74, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x07, 0x00, 0x00, 0x08, 0xb5, 0x03, 0x4b, + 0x1b, 0xb1, 0x03, 0x49, 0x03, 0x48, 0xaf, 0xf3, 0x00, 0x80, 0x08, 0xbd, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x20, 0x60, 0x07, 0x00, 0x00, + 0x15, 0x4b, 0x00, 0x2b, 0x08, 0xbf, 0x13, 0x4b, 0x9d, 0x46, 0xa3, 0xf5, + 0x80, 0x3a, 0x00, 0x21, 0x8b, 0x46, 0x0f, 0x46, 0x13, 0x48, 0x14, 0x4a, + 0x12, 0x1a, 0x00, 0xf0, 0x47, 0xfa, 0x0f, 0x4b, 0x00, 0x2b, 0x00, 0xd0, + 0x98, 0x47, 0x0e, 0x4b, 0x00, 0x2b, 0x00, 0xd0, 0x98, 0x47, 0x00, 0x20, + 0x00, 0x21, 0x04, 0x00, 0x0d, 0x00, 0x0d, 0x48, 0x00, 0x28, 0x02, 0xd0, + 0x0c, 0x48, 0xaf, 0xf3, 0x00, 0x80, 0x00, 0xf0, 0x0f, 0xfa, 0x20, 0x00, + 0x29, 0x00, 0x00, 0xf0, 0xed, 0xf9, 0x00, 0xf0, 0xf5, 0xf9, 0x00, 0xbf, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x20, 0x90, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x49, 0x07, 0x4a, + 0x07, 0x4b, 0x9b, 0x1a, 0x03, 0xdd, 0x04, 0x3b, 0xc8, 0x58, 0xd0, 0x50, + 0xfb, 0xdc, 0x00, 0xf0, 0x2f, 0xf8, 0xff, 0xf7, 0xb9, 0xff, 0x00, 0x00, + 0x6c, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x74, 0x00, 0x00, 0x20, + 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, + 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xbf, 0xf3, 0x4f, 0x8f, + 0x05, 0x49, 0x06, 0x4b, 0xca, 0x68, 0x02, 0xf4, 0xe0, 0x62, 0x13, 0x43, + 0xcb, 0x60, 0xbf, 0xf3, 0x4f, 0x8f, 0x00, 0xbf, 0xfd, 0xe7, 0x00, 0xbf, + 0x00, 0xed, 0x00, 0xe0, 0x04, 0x00, 0xfa, 0x05, 0x03, 0x4b, 0x18, 0x68, + 0xa0, 0xf1, 0x0d, 0x03, 0x58, 0x42, 0x58, 0x41, 0x70, 0x47, 0x00, 0xbf, + 0x30, 0x01, 0x00, 0x10, 0x08, 0xb5, 0xff, 0xf7, 0xf3, 0xff, 0x40, 0xb1, + 0x4f, 0xf0, 0x80, 0x43, 0x00, 0x22, 0xc3, 0xf8, 0x0c, 0x21, 0xc3, 0xf8, + 0x10, 0x21, 0xc3, 0xf8, 0x38, 0x25, 0xff, 0xf7, 0xe7, 0xff, 0x00, 0x28, + 0x46, 0xd0, 0x4f, 0xf0, 0x80, 0x52, 0x59, 0x4b, 0xd2, 0xf8, 0x04, 0x14, + 0xc3, 0xf8, 0x20, 0x15, 0xd2, 0xf8, 0x08, 0x14, 0xc3, 0xf8, 0x24, 0x15, + 0xd2, 0xf8, 0x0c, 0x14, 0xc3, 0xf8, 0x28, 0x15, 0xd2, 0xf8, 0x10, 0x14, + 0xc3, 0xf8, 0x2c, 0x15, 0xd2, 0xf8, 0x14, 0x14, 0xc3, 0xf8, 0x30, 0x15, + 0xd2, 0xf8, 0x18, 0x14, 0xc3, 0xf8, 0x34, 0x15, 0xd2, 0xf8, 0x1c, 0x14, + 0xc3, 0xf8, 0x40, 0x15, 0xd2, 0xf8, 0x20, 0x14, 0xc3, 0xf8, 0x44, 0x15, + 0xd2, 0xf8, 0x24, 0x14, 0xc3, 0xf8, 0x48, 0x15, 0xd2, 0xf8, 0x28, 0x14, + 0xc3, 0xf8, 0x4c, 0x15, 0xd2, 0xf8, 0x2c, 0x14, 0xc3, 0xf8, 0x50, 0x15, + 0xd2, 0xf8, 0x30, 0x14, 0xc3, 0xf8, 0x54, 0x15, 0xd2, 0xf8, 0x34, 0x14, + 0xc3, 0xf8, 0x60, 0x15, 0xd2, 0xf8, 0x38, 0x14, 0xc3, 0xf8, 0x64, 0x15, + 0xd2, 0xf8, 0x3c, 0x14, 0xc3, 0xf8, 0x68, 0x15, 0xd2, 0xf8, 0x40, 0x14, + 0xc3, 0xf8, 0x6c, 0x15, 0xd2, 0xf8, 0x44, 0x24, 0xc3, 0xf8, 0x70, 0x25, + 0xff, 0xf7, 0x9c, 0xff, 0x48, 0xb1, 0x4f, 0xf0, 0x80, 0x43, 0xd3, 0xf8, + 0x00, 0x24, 0xd1, 0x07, 0x44, 0xbf, 0x6f, 0xf0, 0x01, 0x02, 0xc3, 0xf8, + 0x00, 0x24, 0x31, 0x4a, 0xd2, 0xf8, 0x88, 0x30, 0x43, 0xf4, 0x70, 0x03, + 0xc2, 0xf8, 0x88, 0x30, 0xbf, 0xf3, 0x4f, 0x8f, 0xbf, 0xf3, 0x6f, 0x8f, + 0x4f, 0xf0, 0x10, 0x23, 0xd3, 0xf8, 0x0c, 0x22, 0xd2, 0x07, 0x1e, 0xd5, + 0x29, 0x4b, 0x01, 0x22, 0xc3, 0xf8, 0x04, 0x25, 0xd3, 0xf8, 0x00, 0x24, + 0x00, 0x2a, 0xfb, 0xd0, 0x4f, 0xf0, 0x10, 0x22, 0xd2, 0xf8, 0x0c, 0x32, + 0x23, 0xf0, 0x01, 0x03, 0xc2, 0xf8, 0x0c, 0x32, 0x21, 0x4b, 0x1a, 0x46, + 0xd3, 0xf8, 0x00, 0x14, 0x00, 0x29, 0xfb, 0xd0, 0x00, 0x21, 0xc3, 0xf8, + 0x04, 0x15, 0xd2, 0xf8, 0x00, 0x34, 0x00, 0x2b, 0xfb, 0xd0, 0xff, 0xf7, + 0x4f, 0xff, 0xd3, 0xf8, 0x00, 0x22, 0x00, 0x2a, 0x03, 0xdb, 0xd3, 0xf8, + 0x04, 0x32, 0x00, 0x2b, 0x23, 0xda, 0x16, 0x4b, 0x01, 0x22, 0xc3, 0xf8, + 0x04, 0x25, 0xd3, 0xf8, 0x00, 0x24, 0x00, 0x2a, 0xfb, 0xd0, 0x4f, 0xf0, + 0x10, 0x22, 0x12, 0x21, 0xc2, 0xf8, 0x00, 0x12, 0xd3, 0xf8, 0x00, 0x24, + 0x00, 0x2a, 0xfb, 0xd0, 0x4f, 0xf0, 0x10, 0x23, 0x12, 0x22, 0xc3, 0xf8, + 0x04, 0x22, 0x0b, 0x4b, 0x1a, 0x46, 0xd3, 0xf8, 0x00, 0x14, 0x00, 0x29, + 0xfb, 0xd0, 0x00, 0x21, 0xc3, 0xf8, 0x04, 0x15, 0xd2, 0xf8, 0x00, 0x34, + 0x00, 0x2b, 0xfb, 0xd0, 0xd1, 0xe7, 0x05, 0x4b, 0x05, 0x4a, 0x1a, 0x60, + 0x08, 0xbd, 0x00, 0xbf, 0x00, 0xc0, 0x00, 0x40, 0x00, 0xed, 0x00, 0xe0, + 0x00, 0xe0, 0x01, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x90, 0xd0, 0x03, + 0x1f, 0x28, 0x86, 0xbf, 0x00, 0xf0, 0x1f, 0x00, 0x04, 0x4a, 0x4f, 0xf0, + 0xa0, 0x42, 0x01, 0x23, 0x03, 0xfa, 0x00, 0xf0, 0xc2, 0xf8, 0x08, 0x05, + 0x70, 0x47, 0x00, 0xbf, 0x00, 0x03, 0x00, 0x50, 0x80, 0x5c, 0xc1, 0xf1, + 0x04, 0x01, 0x08, 0x41, 0xc0, 0x43, 0x00, 0xf0, 0x01, 0x00, 0x70, 0x47, + 0x00, 0x23, 0x4f, 0xf0, 0xa0, 0x42, 0x83, 0x42, 0x00, 0xdb, 0x70, 0x47, + 0xd2, 0xf8, 0x04, 0x15, 0x01, 0x33, 0xf8, 0xe7, 0x38, 0xb5, 0x1c, 0x20, + 0xff, 0xf7, 0xda, 0xff, 0x0b, 0x20, 0xff, 0xf7, 0xd7, 0xff, 0x1f, 0x20, + 0xff, 0xf7, 0xd4, 0xff, 0x25, 0x20, 0xff, 0xf7, 0xd1, 0xff, 0x0b, 0x4c, + 0x0b, 0x4d, 0x1e, 0x20, 0xff, 0xf7, 0xcc, 0xff, 0x00, 0x22, 0x01, 0x20, + 0x13, 0x5d, 0x1f, 0x2b, 0x86, 0xbf, 0x03, 0xf0, 0x1f, 0x03, 0x29, 0x46, + 0x4f, 0xf0, 0xa0, 0x41, 0x01, 0x32, 0x00, 0xfa, 0x03, 0xf3, 0x05, 0x2a, + 0xc1, 0xf8, 0x0c, 0x35, 0xf0, 0xd1, 0x38, 0xbd, 0x54, 0x07, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x50, 0x2d, 0xe9, 0xf8, 0x4f, 0x80, 0x46, 0x3b, 0x48, + 0x3b, 0x4d, 0x00, 0x22, 0x82, 0x46, 0x03, 0x24, 0x13, 0x5c, 0x1f, 0x2b, + 0x86, 0xbf, 0x03, 0xf0, 0x1f, 0x03, 0x29, 0x46, 0x4f, 0xf0, 0xa0, 0x41, + 0x03, 0xf5, 0xe0, 0x73, 0x01, 0x32, 0x05, 0x2a, 0x41, 0xf8, 0x23, 0x40, + 0xf0, 0xd1, 0x33, 0x48, 0x31, 0x4d, 0x00, 0x22, 0x03, 0x24, 0x13, 0x5c, + 0x1f, 0x2b, 0x86, 0xbf, 0x03, 0xf0, 0x1f, 0x03, 0x29, 0x46, 0x4f, 0xf0, + 0xa0, 0x41, 0x03, 0xf5, 0xe0, 0x73, 0x01, 0x32, 0x05, 0x2a, 0x41, 0xf8, + 0x23, 0x40, 0xf0, 0xd1, 0xff, 0xf7, 0xac, 0xff, 0x4f, 0xf0, 0x01, 0x09, + 0x28, 0x4c, 0x00, 0x26, 0x32, 0x27, 0x00, 0x25, 0x25, 0x4b, 0x58, 0x5d, + 0xff, 0xf7, 0x80, 0xff, 0x4f, 0xf0, 0x00, 0x0b, 0x2a, 0x46, 0x59, 0x46, + 0x20, 0x46, 0x1a, 0xf8, 0x0b, 0x30, 0xff, 0xf7, 0x87, 0xff, 0xa0, 0xbb, + 0x1f, 0x2b, 0x86, 0xbf, 0x03, 0xf0, 0x1f, 0x03, 0x1b, 0x4a, 0x4f, 0xf0, + 0xa0, 0x42, 0x09, 0xfa, 0x03, 0xf3, 0xc2, 0xf8, 0x0c, 0x35, 0x0b, 0xf1, + 0x01, 0x0b, 0xbb, 0xf1, 0x05, 0x0f, 0xe7, 0xd1, 0x44, 0xf6, 0x20, 0x60, + 0x01, 0x35, 0xff, 0xf7, 0x79, 0xff, 0xff, 0xf7, 0x81, 0xff, 0x05, 0x2d, + 0xd8, 0xd1, 0x01, 0x3f, 0xd5, 0xd1, 0x13, 0x48, 0x01, 0x36, 0xff, 0xf7, + 0x6f, 0xff, 0x04, 0x2e, 0xcc, 0xd0, 0x31, 0x46, 0x64, 0x23, 0x0a, 0x22, + 0x02, 0xe0, 0x01, 0x39, 0x93, 0xfb, 0xf2, 0xf3, 0x01, 0x29, 0xfa, 0xd1, + 0x98, 0xfb, 0xf3, 0xf3, 0x93, 0xfb, 0xf2, 0xf4, 0x02, 0xfb, 0x14, 0x34, + 0x09, 0x4b, 0x04, 0xeb, 0x84, 0x04, 0x1c, 0x44, 0xba, 0xe7, 0x18, 0x46, + 0xff, 0xf7, 0x3e, 0xff, 0xd1, 0xe7, 0x00, 0xbf, 0x4a, 0x07, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x50, 0x54, 0x07, 0x00, 0x00, 0x4f, 0x07, 0x00, 0x00, + 0x40, 0x42, 0x0f, 0x00, 0x18, 0x07, 0x00, 0x00, 0x08, 0xb5, 0x03, 0x4b, + 0x98, 0x88, 0xff, 0xf7, 0x75, 0xff, 0x00, 0x20, 0x08, 0xbd, 0x00, 0xbf, + 0x04, 0x00, 0x00, 0x20, 0x08, 0xb5, 0x07, 0x4b, 0x04, 0x46, 0x13, 0xb1, + 0x00, 0x21, 0xaf, 0xf3, 0x00, 0x80, 0x05, 0x4b, 0x18, 0x68, 0x83, 0x6a, + 0x03, 0xb1, 0x98, 0x47, 0x20, 0x46, 0x00, 0xf0, 0x31, 0xf8, 0x00, 0xbf, + 0x00, 0x00, 0x00, 0x00, 0x5c, 0x07, 0x00, 0x00, 0x70, 0xb5, 0x0d, 0x4e, + 0x0d, 0x4c, 0xa4, 0x1b, 0xa4, 0x10, 0x00, 0x25, 0xa5, 0x42, 0x09, 0xd1, + 0x0b, 0x4e, 0x0c, 0x4c, 0x00, 0xf0, 0x22, 0xf8, 0xa4, 0x1b, 0xa4, 0x10, + 0x00, 0x25, 0xa5, 0x42, 0x05, 0xd1, 0x70, 0xbd, 0x56, 0xf8, 0x25, 0x30, + 0x98, 0x47, 0x01, 0x35, 0xee, 0xe7, 0x56, 0xf8, 0x25, 0x30, 0x98, 0x47, + 0x01, 0x35, 0xf2, 0xe7, 0x6c, 0x00, 0x00, 0x20, 0x6c, 0x00, 0x00, 0x20, + 0x6c, 0x00, 0x00, 0x20, 0x70, 0x00, 0x00, 0x20, 0x02, 0x44, 0x03, 0x46, + 0x93, 0x42, 0x00, 0xd1, 0x70, 0x47, 0x03, 0xf8, 0x01, 0x1b, 0xf9, 0xe7, + 0xfe, 0xe7, 0x00, 0xbf, 0xf8, 0xb5, 0x00, 0xbf, 0xf8, 0xbc, 0x08, 0xbc, + 0x9e, 0x46, 0x70, 0x47, 0xf8, 0xb5, 0x00, 0xbf, 0xf8, 0xbc, 0x08, 0xbc, + 0x9e, 0x46, 0x70, 0x47, 0x0c, 0x92, 0x52, 0x52, 0x4c, 0x04, 0x8c, 0x84, + 0x84, 0x8e, 0x1c, 0x82, 0x4c, 0x90, 0x1e, 0x1e, 0xc2, 0x44, 0x92, 0x4c, + 0x06, 0xca, 0x52, 0x5f, 0xe2, 0x1f, 0xf0, 0x1e, 0xc1, 0x3e, 0x02, 0x44, + 0x8e, 0xd1, 0x2e, 0x1f, 0xe2, 0x44, 0x88, 0x10, 0x0e, 0xd1, 0x2e, 0xd1, + 0x2e, 0x0e, 0xd1, 0x2e, 0xc4, 0x88, 0x1c, 0x0b, 0x1f, 0x25, 0x1e, 0x1b, + 0x1b, 0x00, 0x0e, 0x11, 0x15, 0x16, 0x0f, 0x18, 0x13, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xdc, 0xfa, 0xff, 0x7f, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x90, 0xd0, 0x03, 0xde, 0xc0, 0xce, 0xfa, + 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00 +}; diff --git a/source/board/microbitv2/led_error_app.h b/source/board/microbitv2/led_error_app.h new file mode 100644 index 000000000..c618a048f --- /dev/null +++ b/source/board/microbitv2/led_error_app.h @@ -0,0 +1,37 @@ +/** + * @file led_error_app.h + * @brief + * + * DAPLink Interface Firmware + * Copyright 2020 Micro:bit Educational Foundation + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LED_ERROR_APP_H +#define LED_ERROR_APP_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern unsigned int g_led_error_bin_len; +extern unsigned int g_led_error_bin_code; +extern unsigned char g_led_error_bin_data[]; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/board/microbitv2/microbitv2.c b/source/board/microbitv2/microbitv2.c index 355388db5..aa6912d6a 100644 --- a/source/board/microbitv2/microbitv2.c +++ b/source/board/microbitv2/microbitv2.c @@ -4,6 +4,7 @@ * * DAPLink Interface Firmware * Copyright (c) 2009-2019, ARM Limited, All Rights Reserved + * Copyright 2020 NXP * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -18,23 +19,545 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #include "fsl_device_registers.h" #include "IO_Config.h" #include "DAP.h" #include "target_family.h" #include "target_board.h" +#include "flexio_pwm.h" +#include "gpio.h" +#include "power.h" +#include "rl_usb.h" +#include "pwr_mon.h" +#include "main_interface.h" +#include "i2c_commands.h" +#include "adc.h" +#include "fsl_port.h" +#include "fsl_gpio.h" +#include "fsl_i2c.h" +#include "led_error_app.h" +#include "flash_manager.h" +#include "virtual_fs.h" +#include "vfs_manager.h" +#include "cortex_m.h" +#include "fsl_flash.h" +#include "microbitv2.h" + +#ifdef DRAG_N_DROP_SUPPORT +#include "flash_intf.h" +#endif const char * const board_id_mb_2_0 = "9903"; +const char * const board_id_mb_2_1 = "9904"; + +uint16_t board_id_hex_min = 0x9903; +uint16_t board_id_hex = 0; + +volatile uint8_t wake_from_reset = 0; +volatile uint8_t wake_from_usb = 0; +volatile bool usb_pc_connected = false; +uint8_t i2c_wake_timeout = 0; +bool i2c_allow_sleep = true; +power_source_t power_source; +app_power_mode_t interface_power_mode = kAPP_PowerModeVlls0; +bool power_led_sleep_state_on = PWR_LED_SLEEP_STATE_DEFAULT; +bool automatic_sleep_on = AUTOMATIC_SLEEP_DEFAULT; +main_shutdown_state_t main_shutdown_state = MAIN_SHUTDOWN_WAITING; +bool do_remount = false; + +flashConfig_t gflashConfig = { + .key = CFG_KEY, + .fileName = FLASH_CFG_FILENAME, + .fileSize = FLASH_CFG_FILESIZE, + .fileVisible = FLASH_CFG_FILEVISIBLE, +}; + +typedef enum { + BOARD_VERSION_2_0 = 0, + BOARD_VERSION_2_1 = 1, +} mb_version_t; extern target_cfg_t target_device_nrf52_64; +extern main_usb_connect_t usb_state; +extern bool go_to_sleep; +extern i2c_slave_handle_t g_s_handle; +extern flash_config_t g_flash; -// Called in main_task() to init before USB and files are configured -static void prerun_board_config(void) { +extern void main_powerdown_event(void); + +static uint32_t read_file_data_txt(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors); + +// shutdown state +static uint8_t shutdown_led_dc = PWR_LED_ON_MAX_BRIGHTNESS; +static uint8_t final_fade_led_dc = 0; +static uint8_t power_led_max_duty_cycle = PWR_LED_ON_MAX_BRIGHTNESS; +static uint8_t initial_fade_brightness = PWR_LED_INIT_FADE_BRIGHTNESS; +// reset button state count +static uint16_t gpio_reset_count = 0; +// button state +static uint8_t reset_pressed = 0; + +// Board Rev ID detection. Reads BRD_REV_ID voltage +// Depends on gpio_init() to have been executed already +static mb_version_t read_brd_rev_id_pin(void) { + gpio_pin_config_t pin_config = { + .pinDirection = kGPIO_DigitalOutput, + .outputLogic = 0U + }; + mb_version_t board_version = BOARD_VERSION_2_0; + uint32_t board_rev_id_adc = 0; + uint32_t board_rev_id_mv = 0; + + // Set Board Rev ID pin as output but pin disabled + PORT_SetPinMux(PIN_BOARD_REV_ID_PORT , PIN_BOARD_REV_ID_BIT, kPORT_PinDisabledOrAnalog); + PORT_SetPinDriveStrength(PIN_BOARD_REV_ID_PORT, PIN_BOARD_REV_ID_BIT, kPORT_HighDriveStrength); + GPIO_PinInit(PIN_BOARD_REV_ID_GPIO, PIN_BOARD_REV_ID_BIT, &pin_config); + + adc_init(); + + // 1. Discharge capacitor + // Drive BRD_REV_ID pin to low + GPIO_PortClear(PIN_BOARD_REV_ID_GPIO, PIN_BOARD_REV_ID); + PORT_SetPinMux(PIN_BOARD_REV_ID_PORT , PIN_BOARD_REV_ID_BIT, kPORT_MuxAsGpio); + // Add a 3ms delay to allow the 100nF Cap to discharge + // at least 5*RC with 4700R. + for (uint32_t count = 16 * 3000; count > 0UL; count--); + + // 2. Charge capacitor for 100us + // Drive BRD_REV_ID pin to high + GPIO_PortSet(PIN_BOARD_REV_ID_GPIO, PIN_BOARD_REV_ID); + // Add a ~100us delay + // 3 clock cycles per loop at -O2 ARMCC optimization + for (uint32_t count = 1600; count > 0UL; count--); + // Change pin to ADC (High-Z). Capacitor will stop charging + PORT_SetPinMux(PIN_BOARD_REV_ID_PORT , PIN_BOARD_REV_ID_BIT, kPORT_PinDisabledOrAnalog); + + // 3. Take ADC measurement + board_rev_id_adc = adc_read_channel(0, PIN_BOARD_REV_ID_ADC_CH, PIN_BOARD_REV_ID_ADC_MUX); + board_rev_id_mv = board_rev_id_adc * 3300 / 0xFFF; // Convert ADC 12-bit value to mV with 3.3V reference + + // 4. Discharge capacitor + // Drive BRD_REV_ID pin to low + GPIO_PortClear(PIN_BOARD_REV_ID_GPIO, PIN_BOARD_REV_ID); + PORT_SetPinMux(PIN_BOARD_REV_ID_PORT , PIN_BOARD_REV_ID_BIT, kPORT_MuxAsGpio); + // Add a 3ms delay to allow the 100nF Cap to discharge + // at least 5*RC with 4700R. + for (uint32_t count = 16 * 3000; count > 0UL; count--); + + // 5. Identify board ID depending on voltage + if ( board_rev_id_mv > BRD_ID_1_LOWER_THR_V && board_rev_id_mv < BRD_ID_1_UPPER_THR_V) { + board_version = BOARD_VERSION_2_1; + } else { + board_version = BOARD_VERSION_2_0; + } + + return board_version; +} + +static void set_board_id(mb_version_t board_version) { target_device = target_device_nrf52_64; - target_device.rt_board_id = board_id_mb_2_0; + switch (board_version) { + case BOARD_VERSION_2_0: + target_device.rt_board_id = board_id_mb_2_0; + board_id_hex = 0x9903; + break; + case BOARD_VERSION_2_1: + target_device.rt_board_id = board_id_mb_2_1; + board_id_hex = 0x9904; + break; + default: + target_device.rt_board_id = board_id_mb_2_0; + board_id_hex = 0x9903; + break; + } +} + +// Apply a gamma curve to the LED. Input brightness between 0-255 +static inline uint8_t get_led_gamma(uint8_t brightness) { + uint8_t duty_cycle; + duty_cycle = (brightness * brightness * brightness + 32512) / (255*255); + return duty_cycle; } -// USB HID override function return 1 if the activity is trivial or response is null +// Called in main_task() to init before USB and files are configured +static void prerun_board_config(void) +{ + mb_version_t board_version = read_brd_rev_id_pin(); + set_board_id(board_version); + + // init power monitoring + power_init(); + pwr_mon_init(); + + power_source = pwr_mon_get_power_source(); + + flexio_pwm_init(); + flexio_pwm_init_pins(); + + if (power_source == PWR_BATT_ONLY){ + // Turn on the red LED with low duty cycle to conserve power. + power_led_max_duty_cycle = PWR_LED_ON_BATT_BRIGHTNESS; + + } else { + // Turn on the red LED with max duty cycle when powered by USB or EC + power_led_max_duty_cycle = PWR_LED_ON_MAX_BRIGHTNESS; + } + uint8_t gamma_led_dc = get_led_gamma(power_led_max_duty_cycle); + flexio_pwm_set_dutycycle(gamma_led_dc); + + i2c_initialize(); + + gpio_pin_config_t pin_config = { + .pinDirection = kGPIO_DigitalOutput, + .outputLogic = 0U + }; + + /* COMBINED_SENSOR_INT pin mux ALT0 (Disabled High-Z) */ + PORT_SetPinMux(COMBINED_SENSOR_INT_PORT, COMBINED_SENSOR_INT_PIN, kPORT_PinDisabledOrAnalog); + /* COMBINED_SENSOR_INT as output default low when pin mux ALT1 */ + GPIO_PinInit(COMBINED_SENSOR_INT_GPIO, COMBINED_SENSOR_INT_PIN, &pin_config); + + // Load Config from Flash if present + flashConfig_t * pflashConfigROM; + pflashConfigROM = (void *)FLASH_CONFIG_ADDRESS; + + if (CFG_KEY == pflashConfigROM->key) { + memcpy(&gflashConfig, pflashConfigROM, sizeof(flashConfig_t)); + } +} + +// Handle the reset button behavior, this function is called in the main task every 30ms +void handle_reset_button() +{ +#ifdef DRAG_N_DROP_SUPPORT + if (!flash_intf_target->flash_busy()) //added checking if flashing on target is in progress +#endif + { + // handle reset button without eventing + if (!reset_pressed && (gpio_get_reset_btn_fwrd() || wake_from_reset)) { + // Reset button pressed + target_set_state(RESET_PROGRAM); + reset_pressed = 1; + gpio_reset_count = 0; + wake_from_reset = 0; + main_shutdown_state = MAIN_LED_FULL_BRIGHTNESS; + } else if (reset_pressed && !gpio_get_reset_btn_fwrd()) { + // Reset button released + target_set_state(RESET_RUN); + reset_pressed = 0; + power_led_sleep_state_on = PWR_LED_SLEEP_STATE_DEFAULT; + + if (gpio_reset_count <= RESET_SHORT_PRESS) { + main_shutdown_state = MAIN_LED_BLINK_ONCE; + } + else if (gpio_reset_count < RESET_MID_PRESS) { + // Indicate button has been released to stop to cancel the shutdown + main_shutdown_state = MAIN_LED_BLINK_ONCE; + } + else if (gpio_reset_count >= RESET_MID_PRESS) { + // Indicate the button has been released when shutdown is requested + main_shutdown_state = MAIN_USER_EVENT; + } + } else if (reset_pressed && gpio_get_reset_btn_fwrd()) { + // Reset button is still pressed + if (gpio_reset_count <= RESET_SHORT_PRESS) { + // Enter the shutdown pending state to begin LED dimming + main_shutdown_state = MAIN_SHUTDOWN_PENDING; + } + else if (gpio_reset_count < RESET_MID_PRESS) { + // Enter the shutdown pending state to begin LED dimming + main_shutdown_state = MAIN_SHUTDOWN_PENDING; + } + else if (gpio_reset_count < RESET_LONG_PRESS) { + // Enter the shutdown reached state to blink LED + main_shutdown_state = MAIN_SHUTDOWN_REACHED; + } + else if (gpio_reset_count >= RESET_LONG_PRESS) { + // Enter the shutdown reached state to blink LED + main_shutdown_state = MAIN_SHUTDOWN_REACHED_FADE; + } + + // Avoid overflow, stop counting after longest event + if (gpio_reset_count <= RESET_MAX_LENGTH_PRESS) { + gpio_reset_count++; + } + } + } +} + +void board_30ms_hook() +{ + static uint8_t blink_in_progress = 0; + + if (usb_state == USB_CONNECTED) { + // configure pin as GPIO + PIN_HID_LED_PORT->PCR[PIN_HID_LED_BIT] = PORT_PCR_MUX(1); + power_led_max_duty_cycle = PWR_LED_ON_MAX_BRIGHTNESS; + } + else if (usb_state == USB_DISCONNECTED) { + // Disable pin + PIN_HID_LED_PORT->PCR[PIN_HID_LED_BIT] = PORT_PCR_MUX(0); + power_led_max_duty_cycle = PWR_LED_ON_BATT_BRIGHTNESS; + } + + if (wake_from_usb) { + main_shutdown_state = MAIN_USER_EVENT; + + if (usb_state == USB_DISCONNECTED) { + usb_state = USB_CONNECTING; + } + } + + if (i2c_wake_timeout > 0) { + i2c_wake_timeout--; + } + + // Enter light sleep if USB is not enumerated and main_shutdown_state is idle + if (usb_state == USB_DISCONNECTED && !usb_pc_connected && main_shutdown_state == MAIN_SHUTDOWN_WAITING + && automatic_sleep_on == true && g_s_handle.isBusy == false && i2c_wake_timeout == 0 && i2c_allow_sleep) { + interface_power_mode = kAPP_PowerModeVlps; + main_shutdown_state = MAIN_SHUTDOWN_REQUESTED; + } + + switch (main_shutdown_state) { + case MAIN_LED_FULL_BRIGHTNESS: + // Jump power LED to initial fade brightness + shutdown_led_dc = initial_fade_brightness; + break; + case MAIN_SHUTDOWN_CANCEL: + main_shutdown_state = MAIN_SHUTDOWN_WAITING; + // Set the PWM value back to max duty cycle + shutdown_led_dc = power_led_max_duty_cycle; + break; + case MAIN_SHUTDOWN_PENDING: + // Fade the PWM until the board is about to be shut down + shutdown_led_dc = initial_fade_brightness - gpio_reset_count * (initial_fade_brightness - PWR_LED_FADEOUT_MIN_BRIGHTNESS)/(RESET_MID_PRESS); + break; + case MAIN_SHUTDOWN_REACHED: + // Hold LED in min brightness + shutdown_led_dc = PWR_LED_FADEOUT_MIN_BRIGHTNESS; + final_fade_led_dc = get_led_gamma(PWR_LED_FADEOUT_MIN_BRIGHTNESS); + break; + case MAIN_SHUTDOWN_REACHED_FADE: + // Fast fade to off + if (final_fade_led_dc > 0) { + final_fade_led_dc--; + } + break; + case MAIN_USER_EVENT: + { + // Release COMBINED_SENSOR_INT in case it was previously asserted + PORT_SetPinMux(COMBINED_SENSOR_INT_PORT, COMBINED_SENSOR_INT_PIN, kPORT_PinDisabledOrAnalog); + + // Prepare I2C response + i2cCommand_t i2cResponse = {0}; + i2cResponse.cmdId = gReadResponse_c; + i2cResponse.cmdData.readRspCmd.propertyId = (uint8_t) gUserEvent_c; + i2cResponse.cmdData.readRspCmd.dataSize = 1; + + if (wake_from_usb) { + i2cResponse.cmdData.readRspCmd.data[0] = gWakeFromWakeOnEdge_c; + wake_from_usb = 0; + power_led_sleep_state_on = PWR_LED_SLEEP_STATE_DEFAULT; + } else { + i2cResponse.cmdData.readRspCmd.data[0] = gResetButtonLongPress_c; + } + + i2c_fillBuffer((uint8_t*) &i2cResponse, 0, sizeof(i2cResponse)); + + // Response ready, assert COMBINED_SENSOR_INT + PORT_SetPinMux(COMBINED_SENSOR_INT_PORT, COMBINED_SENSOR_INT_PIN, kPORT_MuxAsGpio); + + // Return LED to ON after release of long press + main_shutdown_state = MAIN_SHUTDOWN_WAITING; + } + break; + case MAIN_SHUTDOWN_REQUESTED: + if (power_source == PWR_BATT_ONLY || (usb_state == USB_DISCONNECTED && !usb_pc_connected)) { + main_powerdown_event(); + + // In VLLS0, set the LED either ON or LOW, depending on power_led_sleep_state_on + // When the duty cycle is 0% or 100%, the FlexIO driver will configure the pin as GPIO + if (power_led_sleep_state_on == true && interface_power_mode == kAPP_PowerModeVlls0) { + shutdown_led_dc = PWR_LED_ON_MAX_BRIGHTNESS; + } else if (power_led_sleep_state_on == true && interface_power_mode == kAPP_PowerModeVlps) { + shutdown_led_dc = PWR_LED_ON_BATT_BRIGHTNESS; + } + else { + shutdown_led_dc = 0; + } + + main_shutdown_state = MAIN_SHUTDOWN_WAITING; + } + else if (usb_state == USB_CONNECTED){ + main_shutdown_state = MAIN_LED_BLINKING; + } + break; + case MAIN_SHUTDOWN_WAITING: + // Set the PWM value back to max duty cycle + shutdown_led_dc = power_led_max_duty_cycle; + break; + case MAIN_SHUTDOWN_WAITING_OFF: + shutdown_led_dc = 0; + break; + case MAIN_LED_BLINKING: + // Blink the LED to indicate standby mode + if (shutdown_led_dc < 10) { + shutdown_led_dc++; + } else if (shutdown_led_dc == 10) { + shutdown_led_dc = PWR_LED_ON_MAX_BRIGHTNESS; + } else if (shutdown_led_dc <= (PWR_LED_ON_MAX_BRIGHTNESS - 10)) { + shutdown_led_dc = 0; + } else if (shutdown_led_dc > (PWR_LED_ON_MAX_BRIGHTNESS - 10)) { + shutdown_led_dc--; + } + + // If we are no longer PC connected, go into idle mode + if (usb_state == USB_DISCONNECTED && !usb_pc_connected) { + main_shutdown_state = MAIN_SHUTDOWN_WAITING; + } + break; + case MAIN_LED_BLINK_ONCE: + + if (blink_in_progress) { + blink_in_progress--; + if (blink_in_progress == 5) { + shutdown_led_dc = 0; + } + } else { + blink_in_progress = 10; + shutdown_led_dc = PWR_LED_ON_MAX_BRIGHTNESS; + } + + if (blink_in_progress == 0) { + main_shutdown_state = MAIN_SHUTDOWN_WAITING; + } + break; + default: + break; + } + + // Use gamma curve except in final fade + if (main_shutdown_state != MAIN_SHUTDOWN_REACHED_FADE) { + uint8_t gamma_led_dc = get_led_gamma(shutdown_led_dc); + flexio_pwm_set_dutycycle(gamma_led_dc); + } else { + flexio_pwm_set_dutycycle(final_fade_led_dc); + } + + // Remount if requested. + if (do_remount) { + do_remount = false; + vfs_mngr_fs_remount(); + } +} + +void board_handle_powerdown() +{ + switch(interface_power_mode){ + case kAPP_PowerModeVlps: + power_enter_VLPS(); + break; + case kAPP_PowerModeVlls0: + power_enter_VLLS0(); + break; + default: + break; + } +} + +void board_usb_sof_event(void) +{ + /* Set usb_pc_connected to true to prevent entering sleep mode when host does re-enumeration. + * Will be set to false when the USB cable is detached. */ + usb_pc_connected = true; +} + +void board_vfs_stream_closed_hook() +{ + // Return reset button and LED to default state + reset_pressed = 0; + power_led_sleep_state_on = PWR_LED_SLEEP_STATE_DEFAULT; + main_shutdown_state = MAIN_SHUTDOWN_WAITING; + + // Clear any pending I2C response + i2c_clearBuffer(); + + // Release COMBINED_SENSOR_INT + PORT_SetPinMux(COMBINED_SENSOR_INT_PORT, COMBINED_SENSOR_INT_PIN, kPORT_PinDisabledOrAnalog); +} + +bool vfs_user_magic_file_hook(const vfs_filename_t filename, bool *do_remount) +{ + if (!memcmp(filename, "ERASE ACT", sizeof(vfs_filename_t))) { + // Erase last 128KB flash block + FLASH_Erase(&g_flash, FLASH_CONFIG_ADDRESS, g_flash.PFlashTotalSize / g_flash.PFlashBlockCount, kFLASH_apiEraseKey); + } + + return false; +} + +void vfs_user_build_filesystem_hook() { + uint32_t file_size; + error_t status; + error_t error = vfs_mngr_get_transfer_status(); + + // Microbit error codes for DAPLink in the 500-599 range + uint16_t microbit_error = error + 500; + + if (error != ERROR_SUCCESS) { + // Error code offset after "0xFACEC0DE" magic word + g_led_error_bin_data[g_led_error_bin_code] = (uint8_t) microbit_error & 0xFF; + g_led_error_bin_data[g_led_error_bin_code + 1] = (uint8_t) (microbit_error >> 8) & 0xFF; + + status = flash_manager_init(flash_intf_target); + if (status != ERROR_SUCCESS) { + util_assert(0); + } + + status = flash_manager_data(0, (const uint8_t*)g_led_error_bin_data, g_led_error_bin_len); + if (status != ERROR_SUCCESS) { + flash_manager_uninit(); + util_assert(0); + } + + status = flash_manager_uninit(); + if (status != ERROR_SUCCESS) { + util_assert(0); + } + } + + file_size = gflashConfig.fileSize; + + if (gflashConfig.fileVisible) { + vfs_create_file(gflashConfig.fileName, read_file_data_txt, 0, file_size); + } +} + +// File callback to be used with vfs_add_file to return file contents +static uint32_t read_file_data_txt(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors) +{ + // Ignore out of bound reads + if ( (FLASH_STORAGE_ADDRESS + VFS_SECTOR_SIZE * sector_offset) < (FLASH_CONFIG_ADDRESS + FLASH_INTERFACE_SIZE) ) { + memcpy(data, (uint8_t *) (FLASH_STORAGE_ADDRESS + VFS_SECTOR_SIZE * sector_offset), VFS_SECTOR_SIZE); + } + + return VFS_SECTOR_SIZE; +} + +uint8_t board_detect_incompatible_image(const uint8_t *data, uint32_t size) +{ + uint8_t result = 0; + + // Check difference in vectors (mem fault, bus fault, usage fault) + // If these vectors are 0, we assume it's an M0 image (not compatible) + result = memcmp(data + M0_RESERVED_VECT_OFFSET, (uint8_t[M0_RESERVED_VECT_SIZE]){0}, M0_RESERVED_VECT_SIZE); + + return result == 0; +} + +// USB HID override function return 1 if the activity is trivial or response is null uint8_t usbd_hid_no_activity(uint8_t *buf) { if(buf[0] == ID_DAP_Vendor3 && buf[1] == 0) @@ -52,3 +575,4 @@ const board_info_t g_board_info = { .prerun_board_config = prerun_board_config, .target_cfg = &target_device, }; + diff --git a/source/board/microbitv2/microbitv2.h b/source/board/microbitv2/microbitv2.h new file mode 100644 index 000000000..ea0d60c1f --- /dev/null +++ b/source/board/microbitv2/microbitv2.h @@ -0,0 +1,63 @@ +/** + * @file microbitv2.h + * @brief + * + * DAPLink Interface Firmware + * Copyright 2020 NXP + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MICROBITV2_H_ +#define MICROBITV2_H_ + +#define M0_RESERVED_VECT_OFFSET (4 * 4) +#define M0_RESERVED_VECT_SIZE (3 * 4) // Size for mem fault, bus fault and usage fault vectors + +#define BRD_ID_1_UPPER_THR_V 935 // Upper threshold in mV for 100nF and 4700R +#define BRD_ID_1_LOWER_THR_V 268 // Lower threshold in mV for 100nF and 4700R + +#define PWR_LED_ON_MAX_BRIGHTNESS 255 // Max LED Brightness (PC Connected) +#define PWR_LED_INIT_FADE_BRIGHTNESS 200 // Initial fade LED Brightness +#define PWR_LED_ON_BATT_BRIGHTNESS 100 // LED Brightness while being powered by battery +#define PWR_LED_FADEOUT_MIN_BRIGHTNESS 80 // Minimum LED brightness when fading out +#define PWR_LED_SLEEP_STATE_DEFAULT true +#define AUTOMATIC_SLEEP_DEFAULT true + +#define FLASH_CONFIG_ADDRESS (0x00020000) +#define FLASH_CONFIG_SIZE (0x00000400) +#define FLASH_INTERFACE_SIZE (128*1024) +#define FLASH_STORAGE_ADDRESS (0x00020400) +#define FLASH_CFG_FILENAME "DATA BIN" +#define FLASH_CFG_FILESIZE (126*1024) +#define FLASH_CFG_FILEVISIBLE false + +// 'kvld' in hex - key valid +#define CFG_KEY 0x6b766c64 + +typedef enum main_shutdown_state { + MAIN_SHUTDOWN_WAITING = 0, + MAIN_SHUTDOWN_WAITING_OFF, + MAIN_SHUTDOWN_PENDING, + MAIN_SHUTDOWN_REACHED, + MAIN_SHUTDOWN_REACHED_FADE, + MAIN_SHUTDOWN_REQUESTED, + MAIN_USER_EVENT, + MAIN_LED_BLINK_ONCE, + MAIN_LED_BLINKING, + MAIN_LED_FULL_BRIGHTNESS, + MAIN_SHUTDOWN_CANCEL +} main_shutdown_state_t; + +#endif /* MICROBITV2_H_ */ diff --git a/source/board/microbitv2/power.c b/source/board/microbitv2/power.c new file mode 100644 index 000000000..1ee666670 --- /dev/null +++ b/source/board/microbitv2/power.c @@ -0,0 +1,240 @@ +/** + * @file power.c + * @brief + * + * DAPLink Interface Firmware + * Copyright 2020 NXP + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fsl_smc.h" +#include "fsl_rcm.h" +#include "fsl_llwu.h" +#include "fsl_pmc.h" +#include "fsl_port.h" +#include "fsl_clock.h" + +#include "main_interface.h" +#include "power.h" +#include "pwr_mon.h" +#include "IO_Config.h" +#include "uart.h" +#include "i2c_commands.h" +#include "rl_usb.h" + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +static void power_set_wakeup_config(app_power_mode_t targetMode); +static void power_mode_switch(smc_power_state_t curPowerState, app_power_mode_t targetPowerMode); +static void power_pre_switch_hook(smc_power_state_t originPowerState, app_power_mode_t targetMode); +static void power_post_switch_hook(smc_power_state_t originPowerState, app_power_mode_t targetMode); +static void power_enter_mode(app_power_mode_t targetPowerMode); + +extern volatile uint8_t wake_from_reset; +extern volatile uint8_t wake_from_usb; +extern volatile bool usb_pc_connected; +extern main_usb_connect_t usb_state; +extern power_source_t power_source; + +/******************************************************************************* + * Code + ******************************************************************************/ +void LLWU_IRQHandler(void) +{ + /* If wakeup by external pin BTN_NOT_PRESSED. */ + if (LLWU_GetExternalWakeupPinFlag(LLWU, PIN_SW_RESET_LLWU_PIN)) + { + LLWU_ClearExternalWakeupPinFlag(LLWU, PIN_SW_RESET_LLWU_PIN); + wake_from_reset = 1; + } + /* If wakeup by external pin WAKE_ON_EDGE. */ + if (LLWU_GetExternalWakeupPinFlag(LLWU, PIN_WAKE_ON_EDGE_LLWU_PIN)) + { + LLWU_ClearExternalWakeupPinFlag(LLWU, PIN_WAKE_ON_EDGE_LLWU_PIN); + wake_from_usb = 1; + } +} + +void PORTCD_IRQHandler(void) +{ + if ((1U << PIN_SW_RESET_BIT) & PORT_GetPinsInterruptFlags(PIN_SW_RESET_PORT)) + { + /* Disable interrupt. */ + PORT_SetPinInterruptConfig(PIN_SW_RESET_PORT, PIN_SW_RESET_BIT, kPORT_InterruptOrDMADisabled); + PORT_ClearPinsInterruptFlags(PIN_SW_RESET_PORT, (1U << PIN_SW_RESET_BIT)); + } + if ((1U << PIN_WAKE_ON_EDGE_BIT) & PORT_GetPinsInterruptFlags(PIN_WAKE_ON_EDGE_PORT)) + { + PORT_ClearPinsInterruptFlags(PIN_WAKE_ON_EDGE_PORT, (1U << PIN_WAKE_ON_EDGE_BIT)); + + power_source = pwr_mon_get_power_source(); + + bool usb_on = (((PIN_WAKE_ON_EDGE_GPIO->PDIR) >> PIN_WAKE_ON_EDGE_BIT) & 0x01U) ? false : true; + + if (usb_on == false) { + /* Reset USB on cable detach (VBUS falling edge) */ + USBD_Reset(); + usbd_reset_core(); + usb_pc_connected = false; + usb_state = USB_DISCONNECTED; + } + else { + // Cable inserted + wake_from_usb = 1; + } + } +} + +void power_init(void) +{ + // Configure pin as GPIO + PORT_SetPinMux(PIN_WAKE_ON_EDGE_PORT, PIN_WAKE_ON_EDGE_BIT, kPORT_MuxAsGpio); + + /* Power related. */ + SMC_SetPowerModeProtection(SMC, kSMC_AllowPowerModeAll); + if (kRCM_SourceWakeup & RCM_GetPreviousResetSources(RCM)) /* Wakeup from VLLS. */ + { + PMC_ClearPeriphIOIsolationFlag(PMC); + } + + /* Allow writes to USBREGEN */ + SIM->SOPT1CFG |= SIM_SOPT1CFG_URWE_MASK; + /* Disable USB voltage regulator */ + SIM->SOPT1 &= ~SIM_SOPT1_USBREGEN_MASK; + + /* Enable either edge interrupt on WAKE_ON_EDGE pin to detect USB attach/detach */ + PORT_SetPinInterruptConfig(PIN_WAKE_ON_EDGE_PORT, PIN_WAKE_ON_EDGE_BIT, PIN_WAKE_ON_EDGE_PORT_WAKEUP_TYPE); + + NVIC_SetPriority(LLWU_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); + NVIC_EnableIRQ(LLWU_IRQn); + NVIC_SetPriority(PORTC_PORTD_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); + NVIC_EnableIRQ(PORTC_PORTD_IRQn); +} + +void power_enter_VLLS0() +{ + power_enter_mode(kAPP_PowerModeVlls0); +} + +void power_enter_VLPS() +{ + power_enter_mode(kAPP_PowerModeVlps); +} + +static void power_enter_mode(app_power_mode_t targetPowerMode) +{ + smc_power_state_t curPowerState = (smc_power_state_t) 0; + + curPowerState = SMC_GetPowerModeState(SMC); + + if ((targetPowerMode > kAPP_PowerModeMin) && (targetPowerMode < kAPP_PowerModeMax)) + { + power_pre_switch_hook(curPowerState, targetPowerMode); + power_set_wakeup_config(targetPowerMode); + power_mode_switch(curPowerState, targetPowerMode); + power_post_switch_hook(curPowerState, targetPowerMode); + } +} + +static void power_set_wakeup_config(app_power_mode_t targetMode) +{ + PORT_SetPinInterruptConfig(PIN_SW_RESET_PORT, PIN_SW_RESET_BIT, PIN_SW_RESET_PORT_WAKEUP_TYPE); + + /* If targetMode is VLLS/LLS, setup LLWU. */ + if ((kAPP_PowerModeWait != targetMode) && (kAPP_PowerModeVlpw != targetMode) && + (kAPP_PowerModeVlps != targetMode) && (kAPP_PowerModeStop != targetMode)) + { + LLWU_SetExternalWakeupPinMode(LLWU, PIN_SW_RESET_LLWU_PIN, PIN_SW_RESET_LLWU_WAKEUP_TYPE); + LLWU_SetExternalWakeupPinMode(LLWU, PIN_WAKE_ON_EDGE_LLWU_PIN, PIN_WAKE_ON_EDGE_LLWU_WAKEUP_TYPE); + NVIC_EnableIRQ(LLWU_IRQn); + } +} + +static void power_mode_switch(smc_power_state_t curPowerState, app_power_mode_t targetPowerMode) +{ + smc_power_mode_vlls_config_t vlls_config; + vlls_config.enablePorDetectInVlls0 = true; + + switch (targetPowerMode) + { + case kAPP_PowerModeVlps: + SMC_PreEnterStopModes(); + SMC_SetPowerModeVlps(SMC); + SMC_PostExitStopModes(); + break; + + case kAPP_PowerModeVlls0: + vlls_config.subMode = kSMC_StopSub0; + SMC_PreEnterStopModes(); + SMC_SetPowerModeVlls(SMC, &vlls_config); + SMC_PostExitStopModes(); + break; + + default: + break; + } +} + +static void power_pre_switch_hook(smc_power_state_t originPowerState, app_power_mode_t targetMode) +{ + /* Wait for debug console output finished. */ + while (!(LPUART_STAT_TC_MASK & UART->STAT)) + { + } + uart_uninitialize(); + + /* Disable pins to lower current leakage */ + PORT_SetPinMux(UART_PORT, PIN_UART_RX_BIT, kPORT_PinDisabledOrAnalog); + PORT_SetPinMux(UART_PORT, PIN_UART_TX_BIT, kPORT_PinDisabledOrAnalog); + PORT_SetPinMux(PIN_HID_LED_PORT, PIN_HID_LED_BIT, kPORT_PinDisabledOrAnalog); + + /* Disable I/O pin SWCLK */ + PIN_SWCLK_PORT->PCR[PIN_SWCLK_BIT] = 0; + + /* Disable I/O pin SWDIO */ + PIN_SWDIO_PORT->PCR[PIN_SWDIO_BIT] = 0; + + /* If targetMode is VLLS0, disable I2C pins */ + if (kAPP_PowerModeVlls0 == targetMode) + { + /* PORTC1 is configured as I2C1_SCL */ + PORT_SetPinMux(PORTC, 1U, kPORT_PinDisabledOrAnalog); + + /* PORTC2 is configured as I2C1_SDA */ + PORT_SetPinMux(PORTC, 2U, kPORT_PinDisabledOrAnalog); + } +} + +static void power_post_switch_hook(smc_power_state_t originPowerState, app_power_mode_t targetMode) +{ + /* Configure I/O pin SWCLK */ + PIN_SWCLK_PORT->PCR[PIN_SWCLK_BIT] = PORT_PCR_MUX(1) | /* GPIO */ + PORT_PCR_PE_MASK; /* Pull (Down) enable */ + PIN_SWCLK_GPIO->PSOR = PIN_SWCLK; /* High level */ + PIN_SWCLK_GPIO->PDDR |= PIN_SWCLK; /* Output */ + /* Configure I/O pin SWDIO */ + PIN_SWDIO_PORT->PCR[PIN_SWDIO_BIT] = PORT_PCR_MUX(1) | /* GPIO */ + PORT_PCR_PE_MASK | /* Pull enable */ + PORT_PCR_PS_MASK; /* Pull-up */ + + /* re-configure pinmux of disabled pins */ + PORT_SetPinMux(UART_PORT, PIN_UART_RX_BIT, (port_mux_t)PIN_UART_RX_MUX_ALT); + PORT_SetPinMux(UART_PORT, PIN_UART_TX_BIT, (port_mux_t)PIN_UART_TX_MUX_ALT); + + uart_initialize(); + i2c_deinitialize(); + i2c_initialize(); +} diff --git a/source/board/microbitv2/power.h b/source/board/microbitv2/power.h new file mode 100644 index 000000000..e16035ecc --- /dev/null +++ b/source/board/microbitv2/power.h @@ -0,0 +1,53 @@ +/** + * @file power.h + * @brief + * + * DAPLink Interface Firmware + * Copyright 2020 NXP + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef POWER_H_ +#define POWER_H_ + +#include "fsl_common.h" +#include "fsl_smc.h" + +/* Power mode definition used in application. */ +typedef enum _app_power_mode +{ + kAPP_PowerModeMin = 0, + kAPP_PowerModeRun, /* Normal RUN mode */ + kAPP_PowerModeWait, /* WAIT mode. */ + kAPP_PowerModeStop, /* STOP mode. */ + kAPP_PowerModeVlpr, /* VLPR mode. */ + kAPP_PowerModeVlpw, /* VLPW mode. */ + kAPP_PowerModeVlps, /* VLPS mode. */ + kAPP_PowerModeLls, /* LLS mode. */ + kAPP_PowerModeVlls0, /* VLLS0 mode. */ + kAPP_PowerModeVlls1, /* VLLS1 mode. */ + kAPP_PowerModeVlls3, /* VLLS3 mode. */ + kAPP_PowerModeMax +} app_power_mode_t; + +void power_init(void); + +/* Lowest power mode available in KL27*/ +void power_enter_VLLS0(void); + +/* Lowest power mode that allows I2C operation with address match wakeup */ +void power_enter_VLPS(void); + +#endif /* POWER_H_ */ diff --git a/source/board/microbitv2/pwr_mon.c b/source/board/microbitv2/pwr_mon.c new file mode 100644 index 000000000..0fe9ca83d --- /dev/null +++ b/source/board/microbitv2/pwr_mon.c @@ -0,0 +1,136 @@ +/** + * @file pwr_mon.c + * @brief + * + * DAPLink Interface Firmware + * Copyright 2020 NXP + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "pwr_mon.h" +#include "adc.h" +#include "fsl_adc16.h" +#include "fsl_pmc.h" +#include "fsl_port.h" +#include "fsl_gpio.h" + +#define ADC_VBG_CHANNEL 27U +#define ADC_VBG_MUX (kADC16_ChannelMuxA) +#define ADC_VREFH_CHANNEL 29U +#define ADC_VREFH_MUX (kADC16_ChannelMuxA) + +#define ADC_MV_TO_ADC(x) ((x) * 0xFFF / 3300) // Convert mV to ADC value (12bit and 3.3V reference) +#define BATT_MIN_VOLTAGE 1500 + +static void pwr_mon_bandgap_init(void); +static uint32_t pwr_mon_read_vbg(uint32_t channelGroup); +static uint32_t pwr_mon_adc_to_mv(uint32_t raw_adc); + +void pwr_mon_init(void) +{ + gpio_pin_config_t pin_config = { + .pinDirection = kGPIO_DigitalOutput, + .outputLogic = 0U + }; + + adc_init(); + + // Configure VMON_BAT and RUN_VBAT_SENSE + GPIO_PinInit(PIN_RUN_VBAT_SENSE_GPIO, PIN_RUN_VBAT_SENSE_BIT, &pin_config); + PORT_SetPinMux(PIN_RUN_VBAT_SENSE_PORT, PIN_RUN_VBAT_SENSE_BIT, kPORT_MuxAsGpio); + PORT_SetPinMux(PIN_VMON_BAT_PORT, PIN_VMON_BAT_BIT, PIN_VMON_BAT_ALT_MODE); +} + +power_source_t pwr_mon_get_power_source(void) { + power_source_t power_source = PWR_SOURCE_NONE; + uint32_t bat_voltage_mv = 0; + uint32_t vin_voltage_mv = 0; + + // Read WAKE_ON_EDGE pin for detecting if board is USB powered + bool usb_on = (((PIN_WAKE_ON_EDGE_GPIO->PDIR) >> PIN_WAKE_ON_EDGE_BIT) & 0x01U) ? false : true; + + // Read battery voltage + bat_voltage_mv = pwr_mon_get_vbat_mv(); + + // Read Vin voltage + vin_voltage_mv = pwr_mon_get_vin_mv(); + + // Get power source based on battery and USB + if (usb_on == true && bat_voltage_mv < (BATT_MIN_VOLTAGE)) { + power_source = PWR_USB_ONLY; + } else if (usb_on == true && bat_voltage_mv >= (BATT_MIN_VOLTAGE)) { + power_source = PWR_USB_AND_BATT; + } else if (usb_on == false && bat_voltage_mv >= (BATT_MIN_VOLTAGE)) { + // If battery voltage is greater than Vin, it means the battery is used + if ( bat_voltage_mv + 200 > vin_voltage_mv ) { + power_source = PWR_BATT_ONLY; + } else { + power_source = PWR_SOURCE_NONE; + } + } + + return power_source; +} + +uint32_t pwr_mon_get_vbat_mv(void) { + // Enable voltage divider to take measurement + GPIO_PinWrite(PIN_RUN_VBAT_SENSE_GPIO, PIN_RUN_VBAT_SENSE_BIT, 1); + // Add a ~3ms delay to allow the 100nF capacitors to charge to about 3*RC. + // 3 clock cycles per loop at -O2 ARMCC optimization + for (uint32_t count = 48000; count > 0UL; count--); + uint32_t bat_adc = adc_read_channel(0, PIN_VMON_BAT_ADC_CH, PIN_VMON_BAT_ADC_MUX); + // Disable voltage divider + GPIO_PinWrite(PIN_RUN_VBAT_SENSE_GPIO, PIN_RUN_VBAT_SENSE_BIT, 0); + + // Compensate for voltage divider with ratio of 11 + bat_adc = bat_adc * 11; + + return pwr_mon_adc_to_mv(bat_adc); +} + +uint32_t pwr_mon_get_vin_mv(void) { + // ADC read the Vref (same as Vdda) and the Vbg 1V internal reference + uint32_t vref_high = adc_read_channel(0, ADC_VREFH_CHANNEL, ADC_VREFH_MUX); + uint32_t ref_volt = pwr_mon_read_vbg(0); + + // Reference voltage is 1V, scale to millivolts + return vref_high * 1000 / ref_volt; +} + +static void pwr_mon_bandgap_init(void) { + pmc_bandgap_buffer_config_t pmcBandgapConfig; + pmcBandgapConfig.enable = true; + pmcBandgapConfig.enableInLowPowerMode = false; + PMC_ConfigureBandgapBuffer(PMC, &pmcBandgapConfig); +} + +static uint32_t pwr_mon_read_vbg(uint32_t channelGroup) { + // Ensure the Vbg is enabled from first use only + static bool bandgap_enabled = false; + if (!bandgap_enabled) { + pwr_mon_bandgap_init(); + bandgap_enabled = true; + } + return adc_read_channel(channelGroup, ADC_VBG_CHANNEL, ADC_VBG_MUX); +} + +static uint32_t pwr_mon_adc_to_mv(uint32_t raw_adc) +{ + // ADC read Vbg, a 1V internal reference + uint32_t ref_volt_read = pwr_mon_read_vbg(0); + + // Scale ADC read out to millivolts + return (raw_adc * 1000) / ref_volt_read; +} diff --git a/source/board/microbitv2/pwr_mon.h b/source/board/microbitv2/pwr_mon.h new file mode 100644 index 000000000..7ed5f7efe --- /dev/null +++ b/source/board/microbitv2/pwr_mon.h @@ -0,0 +1,48 @@ +/** + * @file pwr_mon.h + * @brief + * + * DAPLink Interface Firmware + * Copyright 2020 NXP + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PWR_MON_H +#define PWR_MON_H + +#include "IO_Config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + PWR_SOURCE_NONE = 0, + PWR_USB_ONLY, + PWR_BATT_ONLY, + PWR_USB_AND_BATT +} power_source_t; + +void pwr_mon_init(void); +power_source_t pwr_mon_get_power_source(void); +uint32_t pwr_mon_get_vin_mv(void); +uint32_t pwr_mon_get_vbat_mv(void); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/daplink/bootloader/main_bootloader.c b/source/daplink/bootloader/main_bootloader.c index f4b9541cd..74eeb85ca 100644 --- a/source/daplink/bootloader/main_bootloader.c +++ b/source/daplink/bootloader/main_bootloader.c @@ -100,6 +100,11 @@ static main_led_state_t msc_led_state = MAIN_LED_FLASH; static main_usb_busy_t usb_busy; static uint32_t usb_busy_count; +__WEAK bool reset_button_pressed() +{ + return gpio_get_reset_btn(); +} + // Timer task, set flags every 30mS and 90mS void timer_task_30mS(void * arg) { @@ -262,7 +267,7 @@ int main(void) // check for invalid app image or rst button press. Should be checksum or CRC but NVIC validation is better than nothing. // If the interface has set the hold in bootloader setting don't jump to app - if (!gpio_get_reset_btn() + if (!reset_button_pressed() && g_board_info.target_cfg && validate_bin_nvic((uint8_t *)g_board_info.target_cfg->flash_regions[0].start) && !config_ram_get_initial_hold_in_bl()) { diff --git a/source/daplink/cmsis-dap/DAP.c b/source/daplink/cmsis-dap/DAP.c index d94bcd201..7e96462d2 100644 --- a/source/daplink/cmsis-dap/DAP.c +++ b/source/daplink/cmsis-dap/DAP.c @@ -1777,8 +1777,6 @@ void DAP_Setup(void) { // Default settings DAP_Data.debug_port = 0U; - DAP_Data.fast_clock = 0U; - DAP_Data.clock_delay = CLOCK_DELAY(DAP_DEFAULT_SWJ_CLOCK); DAP_Data.nominal_clock = DAP_DEFAULT_SWJ_CLOCK; DAP_Data.transfer.idle_cycles = 0U; DAP_Data.transfer.retry_count = 100U; @@ -1792,5 +1790,22 @@ void DAP_Setup(void) { DAP_Data.jtag_dev.count = 0U; #endif + if (DAP_DEFAULT_SWJ_CLOCK >= MAX_SWJ_CLOCK(DELAY_FAST_CYCLES)) { + DAP_Data.fast_clock = 1U; + DAP_Data.clock_delay = 1U; + } else { + DAP_Data.fast_clock = 0U; + + uint32_t delay = ((CPU_CLOCK/2U) + (DAP_DEFAULT_SWJ_CLOCK - 1U)) / DAP_DEFAULT_SWJ_CLOCK; + if (delay > IO_PORT_WRITE_CYCLES) { + delay -= IO_PORT_WRITE_CYCLES; + delay = (delay + (DELAY_SLOW_CYCLES - 1U)) / DELAY_SLOW_CYCLES; + } else { + delay = 1U; + } + + DAP_Data.clock_delay = delay; + } + DAP_SETUP(); // Device specific setup } diff --git a/source/daplink/cmsis-dap/DAP_vendor.c b/source/daplink/cmsis-dap/DAP_vendor.c index 5a4fd79db..ce34cab28 100644 --- a/source/daplink/cmsis-dap/DAP_vendor.c +++ b/source/daplink/cmsis-dap/DAP_vendor.c @@ -102,6 +102,9 @@ uint32_t DAP_ProcessVendorCommand(const uint8_t *request, uint8_t *response) { // uart read int32_t read_len = 62; read_len = uart_read_data(response + 1, read_len); + if (read_len) { + main_blink_cdc_led(MAIN_LED_FLASH); + } response[0] = read_len; // increment request and response count num += (read_len + 1); @@ -112,6 +115,7 @@ uint32_t DAP_ProcessVendorCommand(const uint8_t *request, uint8_t *response) { int32_t write_len = *request; request++; uart_write_data((uint8_t *)request, write_len); + main_blink_cdc_led(MAIN_LED_FLASH); *response = 1; num += ((write_len + 1) << 16) | 1; break; @@ -157,6 +161,7 @@ uint32_t DAP_ProcessVendorCommand(const uint8_t *request, uint8_t *response) { // write to mass storage device uint32_t write_len = *request; request++; + main_blink_msc_led(MAIN_LED_FLASH); *response = stream_write((uint8_t *)request, write_len); num += ((write_len + 1) << 16) | 1; break; diff --git a/source/daplink/drag-n-drop/flash_decoder.c b/source/daplink/drag-n-drop/flash_decoder.c index 3854f57e2..ce7109fd1 100644 --- a/source/daplink/drag-n-drop/flash_decoder.c +++ b/source/daplink/drag-n-drop/flash_decoder.c @@ -29,6 +29,7 @@ #include "settings.h" // for config_get_automation_allowed #include "validation.h" #include "target_board.h" +#include "cmsis_compiler.h" // Set to 1 to enable debugging #define DEBUG_FLASH_DECODER 0 @@ -59,6 +60,11 @@ static bool flash_type_target_bin; static bool flash_decoder_is_at_end(uint32_t addr, const uint8_t *data, uint32_t size); +__WEAK uint8_t board_detect_incompatible_image(const uint8_t *data, uint32_t size) +{ + return 0; // Return 0 if image is compatible +} + flash_decoder_type_t flash_decoder_detect_type(const uint8_t *data, uint32_t size, uint32_t addr, bool addr_valid) { daplink_info_t info; @@ -124,9 +130,14 @@ error_t flash_decoder_get_flash(flash_decoder_type_t type, uint32_t addr, bool a flash_intf_local = flash_intf_iap_protected; } } else if (FLASH_DECODER_TYPE_TARGET == type) { - // "Target" update in this case would be a 3rd party interface application - flash_start_local = DAPLINK_ROM_IF_START; - flash_intf_local = flash_intf_iap_protected; + if (addr_valid && (DAPLINK_ROM_IF_START != addr)) { + // Address is wrong so display error message + status = ERROR_FD_INTF_UPDT_ADDR_WRONG; + } else { + // "Target" update in this case would be a 3rd party interface application + flash_start_local = DAPLINK_ROM_IF_START; + flash_intf_local = flash_intf_iap_protected; + } } else { status = ERROR_FD_UNSUPPORTED_UPDATE; } @@ -179,6 +190,28 @@ error_t flash_decoder_get_flash(flash_decoder_type_t type, uint32_t addr, bool a return status; } +error_t flash_decoder_validate_target_image(flash_decoder_type_t type, const uint8_t *data, uint32_t size) +{ + error_t status = ERROR_SUCCESS; + + if (daplink_is_interface()) { + if (FLASH_DECODER_TYPE_TARGET == type) { + if (g_board_info.target_cfg) { + if (board_detect_incompatible_image(data, size)){ + status = ERROR_FD_INCOMPATIBLE_IMAGE; + flash_intf_target->init(); + flash_intf_target->erase_chip(); + flash_intf_target->uninit(); + } else { + status = ERROR_SUCCESS; + } + } + } + } + + return status; +} + error_t flash_decoder_open(void) { flash_decoder_printf("flash_decoder_open()\r\n"); @@ -262,6 +295,16 @@ error_t flash_decoder_write(uint32_t addr, const uint8_t *data, uint32_t size) state = DECODER_STATE_ERROR; return status; } + + // Validate incompatible target image file + if (config_get_detect_incompatible_target()){ + status = flash_decoder_validate_target_image(flash_type, flash_buf, flash_buf_pos); + + if (ERROR_SUCCESS != status) { + state = DECODER_STATE_ERROR; + return status; + } + } flash_decoder_printf(" flash_start_addr=0x%x\r\n", flash_start_addr); // Initialize flash manager diff --git a/source/daplink/drag-n-drop/flash_decoder.h b/source/daplink/drag-n-drop/flash_decoder.h index 2895c93d0..bf6b0bd8c 100644 --- a/source/daplink/drag-n-drop/flash_decoder.h +++ b/source/daplink/drag-n-drop/flash_decoder.h @@ -45,6 +45,7 @@ typedef enum { flash_decoder_type_t flash_decoder_detect_type(const uint8_t *data, uint32_t size, uint32_t addr, bool addr_valid); error_t flash_decoder_get_flash(flash_decoder_type_t type, uint32_t addr, bool addr_valid, uint32_t *start_addr, const flash_intf_t **flash_intf); +error_t flash_decoder_validate_target_image(flash_decoder_type_t type, const uint8_t *data, uint32_t size); error_t flash_decoder_open(void); error_t flash_decoder_write(uint32_t addr, const uint8_t *data, uint32_t size); error_t flash_decoder_close(void); diff --git a/source/daplink/drag-n-drop/intelhex.c b/source/daplink/drag-n-drop/intelhex.c index 58f7c7883..fe222540b 100644 --- a/source/daplink/drag-n-drop/intelhex.c +++ b/source/daplink/drag-n-drop/intelhex.c @@ -22,6 +22,7 @@ #include #include "intelhex.h" +#include "cmsis_compiler.h" typedef enum hex_record_t hex_record_t; enum hex_record_t { @@ -30,7 +31,9 @@ enum hex_record_t { EXT_SEG_ADDR_RECORD = 2, START_SEG_ADDR_RECORD = 3, EXT_LINEAR_ADDR_RECORD = 4, - START_LINEAR_ADDR_RECORD = 5 + START_LINEAR_ADDR_RECORD = 5, + CUSTOM_METADATA_RECORD = 0x0A, + CUSTOM_DATA_RECORD = 0x0D, }; typedef union hex_line_t hex_line_t; @@ -82,6 +85,9 @@ static uint8_t validate_checksum(hex_line_t *record) static hex_line_t line = {0}, shadow_line = {0}; static uint32_t next_address_to_write = 0; static uint8_t low_nibble = 0, idx = 0, record_processed = 0, load_unaligned_record = 0; +static uint16_t binary_version = 0; +uint16_t board_id_hex __WEAK; +uint16_t board_id_hex_min __WEAK; void reset_hex_parser(void) { @@ -92,6 +98,7 @@ void reset_hex_parser(void) idx = 0; record_processed = 0; load_unaligned_record = 0; + binary_version = 0; } hexfile_parse_status_t parse_hex_blob(const uint8_t *hex_blob, const uint32_t hex_blob_size, uint32_t *hex_parse_cnt, uint8_t *bin_buf, const uint32_t bin_buf_size, uint32_t *bin_buf_address, uint32_t *bin_buf_cnt) @@ -147,23 +154,34 @@ hexfile_parse_status_t parse_hex_blob(const uint8_t *hex_blob, const uint32_t he line.address = swap16(line.address); switch (line.record_type) { + case CUSTOM_METADATA_RECORD: + binary_version = (uint16_t) line.data[0] << 8 | line.data[1]; + break; case DATA_RECORD: + case CUSTOM_DATA_RECORD: // keeping a record of the last hex record memcpy(shadow_line.buf, line.buf, sizeof(hex_line_t)); - // verify this is a continous block of memory or need to exit and dump - if (((next_address_to_write & 0xffff0000) | line.address) != next_address_to_write) { - load_unaligned_record = 1; - status = HEX_PARSE_UNALIGNED; - goto hex_parser_exit; + if (binary_version == 0 || (binary_version >= board_id_hex_min && binary_version <= board_id_hex)){ + // Only save data from the correct binary + // verify this is a continous block of memory or need to exit and dump + if (((next_address_to_write & 0xffff0000) | line.address) != next_address_to_write) { + load_unaligned_record = 1; + status = HEX_PARSE_UNALIGNED; + goto hex_parser_exit; + } + + // move from line buffer back to input buffer + memcpy(bin_buf, line.data, line.byte_count); + bin_buf += line.byte_count; + *bin_buf_cnt = (uint32_t)(*bin_buf_cnt) + line.byte_count; + // Save next address to write + next_address_to_write = ((next_address_to_write & 0xffff0000) | line.address) + line.byte_count; + } + else { + status = HEX_PARSE_OK; + goto hex_parser_exit; } - - // move from line buffer back to input buffer - memcpy(bin_buf, line.data, line.byte_count); - bin_buf += line.byte_count; - *bin_buf_cnt = (uint32_t)(*bin_buf_cnt) + line.byte_count; - // Save next address to write - next_address_to_write = ((next_address_to_write & 0xffff0000) | line.address) + line.byte_count; break; case EOF_RECORD: diff --git a/source/daplink/drag-n-drop/vfs_manager.c b/source/daplink/drag-n-drop/vfs_manager.c index 64a90ba94..d50ae01bc 100644 --- a/source/daplink/drag-n-drop/vfs_manager.c +++ b/source/daplink/drag-n-drop/vfs_manager.c @@ -158,6 +158,7 @@ static void transfer_stream_open(stream_type_t stream, uint32_t start_sector); static void transfer_stream_data(uint32_t sector, const uint8_t *data, uint32_t size); static void transfer_update_state(error_t status); +__WEAK void board_vfs_stream_closed_hook(void){} void vfs_mngr_fs_enable(bool enable) { @@ -717,6 +718,9 @@ static void transfer_stream_data(uint32_t sector, const uint8_t *data, uint32_t file_transfer_state.stream_open = false; file_transfer_state.stream_finished = true; file_transfer_state.stream_optional_finish = true; + + // Custom board hook to notify that a stream has close (flashing finished) + board_vfs_stream_closed_hook(); } else if (ERROR_SUCCESS_DONE_OR_CONTINUE == status) { status = ERROR_SUCCESS; file_transfer_state.stream_optional_finish = true; diff --git a/source/daplink/drag-n-drop/vfs_user.c b/source/daplink/drag-n-drop/vfs_user.c index c4eab4610..b92790f0d 100644 --- a/source/daplink/drag-n-drop/vfs_user.c +++ b/source/daplink/drag-n-drop/vfs_user.c @@ -45,6 +45,11 @@ //! device. This is to accomodate for hex file programming. #define VFS_DISK_SIZE (MB(64)) +// Additional buffer space to display more than 512 bytes in DETAILS.TXT +#if !defined(BOARD_EXTRA_BUFFER) +#define BOARD_EXTRA_BUFFER 0 +#endif + //! @brief Constants for magic action or config files. //! //! The "magic files" are files with a special name that if created on the USB MSC volume, will @@ -66,6 +71,8 @@ typedef enum _magic_file { kOverflowOffConfigFile, //!< Disable UART overflow reporting. kMSDOnConfigFile, //!< Enable USB MSC. Uh.... kMSDOffConfigFile, //!< Disable USB MSC. + kImageCheckOnConfigFile, //!< Enable Incompatible target image detection. + kImageCheckOffConfigFile, //!< Disable Incompatible target image detection. kPageEraseActionFile, //!< Enable page programming and sector erase for drag and drop. kChipEraseActionFile, //!< Enable page programming and chip erase for drag and drop. } magic_file_t; @@ -110,11 +117,13 @@ static const magic_file_info_t s_magic_file_info[] = { { "OVFL_OFFCFG", kOverflowOffConfigFile }, { "MSD_ON CFG", kMSDOnConfigFile }, { "MSD_OFF CFG", kMSDOffConfigFile }, + { "COMP_ON CFG", kImageCheckOnConfigFile }, + { "COMP_OFFCFG", kImageCheckOffConfigFile }, { "PAGE_ON ACT", kPageEraseActionFile }, { "PAGE_OFFACT", kChipEraseActionFile }, }; -static uint8_t file_buffer[VFS_SECTOR_SIZE]; +static uint8_t file_buffer[VFS_SECTOR_SIZE+BOARD_EXTRA_BUFFER]; static char assert_buf[64 + 1]; static uint16_t assert_line; static assert_source_t assert_source; @@ -134,6 +143,8 @@ static void erase_target(void); static uint32_t expand_info(uint8_t *buf, uint32_t bufsize); +__WEAK void vfs_user_build_filesystem_hook(){} + void vfs_user_build_filesystem() { uint32_t file_size; @@ -173,6 +184,8 @@ void vfs_user_build_filesystem() file_size = get_file_size(read_file_need_bl_txt); vfs_create_file("NEED_BL TXT", read_file_need_bl_txt, 0, file_size); } + + vfs_user_build_filesystem_hook(); } // Default file change hook. @@ -268,6 +281,12 @@ void vfs_user_file_change_handler(const vfs_filename_t filename, vfs_file_change case kMSDOffConfigFile: config_ram_set_disable_msd(true); break; + case kImageCheckOnConfigFile: + config_set_detect_incompatible_target(true); + break; + case kImageCheckOffConfigFile: + config_set_detect_incompatible_target(false); + break; case kPageEraseActionFile: config_ram_set_page_erase(true); break; @@ -334,12 +353,22 @@ static uint32_t read_file_mbed_htm(uint32_t sector_offset, uint8_t *data, uint32 // File callback to be used with vfs_add_file to return file contents static uint32_t read_file_details_txt(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors) { + uint32_t size = 0; - if (sector_offset != 0) { + if (sector_offset > 1) { return 0; } + + size = update_details_txt_file(file_buffer, VFS_SECTOR_SIZE+BOARD_EXTRA_BUFFER); + + if (size - VFS_SECTOR_SIZE * sector_offset > VFS_SECTOR_SIZE) { + memcpy(data, file_buffer + sector_offset * VFS_SECTOR_SIZE, VFS_SECTOR_SIZE); + } + else { + memcpy(data, file_buffer + sector_offset * VFS_SECTOR_SIZE, size - VFS_SECTOR_SIZE * sector_offset); + } - return update_details_txt_file(data, VFS_SECTOR_SIZE); + return size; } // Text representation of each error type, starting from the rightmost bit @@ -492,6 +521,9 @@ static uint32_t update_details_txt_file(uint8_t *data, uint32_t datasize) pos += util_write_string(buf + pos, "Overflow detection: "); pos += util_write_string(buf + pos, config_get_overflow_detect() ? "1" : "0"); pos += util_write_string(buf + pos, "\r\n"); + pos += util_write_string(buf + pos, "Incompatible image detection: "); + pos += util_write_string(buf + pos, config_get_detect_incompatible_target() ? "1" : "0"); + pos += util_write_string(buf + pos, "\r\n"); pos += util_write_string(buf + pos, "Page erasing: "); pos += util_write_string(buf + pos, config_ram_get_page_erase() ? "1" : "0"); pos += util_write_string(buf + pos, "\r\n"); diff --git a/source/daplink/drag-n-drop/virtual_fs.c b/source/daplink/drag-n-drop/virtual_fs.c index 94c80bfb3..c8b903e3b 100644 --- a/source/daplink/drag-n-drop/virtual_fs.c +++ b/source/daplink/drag-n-drop/virtual_fs.c @@ -114,7 +114,6 @@ static void write_dir(uint32_t offset, const uint8_t *data, uint32_t size); static void file_change_cb_stub(const vfs_filename_t filename, vfs_file_change_t change, vfs_file_t file, vfs_file_t new_file_data); static uint32_t cluster_to_sector(uint32_t cluster_idx); -static bool filename_valid(const vfs_filename_t filename); static bool filename_character_valid(char character); // If sector size changes update comment below @@ -684,7 +683,7 @@ static uint32_t cluster_to_sector(uint32_t cluster_idx) return sectors_before_data + (cluster_idx - 2) * mbr.sectors_per_cluster; } -static bool filename_valid(const vfs_filename_t filename) +bool filename_valid(const vfs_filename_t filename) { // Information on valid 8.3 filenames can be found in // the microsoft hardware whitepaper: diff --git a/source/daplink/drag-n-drop/virtual_fs.h b/source/daplink/drag-n-drop/virtual_fs.h index 581017c8f..aa6713da2 100644 --- a/source/daplink/drag-n-drop/virtual_fs.h +++ b/source/daplink/drag-n-drop/virtual_fs.h @@ -23,6 +23,7 @@ #define VIRTUAL_FS_H #include +#include #ifdef __cplusplus extern "C" { @@ -101,6 +102,9 @@ void vfs_read(uint32_t sector, uint8_t *buf, uint32_t num_of_sectors); // Write one or more sectors to the virtual filesystem void vfs_write(uint32_t sector, const uint8_t *buf, uint32_t num_of_sectors); +// Validate 8.3 filenames +bool filename_valid(const vfs_filename_t filename); + #ifdef __cplusplus } #endif diff --git a/source/daplink/error.c b/source/daplink/error.c index 965c2dfbd..6ae288930 100644 --- a/source/daplink/error.c +++ b/source/daplink/error.c @@ -99,6 +99,8 @@ static const char *const error_message[] = { "The starting address for the interface update is wrong.", // ERROR_FD_UNSUPPORTED_UPDATE "The application file format is unknown and cannot be parsed and/or processed.", + // ERROR_FD_INCOMPATIBLE_IMAGE + "The application image is not compatible with the target.", /* Flash IAP interface */ @@ -203,6 +205,8 @@ static error_type_t error_type[] = { ERROR_TYPE_USER, // ERROR_FD_UNSUPPORTED_UPDATE ERROR_TYPE_USER, + // ERROR_FD_INCOMPATIBLE_IMAGE + ERROR_TYPE_USER, /* Flash IAP interface */ diff --git a/source/daplink/error.h b/source/daplink/error.h index c3a096086..ed248cbae 100644 --- a/source/daplink/error.h +++ b/source/daplink/error.h @@ -27,6 +27,7 @@ extern "C" { #endif // Keep in sync with the lists error_message and error_type +// New values shold be added to the end of the enum to preserve error codes typedef enum { /* Shared errors */ ERROR_SUCCESS = 0, @@ -66,6 +67,7 @@ typedef enum { ERROR_FD_BL_UPDT_ADDR_WRONG, ERROR_FD_INTF_UPDT_ADDR_WRONG, ERROR_FD_UNSUPPORTED_UPDATE, + ERROR_FD_INCOMPATIBLE_IMAGE, /* Flash IAP interface */ ERROR_IAP_INIT, diff --git a/source/daplink/interface/main_interface.c b/source/daplink/interface/main_interface.c index 24f9678e7..76bd7240f 100644 --- a/source/daplink/interface/main_interface.c +++ b/source/daplink/interface/main_interface.c @@ -73,6 +73,7 @@ void __libc_init_array (void) {} // Reset events #define FLAGS_MAIN_RESET (1 << 2) // Other Events +#define FLAGS_BOARD_EVENT (1 << 3) #define FLAGS_MAIN_POWERDOWN (1 << 4) #define FLAGS_MAIN_DISABLEDEBUG (1 << 5) #define FLAGS_MAIN_PROC_USB (1 << 9) @@ -143,6 +144,43 @@ static main_led_state_t msc_led_state = MAIN_LED_FLASH; main_usb_connect_t usb_state; static bool usb_test_mode = false; +__WEAK void board_30ms_hook(void) +{ + +} + +__WEAK void handle_reset_button(void) +{ + // button state + static uint8_t reset_pressed = 0; + + // handle reset button without eventing + if (!reset_pressed && gpio_get_reset_btn_fwrd()) { +#ifdef DRAG_N_DROP_SUPPORT + if (!flash_intf_target->flash_busy()) //added checking if flashing on target is in progress +#endif + { + // Reset button pressed + target_set_state(RESET_HOLD); + reset_pressed = 1; + } + } else if (reset_pressed && !gpio_get_reset_btn_fwrd()) { + // Reset button released + target_set_state(RESET_RUN); + reset_pressed = 0; + } +} + +__WEAK void board_handle_powerdown() +{ + // TODO: put the interface chip in sleep mode +} + +__WEAK void board_custom_event() +{ + +} + // Timer task, set flags every 30mS and 90mS void timer_task_30mS(void * arg) { @@ -192,6 +230,13 @@ void main_powerdown_event(void) return; } +// Set custom board event +void main_board_event(void) +{ + osThreadFlagsSet(main_task_id, FLAGS_BOARD_EVENT); + return; +} + // Disable debug on target void main_disable_debug_event(void) { @@ -229,8 +274,6 @@ void main_task(void * arg) // USB uint32_t usb_state_count = USB_BUSY_TIME; uint32_t usb_no_config_count = USB_CONFIGURE_TIMEOUT; - // button state - uint8_t reset_pressed = 0; #ifdef PBON_BUTTON uint8_t power_on = 1; #endif @@ -304,6 +347,7 @@ void main_task(void * arg) | FLAGS_MAIN_DISABLEDEBUG // Disable target debug | FLAGS_MAIN_PROC_USB // process usb events | FLAGS_MAIN_CDC_EVENT // cdc event + | FLAGS_BOARD_EVENT // custom board event , osFlagsWaitAny , osWaitForever); @@ -332,8 +376,7 @@ void main_task(void * arg) gpio_set_cdc_led(GPIO_LED_OFF); gpio_set_msc_led(GPIO_LED_OFF); - // TODO: put the interface chip in sleep mode - while (1); + board_handle_powerdown(); } if (flags & FLAGS_MAIN_DISABLEDEBUG) { @@ -344,6 +387,10 @@ void main_task(void * arg) if (flags & FLAGS_MAIN_CDC_EVENT) { cdc_process_event(); } + + if (flags & FLAGS_BOARD_EVENT) { + board_custom_event(); + } if (flags & FLAGS_MAIN_90MS) { // Update USB busy status @@ -382,12 +429,21 @@ void main_task(void * arg) // powered by a USB wall wart or similar power source. Go ahead and enable // board power. gpio_set_board_power(true); + usb_state = USB_DISCONNECTED; } break; case USB_CONNECTED: case USB_DISCONNECTED: + if (usbd_configured()) { + usb_state = USB_CONNECTED; + } + else { + usb_state = USB_DISCONNECTED; + usb_state_count = USB_CONNECT_DELAY; + usb_no_config_count = USB_CONFIGURE_TIMEOUT; + } default: break; } @@ -396,21 +452,7 @@ void main_task(void * arg) // 30mS tick used for flashing LED when USB is busy if (flags & FLAGS_MAIN_30MS) { - // handle reset button without eventing - if (!reset_pressed && gpio_get_reset_btn_fwrd()) { -#ifdef DRAG_N_DROP_SUPPORT - if (!flash_intf_target->flash_busy()) //added checking if flashing on target is in progress -#endif - { - // Reset button pressed - target_set_state(RESET_HOLD); - reset_pressed = 1; - } - } else if (reset_pressed && !gpio_get_reset_btn_fwrd()) { - // Reset button released - target_set_state(RESET_RUN); - reset_pressed = 0; - } + handle_reset_button(); #ifdef PBON_BUTTON // handle PBON pressed @@ -434,6 +476,8 @@ void main_task(void * arg) } } #endif + // 30ms event hook function + board_30ms_hook(); // DAP LED if (hid_led_usb_activity) { diff --git a/source/daplink/interface/main_interface.h b/source/daplink/interface/main_interface.h index 06d8cdb3d..e27c2dc46 100644 --- a/source/daplink/interface/main_interface.h +++ b/source/daplink/interface/main_interface.h @@ -48,6 +48,7 @@ extern "C" { void main_reset_target(uint8_t send_unique_id); void main_usb_set_test_mode(bool enabled); void main_powerdown_event(void); +void main_board_event(void); void main_disable_debug_event(void); void main_cdc_send_event(void); void main_msc_disconnect_event(void); diff --git a/source/daplink/interface/swd_host.c b/source/daplink/interface/swd_host.c index ff0b7170c..1e51ee319 100644 --- a/source/daplink/interface/swd_host.c +++ b/source/daplink/interface/swd_host.c @@ -1051,6 +1051,19 @@ uint8_t swd_set_target_state_sw(target_state_t state) osDelay(2); swd_set_target_reset(0); osDelay(2); + + // Power down + if (!swd_write_dp(DP_CTRL_STAT, 0x0)) { + return 0; + } + + // Wait until ACK is deasserted + do { + if (!swd_read_dp(DP_CTRL_STAT, &val)) { + return 0; + } + } while ((val & (CSYSPWRUPACK | CDBGPWRUPACK)) == 1); + swd_off(); break; diff --git a/source/daplink/settings/settings.h b/source/daplink/settings/settings.h index 7a84ba6f4..0e823ae82 100644 --- a/source/daplink/settings/settings.h +++ b/source/daplink/settings/settings.h @@ -42,9 +42,11 @@ void config_init(void); void config_set_auto_rst(bool on); void config_set_automation_allowed(bool on); void config_set_overflow_detect(bool on); +void config_set_detect_incompatible_target(bool on); bool config_get_auto_rst(void); bool config_get_automation_allowed(void); bool config_get_overflow_detect(void); +bool config_get_detect_incompatible_target(void); // Get/set settings residing in shared ram void config_ram_set_hold_in_bl(bool hold); diff --git a/source/daplink/settings/settings_rom.c b/source/daplink/settings/settings_rom.c index be01a5ba9..2ecd00ca8 100644 --- a/source/daplink/settings/settings_rom.c +++ b/source/daplink/settings/settings_rom.c @@ -44,13 +44,14 @@ typedef struct __attribute__((__packed__)) cfg_setting { uint8_t auto_rst; uint8_t automation_allowed; uint8_t overflow_detect; + uint8_t detect_incompatible_target; // Add new members here } cfg_setting_t; // Make sure FORMAT in generate_config.py is updated if size changes -COMPILER_ASSERT(sizeof(cfg_setting_t) == 9); +COMPILER_ASSERT(sizeof(cfg_setting_t) == 10); // Sector buffer must be as big or bigger than settings COMPILER_ASSERT(sizeof(cfg_setting_t) < SECTOR_BUFFER_SIZE); @@ -74,6 +75,7 @@ static const cfg_setting_t config_default = { .auto_rst = 1, .automation_allowed = 1, .overflow_detect = 1, + .detect_incompatible_target = 0 }; // Check if the configuration in flash needs to be updated @@ -169,6 +171,12 @@ void config_set_overflow_detect(bool on) program_cfg(&config_rom_copy); } +void config_set_detect_incompatible_target(bool on) +{ + config_rom_copy.detect_incompatible_target = on; + program_cfg(&config_rom_copy); +} + bool config_get_auto_rst() { return config_rom_copy.auto_rst; @@ -183,3 +191,8 @@ bool config_get_overflow_detect() { return config_rom_copy.overflow_detect; } + +bool config_get_detect_incompatible_target() +{ + return config_rom_copy.detect_incompatible_target; +} diff --git a/source/daplink/settings/settings_rom_stub.c b/source/daplink/settings/settings_rom_stub.c index 22d82013e..29826280f 100644 --- a/source/daplink/settings/settings_rom_stub.c +++ b/source/daplink/settings/settings_rom_stub.c @@ -41,6 +41,11 @@ void config_set_overflow_detect(bool on) // Do nothing } +void config_set_detect_incompatible_target(bool on) +{ + // Do nothing +} + bool config_get_auto_rst() { return false; @@ -55,3 +60,8 @@ bool config_get_overflow_detect() { return false; } + +bool config_get_detect_incompatible_target() +{ + return false; +} diff --git a/source/hic_hal/adc.h b/source/hic_hal/adc.h new file mode 100644 index 000000000..4d70131f3 --- /dev/null +++ b/source/hic_hal/adc.h @@ -0,0 +1,39 @@ +/** + * @file adc.h + * @brief + * + * DAPLink Interface Firmware + * Copyright 2020 NXP + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ADC_H +#define ADC_H + +#include "IO_Config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void adc_init(void); +void adc_init_pins(void); +uint32_t adc_read_channel(uint32_t channelGroup, uint32_t channelNumber, uint32_t channelMux); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/hic_hal/atmel/sam3u2c/usb_config.c b/source/hic_hal/atmel/sam3u2c/usb_config.c index ed39c0cfb..e78132cd4 100644 --- a/source/hic_hal/atmel/sam3u2c/usb_config.c +++ b/source/hic_hal/atmel/sam3u2c/usb_config.c @@ -68,7 +68,11 @@ // when the device is fully operational (bMaxPower) // #define USBD_CFGDESC_BMATTRIBUTES 0x80 +#if !defined(BOARD_USB_BMAXPOWER) #define USBD_CFGDESC_BMAXPOWER 0xFA +#else +#define USBD_CFGDESC_BMAXPOWER BOARD_USB_BMAXPOWER +#endif // String Settings // These settings affect String Descriptor diff --git a/source/hic_hal/freescale/k20dx/usb_config.c b/source/hic_hal/freescale/k20dx/usb_config.c index 123957820..972a0523f 100644 --- a/source/hic_hal/freescale/k20dx/usb_config.c +++ b/source/hic_hal/freescale/k20dx/usb_config.c @@ -68,7 +68,11 @@ // when the device is fully operational (bMaxPower) // #define USBD_CFGDESC_BMATTRIBUTES 0x80 +#if !defined(BOARD_USB_BMAXPOWER) #define USBD_CFGDESC_BMAXPOWER 0xFA +#else +#define USBD_CFGDESC_BMAXPOWER BOARD_USB_BMAXPOWER +#endif // String Settings // These settings affect String Descriptor diff --git a/source/hic_hal/freescale/k26f/usb_config.c b/source/hic_hal/freescale/k26f/usb_config.c index f816f800c..9b8dde6c1 100644 --- a/source/hic_hal/freescale/k26f/usb_config.c +++ b/source/hic_hal/freescale/k26f/usb_config.c @@ -77,7 +77,11 @@ // when the device is fully operational (bMaxPower) // #define USBD_CFGDESC_BMATTRIBUTES 0x80 +#if !defined(BOARD_USB_BMAXPOWER) #define USBD_CFGDESC_BMAXPOWER 0xFA +#else +#define USBD_CFGDESC_BMAXPOWER BOARD_USB_BMAXPOWER +#endif // String Settings // These settings affect String Descriptor diff --git a/source/hic_hal/freescale/kl26z/usb_config.c b/source/hic_hal/freescale/kl26z/usb_config.c index 123957820..972a0523f 100644 --- a/source/hic_hal/freescale/kl26z/usb_config.c +++ b/source/hic_hal/freescale/kl26z/usb_config.c @@ -68,7 +68,11 @@ // when the device is fully operational (bMaxPower) // #define USBD_CFGDESC_BMATTRIBUTES 0x80 +#if !defined(BOARD_USB_BMAXPOWER) #define USBD_CFGDESC_BMAXPOWER 0xFA +#else +#define USBD_CFGDESC_BMAXPOWER BOARD_USB_BMAXPOWER +#endif // String Settings // These settings affect String Descriptor diff --git a/source/hic_hal/freescale/kl27z/DAP_config.h b/source/hic_hal/freescale/kl27z/DAP_config.h index 672e62906..3bd98065c 100644 --- a/source/hic_hal/freescale/kl27z/DAP_config.h +++ b/source/hic_hal/freescale/kl27z/DAP_config.h @@ -68,7 +68,9 @@ Provides definitions about: /// Default communication speed on the Debug Access Port for SWD and JTAG mode. /// Used to initialize the default SWD/JTAG clock frequency. /// The command \ref DAP_SWJ_Clock can be used to overwrite this default setting. +#if !defined(DAP_DEFAULT_SWJ_CLOCK) #define DAP_DEFAULT_SWJ_CLOCK 5000000 ///< Default SWD/JTAG clock frequency in Hz. +#endif /// Maximum Package Size for Command and Response data. /// This configuration settings is used to optimized the communication performance with the diff --git a/source/hic_hal/freescale/kl27z/adc.c b/source/hic_hal/freescale/kl27z/adc.c new file mode 100644 index 000000000..cc4ddfacd --- /dev/null +++ b/source/hic_hal/freescale/kl27z/adc.c @@ -0,0 +1,62 @@ +/** + * @file adc.c + * @brief + * + * DAPLink Interface Firmware + * Copyright 2020 NXP + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "adc.h" +#include "fsl_adc16.h" + +#define ADC_BASE ADC0 + +void adc_init(void) +{ + adc16_config_t adc16ConfigStruct; + adc16ConfigStruct.referenceVoltageSource = kADC16_ReferenceVoltageSourceVref; + adc16ConfigStruct.clockSource = kADC16_ClockSourceAsynchronousClock; + adc16ConfigStruct.enableAsynchronousClock = true; + adc16ConfigStruct.clockDivider = kADC16_ClockDivider1; + adc16ConfigStruct.resolution = kADC16_ResolutionSE12Bit; + adc16ConfigStruct.longSampleMode = kADC16_LongSampleCycle24; + adc16ConfigStruct.enableHighSpeed = false; + adc16ConfigStruct.enableLowPower = false; + adc16ConfigStruct.enableContinuousConversion = false; + //ADC16_GetDefaultConfig(&adc16ConfigStruct); + ADC16_Init(ADC_BASE, &adc16ConfigStruct); + ADC16_SetHardwareAverage(ADC_BASE, kADC16_HardwareAverageCount8); + ADC16_DoAutoCalibration(ADC_BASE); +} + +void adc_init_pins() +{ + +} + +uint32_t adc_read_channel(uint32_t channelGroup, uint32_t channelNumber, uint32_t channelMux) +{ + adc16_channel_config_t adc16ChannelConfigStruct; + adc16ChannelConfigStruct.channelNumber = channelNumber; + adc16ChannelConfigStruct.enableInterruptOnConversionCompleted = false; + adc16ChannelConfigStruct.enableDifferentialConversion = false; + + ADC16_SetChannelMuxMode(ADC_BASE, (adc16_channel_mux_mode_t)channelMux); + ADC16_SetChannelConfig(ADC_BASE, channelGroup, &adc16ChannelConfigStruct); + while (0U == (kADC16_ChannelConversionDoneFlag & + ADC16_GetChannelStatusFlags(ADC_BASE, channelGroup))); + return ADC16_GetChannelConversionValue(ADC_BASE, channelGroup); +} diff --git a/source/hic_hal/freescale/kl27z/armcc/startup_MKL27Z4.s b/source/hic_hal/freescale/kl27z/armcc/startup_MKL27Z4.s index 06f59c896..ac06bcb11 100644 --- a/source/hic_hal/freescale/kl27z/armcc/startup_MKL27Z4.s +++ b/source/hic_hal/freescale/kl27z/armcc/startup_MKL27Z4.s @@ -167,6 +167,16 @@ __Vectors_Size EQU __Vectors_End - __Vectors ; Backdoor Comparison Key 5. <0x0-0xFF:2> ; Backdoor Comparison Key 6. <0x0-0xFF:2> ; Backdoor Comparison Key 7. <0x0-0xFF:2> +#if defined(MICROBIT_LOCK_BOOTLOADER) +BackDoorK0 EQU 0x4D ; 'M' +BackDoorK1 EQU 0x49 ; 'I' +BackDoorK2 EQU 0x43 ; 'C' +BackDoorK3 EQU 0x52 ; 'R' +BackDoorK4 EQU 0x4F ; 'O' +BackDoorK5 EQU 0x42 ; 'B' +BackDoorK6 EQU 0x49 ; 'I' +BackDoorK7 EQU 0x54 ; 'T' +#else BackDoorK0 EQU 0xFF BackDoorK1 EQU 0xFF BackDoorK2 EQU 0xFF @@ -175,41 +185,32 @@ BackDoorK4 EQU 0xFF BackDoorK5 EQU 0xFF BackDoorK6 EQU 0xFF BackDoorK7 EQU 0xFF +#endif ; ; Program flash protection bytes (FPROT) ; Each program flash region can be protected from program and erase operation by setting the associated PROT bit. ; Each bit protects a 1/32 region of the program flash memory. -; FPROT0 -; Program Flash Region Protect Register 0 +; FPROT3 +; Program Flash Region Protect Register 3 ; 1/32 - 8/32 region -; FPROT0.0 -; FPROT0.1 -; FPROT0.2 -; FPROT0.3 -; FPROT0.4 -; FPROT0.5 -; FPROT0.6 -; FPROT0.7 -nFPROT0 EQU 0x00 -FPROT0 EQU nFPROT0:EOR:0xFF -; -; FPROT1 -; Program Flash Region Protect Register 1 -; 9/32 - 16/32 region -; FPROT1.0 -; FPROT1.1 -; FPROT1.2 -; FPROT1.3 -; FPROT1.4 -; FPROT1.5 -; FPROT1.6 -; FPROT1.7 -nFPROT1 EQU 0x00 -FPROT1 EQU nFPROT1:EOR:0xFF +; FPROT3.0 +; FPROT3.1 +; FPROT3.2 +; FPROT3.3 +; FPROT3.4 +; FPROT3.5 +; FPROT3.6 +; FPROT3.7 +#if defined(MICROBIT_LOCK_BOOTLOADER) +nFPROT3 EQU 0x0F ; Enable protection of the first 32 kB of flash +#else +nFPROT3 EQU 0x00 +#endif +FPROT3 EQU nFPROT3:EOR:0xFF ; ; FPROT2 ; Program Flash Region Protect Register 2 -; 17/32 - 24/32 region +; 9/32 - 16/32 region ; FPROT2.0 ; FPROT2.1 ; FPROT2.2 @@ -221,43 +222,57 @@ FPROT1 EQU nFPROT1:EOR:0xFF nFPROT2 EQU 0x00 FPROT2 EQU nFPROT2:EOR:0xFF ; -; FPROT3 -; Program Flash Region Protect Register 3 +; FPROT1 +; Program Flash Region Protect Register 1 +; 17/32 - 24/32 region +; FPROT1.0 +; FPROT1.1 +; FPROT1.2 +; FPROT1.3 +; FPROT1.4 +; FPROT1.5 +; FPROT1.6 +; FPROT1.7 +nFPROT1 EQU 0x00 +FPROT1 EQU nFPROT1:EOR:0xFF +; +; FPROT0 +; Program Flash Region Protect Register 0 ; 25/32 - 32/32 region -; FPROT3.0 -; FPROT3.1 -; FPROT3.2 -; FPROT3.3 -; FPROT3.4 -; FPROT3.5 -; FPROT3.6 -; FPROT3.7 -nFPROT3 EQU 0x00 -FPROT3 EQU nFPROT3:EOR:0xFF +; FPROT0.0 +; FPROT0.1 +; FPROT0.2 +; FPROT0.3 +; FPROT0.4 +; FPROT0.5 +; FPROT0.6 +; FPROT0.7 +nFPROT0 EQU 0x00 +FPROT0 EQU nFPROT0:EOR:0xFF ; ; ; Flash nonvolatile option byte (FOPT) ; Allows the user to customize the operation of the MCU at boot time. ; LPBOOT0 ; <0=> Core and system clock divider (OUTDIV1) is 0x7 (divide by 8) when LPBOOT1=0 or 0x1 (divide by 2) when LPBOOT1=1. -; <1=> Core and system clock divider (OUTDIV1) is 0x3 (divide by 4) when LPBOOT1=0 or 0x0 (divide by 1) when LPBOOT1=1. +; * <1=> Core and system clock divider (OUTDIV1) is 0x3 (divide by 4) when LPBOOT1=0 or 0x0 (divide by 1) when LPBOOT1=1. ; BOOTPIN_OPT -; <0=> Force Boot from ROM if BOOTCFG0 asserted, where BOOTCFG0 is the boot config function which is muxed with NMI pin +; * <0=> Force Boot from ROM if BOOTCFG0 asserted, where BOOTCFG0 is the boot config function which is muxed with NMI pin ; <1=> Boot source configured by FOPT (BOOTSRC_SEL) bits ; NMI_DIS -; <0=> NMI interrupts are always blocked +; * <0=> NMI interrupts are always blocked ; <1=> NMI_b pin/interrupts reset default to enabled ; RESET_PIN_CFG ; <0=> RESET pin is disabled following a POR and cannot be enabled as reset function -; <1=> RESET_b pin is dedicated +; * <1=> RESET_b pin is dedicated ; LPBOOT1 ; <0=> Core and system clock divider (OUTDIV1) is 0x7 (divide by 8) when LPBOOT0=0 or 0x3 (divide by 4) when LPBOOT0=1. -; <1=> Core and system clock divider (OUTDIV1) is 0x1 (divide by 2) when LPBOOT0=0 or 0x0 (divide by 1) when LPBOOT0=1. +; * <1=> Core and system clock divider (OUTDIV1) is 0x1 (divide by 2) when LPBOOT0=0 or 0x0 (divide by 1) when LPBOOT0=1. ; FAST_INIT ; <0=> Slower initialization -; <1=> Fast Initialization +; * <1=> Fast Initialization ; BOOTSRC_SEL -; <0=> Boot from Flash +; * <0=> Boot from Flash ; <2=> Boot from ROM ; <3=> Boot from ROM ; Boot source selection @@ -267,21 +282,25 @@ FOPT EQU 0x39 ; WARNING: If SEC field is configured as "MCU security status is secure" and MEEN field is configured as "Mass erase is disabled", ; MCU's security status cannot be set back to unsecure state since Mass erase via the debugger is blocked !!! ; SEC -; <2=> MCU security status is unsecure +; * <2=> MCU security status is unsecure ; <3=> MCU security status is secure ; Flash Security ; FSLACC ; <2=> Freescale factory access denied -; <3=> Freescale factory access granted +; * <3=> Freescale factory access granted ; Freescale Failure Analysis Access Code ; MEEN ; <2=> Mass erase is disabled -; <3=> Mass erase is enabled +; * <3=> Mass erase is enabled ; KEYEN -; <2=> Backdoor key access enabled +; * <2=> Backdoor key access enabled ; <3=> Backdoor key access disabled ; Backdoor Key Security Enable +#if defined(MICROBIT_LOCK_BOOTLOADER) +FSEC EQU 0xBE +#else FSEC EQU 0xFE +#endif ; ; @@ -293,7 +312,7 @@ FSEC EQU 0xFE DCB BackDoorK0, BackDoorK1, BackDoorK2, BackDoorK3 DCB BackDoorK4, BackDoorK5, BackDoorK6, BackDoorK7 - DCB FPROT0 , FPROT1 , FPROT2 , FPROT3 + DCB FPROT3 , FPROT2 , FPROT1 , FPROT0 DCB FSEC , FOPT , 0xFF , 0xFF AREA |.text|, CODE, READONLY @@ -339,6 +358,19 @@ SysTick_Handler\ EXPORT SysTick_Handler [WEAK] B . ENDP +I2C0_IRQHandler\ + PROC + EXPORT I2C0_IRQHandler [WEAK] + LDR R0, =I2C0_DriverIRQHandler + BX R0 + ENDP + +I2C1_IRQHandler\ + PROC + EXPORT I2C1_IRQHandler [WEAK] + LDR R0, =I2C1_DriverIRQHandler + BX R0 + ENDP Default_Handler\ PROC EXPORT DMA0_IRQHandler [WEAK] @@ -349,8 +381,8 @@ Default_Handler\ EXPORT FTFA_IRQHandler [WEAK] EXPORT PMC_IRQHandler [WEAK] EXPORT LLWU_IRQHandler [WEAK] - EXPORT I2C0_IRQHandler [WEAK] - EXPORT I2C1_IRQHandler [WEAK] + EXPORT I2C0_DriverIRQHandler [WEAK] + EXPORT I2C1_DriverIRQHandler [WEAK] EXPORT SPI0_IRQHandler [WEAK] EXPORT SPI1_IRQHandler [WEAK] EXPORT LPUART0_IRQHandler [WEAK] @@ -382,8 +414,8 @@ Reserved20_IRQHandler FTFA_IRQHandler PMC_IRQHandler LLWU_IRQHandler -I2C0_IRQHandler -I2C1_IRQHandler +I2C0_DriverIRQHandler +I2C1_DriverIRQHandler SPI0_IRQHandler SPI1_IRQHandler LPUART0_IRQHandler diff --git a/source/hic_hal/freescale/kl27z/fsl_adc16.c b/source/hic_hal/freescale/kl27z/fsl_adc16.c new file mode 100644 index 000000000..db5b03c20 --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_adc16.c @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fsl_adc16.h" + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief Get instance number for ADC16 module. + * + * @param base ADC16 peripheral base address + */ +static uint32_t ADC16_GetInstance(ADC_Type *base); + +/******************************************************************************* + * Variables + ******************************************************************************/ +/*! @brief Pointers to ADC16 bases for each instance. */ +static ADC_Type *const s_adc16Bases[] = ADC_BASE_PTRS; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Pointers to ADC16 clocks for each instance. */ +static const clock_ip_name_t s_adc16Clocks[] = ADC16_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/******************************************************************************* + * Code + ******************************************************************************/ +static uint32_t ADC16_GetInstance(ADC_Type *base) +{ + uint32_t instance; + + /* Find the instance index from base address mappings. */ + for (instance = 0; instance < FSL_FEATURE_SOC_ADC16_COUNT; instance++) + { + if (s_adc16Bases[instance] == base) + { + break; + } + } + + assert(instance < FSL_FEATURE_SOC_ADC16_COUNT); + + return instance; +} + +void ADC16_Init(ADC_Type *base, const adc16_config_t *config) +{ + assert(NULL != config); + + uint32_t tmp32; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Enable the clock. */ + CLOCK_EnableClock(s_adc16Clocks[ADC16_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* ADCx_CFG1. */ + tmp32 = ADC_CFG1_ADICLK(config->clockSource) | ADC_CFG1_MODE(config->resolution); + if (kADC16_LongSampleDisabled != config->longSampleMode) + { + tmp32 |= ADC_CFG1_ADLSMP_MASK; + } + tmp32 |= ADC_CFG1_ADIV(config->clockDivider); + if (config->enableLowPower) + { + tmp32 |= ADC_CFG1_ADLPC_MASK; + } + base->CFG1 = tmp32; + + /* ADCx_CFG2. */ + tmp32 = base->CFG2 & ~(ADC_CFG2_ADACKEN_MASK | ADC_CFG2_ADHSC_MASK | ADC_CFG2_ADLSTS_MASK); + if (kADC16_LongSampleDisabled != config->longSampleMode) + { + tmp32 |= ADC_CFG2_ADLSTS(config->longSampleMode); + } + if (config->enableHighSpeed) + { + tmp32 |= ADC_CFG2_ADHSC_MASK; + } + if (config->enableAsynchronousClock) + { + tmp32 |= ADC_CFG2_ADACKEN_MASK; + } + base->CFG2 = tmp32; + + /* ADCx_SC2. */ + tmp32 = base->SC2 & ~(ADC_SC2_REFSEL_MASK); + tmp32 |= ADC_SC2_REFSEL(config->referenceVoltageSource); + base->SC2 = tmp32; + + /* ADCx_SC3. */ + if (config->enableContinuousConversion) + { + base->SC3 |= ADC_SC3_ADCO_MASK; + } + else + { + base->SC3 &= ~ADC_SC3_ADCO_MASK; + } +} + +void ADC16_Deinit(ADC_Type *base) +{ +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Disable the clock. */ + CLOCK_DisableClock(s_adc16Clocks[ADC16_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +void ADC16_GetDefaultConfig(adc16_config_t *config) +{ + assert(NULL != config); + + config->referenceVoltageSource = kADC16_ReferenceVoltageSourceVref; + config->clockSource = kADC16_ClockSourceAsynchronousClock; + config->enableAsynchronousClock = true; + config->clockDivider = kADC16_ClockDivider8; + config->resolution = kADC16_ResolutionSE12Bit; + config->longSampleMode = kADC16_LongSampleDisabled; + config->enableHighSpeed = false; + config->enableLowPower = false; + config->enableContinuousConversion = false; +} + +#if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION +status_t ADC16_DoAutoCalibration(ADC_Type *base) +{ + bool bHWTrigger = false; + volatile uint32_t tmp32; /* 'volatile' here is for the dummy read of ADCx_R[0] register. */ + status_t status = kStatus_Success; + + /* The calibration would be failed when in hardwar mode. + * Remember the hardware trigger state here and restore it later if the hardware trigger is enabled.*/ + if (0U != (ADC_SC2_ADTRG_MASK & base->SC2)) + { + bHWTrigger = true; + base->SC2 &= ~ADC_SC2_ADTRG_MASK; + } + + /* Clear the CALF and launch the calibration. */ + base->SC3 |= ADC_SC3_CAL_MASK | ADC_SC3_CALF_MASK; + while (0U == (kADC16_ChannelConversionDoneFlag & ADC16_GetChannelStatusFlags(base, 0U))) + { + /* Check the CALF when the calibration is active. */ + if (0U != (kADC16_CalibrationFailedFlag & ADC16_GetStatusFlags(base))) + { + status = kStatus_Fail; + break; + } + } + tmp32 = base->R[0]; /* Dummy read to clear COCO caused by calibration. */ + + /* Restore the hardware trigger setting if it was enabled before. */ + if (bHWTrigger) + { + base->SC2 |= ADC_SC2_ADTRG_MASK; + } + /* Check the CALF at the end of calibration. */ + if (0U != (kADC16_CalibrationFailedFlag & ADC16_GetStatusFlags(base))) + { + status = kStatus_Fail; + } + if (kStatus_Success != status) /* Check if the calibration process is succeed. */ + { + return status; + } + + /* Calculate the calibration values. */ + tmp32 = base->CLP0 + base->CLP1 + base->CLP2 + base->CLP3 + base->CLP4 + base->CLPS; + tmp32 = 0x8000U | (tmp32 >> 1U); + base->PG = tmp32; + +#if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE + tmp32 = base->CLM0 + base->CLM1 + base->CLM2 + base->CLM3 + base->CLM4 + base->CLMS; + tmp32 = 0x8000U | (tmp32 >> 1U); + base->MG = tmp32; +#endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */ + + return kStatus_Success; +} +#endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */ + +#if defined(FSL_FEATURE_ADC16_HAS_MUX_SELECT) && FSL_FEATURE_ADC16_HAS_MUX_SELECT +void ADC16_SetChannelMuxMode(ADC_Type *base, adc16_channel_mux_mode_t mode) +{ + if (kADC16_ChannelMuxA == mode) + { + base->CFG2 &= ~ADC_CFG2_MUXSEL_MASK; + } + else /* kADC16_ChannelMuxB. */ + { + base->CFG2 |= ADC_CFG2_MUXSEL_MASK; + } +} +#endif /* FSL_FEATURE_ADC16_HAS_MUX_SELECT */ + +void ADC16_SetHardwareCompareConfig(ADC_Type *base, const adc16_hardware_compare_config_t *config) +{ + uint32_t tmp32 = base->SC2 & ~(ADC_SC2_ACFE_MASK | ADC_SC2_ACFGT_MASK | ADC_SC2_ACREN_MASK); + + if (!config) /* Pass "NULL" to disable the feature. */ + { + base->SC2 = tmp32; + return; + } + /* Enable the feature. */ + tmp32 |= ADC_SC2_ACFE_MASK; + + /* Select the hardware compare working mode. */ + switch (config->hardwareCompareMode) + { + case kADC16_HardwareCompareMode0: + break; + case kADC16_HardwareCompareMode1: + tmp32 |= ADC_SC2_ACFGT_MASK; + break; + case kADC16_HardwareCompareMode2: + tmp32 |= ADC_SC2_ACREN_MASK; + break; + case kADC16_HardwareCompareMode3: + tmp32 |= ADC_SC2_ACFGT_MASK | ADC_SC2_ACREN_MASK; + break; + default: + break; + } + base->SC2 = tmp32; + + /* Load the compare values. */ + base->CV1 = ADC_CV1_CV(config->value1); + base->CV2 = ADC_CV2_CV(config->value2); +} + +#if defined(FSL_FEATURE_ADC16_HAS_HW_AVERAGE) && FSL_FEATURE_ADC16_HAS_HW_AVERAGE +void ADC16_SetHardwareAverage(ADC_Type *base, adc16_hardware_average_mode_t mode) +{ + uint32_t tmp32 = base->SC3 & ~(ADC_SC3_AVGE_MASK | ADC_SC3_AVGS_MASK); + + if (kADC16_HardwareAverageDisabled != mode) + { + tmp32 |= ADC_SC3_AVGE_MASK | ADC_SC3_AVGS(mode); + } + base->SC3 = tmp32; +} +#endif /* FSL_FEATURE_ADC16_HAS_HW_AVERAGE */ + +#if defined(FSL_FEATURE_ADC16_HAS_PGA) && FSL_FEATURE_ADC16_HAS_PGA +void ADC16_SetPGAConfig(ADC_Type *base, const adc16_pga_config_t *config) +{ + uint32_t tmp32; + + if (!config) /* Passing "NULL" is to disable the feature. */ + { + base->PGA = 0U; + return; + } + + /* Enable the PGA and set the gain value. */ + tmp32 = ADC_PGA_PGAEN_MASK | ADC_PGA_PGAG(config->pgaGain); + + /* Configure the misc features for PGA. */ + if (config->enableRunInNormalMode) + { + tmp32 |= ADC_PGA_PGALPb_MASK; + } +#if defined(FSL_FEATURE_ADC16_HAS_PGA_CHOPPING) && FSL_FEATURE_ADC16_HAS_PGA_CHOPPING + if (config->disablePgaChopping) + { + tmp32 |= ADC_PGA_PGACHPb_MASK; + } +#endif /* FSL_FEATURE_ADC16_HAS_PGA_CHOPPING */ +#if defined(FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT) && FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT + if (config->enableRunInOffsetMeasurement) + { + tmp32 |= ADC_PGA_PGAOFSM_MASK; + } +#endif /* FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT */ + base->PGA = tmp32; +} +#endif /* FSL_FEATURE_ADC16_HAS_PGA */ + +uint32_t ADC16_GetStatusFlags(ADC_Type *base) +{ + uint32_t ret = 0; + + if (0U != (base->SC2 & ADC_SC2_ADACT_MASK)) + { + ret |= kADC16_ActiveFlag; + } +#if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION + if (0U != (base->SC3 & ADC_SC3_CALF_MASK)) + { + ret |= kADC16_CalibrationFailedFlag; + } +#endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */ + return ret; +} + +void ADC16_ClearStatusFlags(ADC_Type *base, uint32_t mask) +{ +#if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION + if (0U != (mask & kADC16_CalibrationFailedFlag)) + { + base->SC3 |= ADC_SC3_CALF_MASK; + } +#endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */ +} + +void ADC16_SetChannelConfig(ADC_Type *base, uint32_t channelGroup, const adc16_channel_config_t *config) +{ + assert(channelGroup < ADC_SC1_COUNT); + assert(NULL != config); + + uint32_t sc1 = ADC_SC1_ADCH(config->channelNumber); /* Set the channel number. */ + +#if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE + /* Enable the differential conversion. */ + if (config->enableDifferentialConversion) + { + sc1 |= ADC_SC1_DIFF_MASK; + } +#endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */ + /* Enable the interrupt when the conversion is done. */ + if (config->enableInterruptOnConversionCompleted) + { + sc1 |= ADC_SC1_AIEN_MASK; + } + base->SC1[channelGroup] = sc1; +} + +uint32_t ADC16_GetChannelStatusFlags(ADC_Type *base, uint32_t channelGroup) +{ + assert(channelGroup < ADC_SC1_COUNT); + + uint32_t ret = 0U; + + if (0U != (base->SC1[channelGroup] & ADC_SC1_COCO_MASK)) + { + ret |= kADC16_ChannelConversionDoneFlag; + } + return ret; +} diff --git a/source/hic_hal/freescale/kl27z/fsl_adc16.h b/source/hic_hal/freescale/kl27z/fsl_adc16.h new file mode 100644 index 000000000..fa9f20ed7 --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_adc16.h @@ -0,0 +1,526 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FSL_ADC16_H_ +#define _FSL_ADC16_H_ + +#include "fsl_common.h" +#include "fsl_clock.h" + +/*! + * @addtogroup adc16 + * @{ + */ + + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +/*! @brief ADC16 driver version 2.0.0. */ +#define FSL_ADC16_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) +/*@}*/ + +/*! + * @brief Channel status flags. + */ +enum _adc16_channel_status_flags +{ + kADC16_ChannelConversionDoneFlag = ADC_SC1_COCO_MASK, /*!< Conversion done. */ +}; + +/*! + * @brief Converter status flags. + */ +enum _adc16_status_flags +{ + kADC16_ActiveFlag = ADC_SC2_ADACT_MASK, /*!< Converter is active. */ +#if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION + kADC16_CalibrationFailedFlag = ADC_SC3_CALF_MASK, /*!< Calibration is failed. */ +#endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */ +}; + +#if defined(FSL_FEATURE_ADC16_HAS_MUX_SELECT) && FSL_FEATURE_ADC16_HAS_MUX_SELECT +/*! + * @brief Channel multiplexer mode for each channel. + * + * For some ADC16 channels, there are two pin selections in channel multiplexer. For example, ADC0_SE4a and ADC0_SE4b + * are the different channels that share the same channel number. + */ +typedef enum _adc_channel_mux_mode +{ + kADC16_ChannelMuxA = 0U, /*!< For channel with channel mux a. */ + kADC16_ChannelMuxB = 1U, /*!< For channel with channel mux b. */ +} adc16_channel_mux_mode_t; +#endif /* FSL_FEATURE_ADC16_HAS_MUX_SELECT */ + +/*! + * @brief Clock divider for the converter. + */ +typedef enum _adc16_clock_divider +{ + kADC16_ClockDivider1 = 0U, /*!< For divider 1 from the input clock to the module. */ + kADC16_ClockDivider2 = 1U, /*!< For divider 2 from the input clock to the module. */ + kADC16_ClockDivider4 = 2U, /*!< For divider 4 from the input clock to the module. */ + kADC16_ClockDivider8 = 3U, /*!< For divider 8 from the input clock to the module. */ +} adc16_clock_divider_t; + +/*! + *@brief Converter's resolution. + */ +typedef enum _adc16_resolution +{ + /* This group of enumeration is for internal use which is related to register setting. */ + kADC16_Resolution8or9Bit = 0U, /*!< Single End 8-bit or Differential Sample 9-bit. */ + kADC16_Resolution12or13Bit = 1U, /*!< Single End 12-bit or Differential Sample 13-bit. */ + kADC16_Resolution10or11Bit = 2U, /*!< Single End 10-bit or Differential Sample 11-bit. */ + + /* This group of enumeration is for a public user. */ + kADC16_ResolutionSE8Bit = kADC16_Resolution8or9Bit, /*!< Single End 8-bit. */ + kADC16_ResolutionSE12Bit = kADC16_Resolution12or13Bit, /*!< Single End 12-bit. */ + kADC16_ResolutionSE10Bit = kADC16_Resolution10or11Bit, /*!< Single End 10-bit. */ +#if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE + kADC16_ResolutionDF9Bit = kADC16_Resolution8or9Bit, /*!< Differential Sample 9-bit. */ + kADC16_ResolutionDF13Bit = kADC16_Resolution12or13Bit, /*!< Differential Sample 13-bit. */ + kADC16_ResolutionDF11Bit = kADC16_Resolution10or11Bit, /*!< Differential Sample 11-bit. */ +#endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */ + +#if defined(FSL_FEATURE_ADC16_MAX_RESOLUTION) && (FSL_FEATURE_ADC16_MAX_RESOLUTION >= 16U) + /* 16-bit is supported by default. */ + kADC16_Resolution16Bit = 3U, /*!< Single End 16-bit or Differential Sample 16-bit. */ + kADC16_ResolutionSE16Bit = kADC16_Resolution16Bit, /*!< Single End 16-bit. */ +#if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE + kADC16_ResolutionDF16Bit = kADC16_Resolution16Bit, /*!< Differential Sample 16-bit. */ +#endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */ +#endif /* FSL_FEATURE_ADC16_MAX_RESOLUTION >= 16U */ +} adc16_resolution_t; + +/*! + * @brief Clock source. + */ +typedef enum _adc16_clock_source +{ + kADC16_ClockSourceAlt0 = 0U, /*!< Selection 0 of the clock source. */ + kADC16_ClockSourceAlt1 = 1U, /*!< Selection 1 of the clock source. */ + kADC16_ClockSourceAlt2 = 2U, /*!< Selection 2 of the clock source. */ + kADC16_ClockSourceAlt3 = 3U, /*!< Selection 3 of the clock source. */ + + /* Chip defined clock source */ + kADC16_ClockSourceAsynchronousClock = kADC16_ClockSourceAlt3, /*!< Using internal asynchronous clock. */ +} adc16_clock_source_t; + +/*! + * @brief Long sample mode. + */ +typedef enum _adc16_long_sample_mode +{ + kADC16_LongSampleCycle24 = 0U, /*!< 20 extra ADCK cycles, 24 ADCK cycles total. */ + kADC16_LongSampleCycle16 = 1U, /*!< 12 extra ADCK cycles, 16 ADCK cycles total. */ + kADC16_LongSampleCycle10 = 2U, /*!< 6 extra ADCK cycles, 10 ADCK cycles total. */ + kADC16_LongSampleCycle6 = 3U, /*!< 2 extra ADCK cycles, 6 ADCK cycles total. */ + kADC16_LongSampleDisabled = 4U, /*!< Disable the long sample feature. */ +} adc16_long_sample_mode_t; + +/*! + * @brief Reference voltage source. + */ +typedef enum _adc16_reference_voltage_source +{ + kADC16_ReferenceVoltageSourceVref = 0U, /*!< For external pins pair of VrefH and VrefL. */ + kADC16_ReferenceVoltageSourceValt = 1U, /*!< For alternate reference pair of ValtH and ValtL. */ +} adc16_reference_voltage_source_t; + +#if defined(FSL_FEATURE_ADC16_HAS_HW_AVERAGE) && FSL_FEATURE_ADC16_HAS_HW_AVERAGE +/*! + * @brief Hardware average mode. + */ +typedef enum _adc16_hardware_average_mode +{ + kADC16_HardwareAverageCount4 = 0U, /*!< For hardware average with 4 samples. */ + kADC16_HardwareAverageCount8 = 1U, /*!< For hardware average with 8 samples. */ + kADC16_HardwareAverageCount16 = 2U, /*!< For hardware average with 16 samples. */ + kADC16_HardwareAverageCount32 = 3U, /*!< For hardware average with 32 samples. */ + kADC16_HardwareAverageDisabled = 4U, /*!< Disable the hardware average feature.*/ +} adc16_hardware_average_mode_t; +#endif /* FSL_FEATURE_ADC16_HAS_HW_AVERAGE */ + +/*! + * @brief Hardware compare mode. + */ +typedef enum _adc16_hardware_compare_mode +{ + kADC16_HardwareCompareMode0 = 0U, /*!< x < value1. */ + kADC16_HardwareCompareMode1 = 1U, /*!< x > value1. */ + kADC16_HardwareCompareMode2 = 2U, /*!< if value1 <= value2, then x < value1 || x > value2; + else, value1 > x > value2. */ + kADC16_HardwareCompareMode3 = 3U, /*!< if value1 <= value2, then value1 <= x <= value2; + else x >= value1 || x <= value2. */ +} adc16_hardware_compare_mode_t; + +#if defined(FSL_FEATURE_ADC16_HAS_PGA) && FSL_FEATURE_ADC16_HAS_PGA +/*! + * @brief PGA's Gain mode. + */ +typedef enum _adc16_pga_gain +{ + kADC16_PGAGainValueOf1 = 0U, /*!< For amplifier gain of 1. */ + kADC16_PGAGainValueOf2 = 1U, /*!< For amplifier gain of 2. */ + kADC16_PGAGainValueOf4 = 2U, /*!< For amplifier gain of 4. */ + kADC16_PGAGainValueOf8 = 3U, /*!< For amplifier gain of 8. */ + kADC16_PGAGainValueOf16 = 4U, /*!< For amplifier gain of 16. */ + kADC16_PGAGainValueOf32 = 5U, /*!< For amplifier gain of 32. */ + kADC16_PGAGainValueOf64 = 6U, /*!< For amplifier gain of 64. */ +} adc16_pga_gain_t; +#endif /* FSL_FEATURE_ADC16_HAS_PGA */ + +/*! + * @brief ADC16 converter configuration. + */ +typedef struct _adc16_config +{ + adc16_reference_voltage_source_t referenceVoltageSource; /*!< Select the reference voltage source. */ + adc16_clock_source_t clockSource; /*!< Select the input clock source to converter. */ + bool enableAsynchronousClock; /*!< Enable the asynchronous clock output. */ + adc16_clock_divider_t clockDivider; /*!< Select the divider of input clock source. */ + adc16_resolution_t resolution; /*!< Select the sample resolution mode. */ + adc16_long_sample_mode_t longSampleMode; /*!< Select the long sample mode. */ + bool enableHighSpeed; /*!< Enable the high-speed mode. */ + bool enableLowPower; /*!< Enable low power. */ + bool enableContinuousConversion; /*!< Enable continuous conversion mode. */ +} adc16_config_t; + +/*! + * @brief ADC16 Hardware comparison configuration. + */ +typedef struct _adc16_hardware_compare_config +{ + adc16_hardware_compare_mode_t hardwareCompareMode; /*!< Select the hardware compare mode. + See "adc16_hardware_compare_mode_t". */ + int16_t value1; /*!< Setting value1 for hardware compare mode. */ + int16_t value2; /*!< Setting value2 for hardware compare mode. */ +} adc16_hardware_compare_config_t; + +/*! + * @brief ADC16 channel conversion configuration. + */ +typedef struct _adc16_channel_config +{ + uint32_t channelNumber; /*!< Setting the conversion channel number. The available range is 0-31. + See channel connection information for each chip in Reference + Manual document. */ + bool enableInterruptOnConversionCompleted; /*!< Generate an interrupt request once the conversion is completed. */ +#if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE + bool enableDifferentialConversion; /*!< Using Differential sample mode. */ +#endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */ +} adc16_channel_config_t; + +#if defined(FSL_FEATURE_ADC16_HAS_PGA) && FSL_FEATURE_ADC16_HAS_PGA +/*! + * @brief ADC16 programmable gain amplifier configuration. + */ +typedef struct _adc16_pga_config +{ + adc16_pga_gain_t pgaGain; /*!< Setting PGA gain. */ + bool enableRunInNormalMode; /*!< Enable PGA working in normal mode, or low power mode by default. */ +#if defined(FSL_FEATURE_ADC16_HAS_PGA_CHOPPING) && FSL_FEATURE_ADC16_HAS_PGA_CHOPPING + bool disablePgaChopping; /*!< Disable the PGA chopping function. + The PGA employs chopping to remove/reduce offset and 1/f noise and offers + an offset measurement configuration that aids the offset calibration. */ +#endif /* FSL_FEATURE_ADC16_HAS_PGA_CHOPPING */ +#if defined(FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT) && FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT + bool enableRunInOffsetMeasurement; /*!< Enable the PGA working in offset measurement mode. + When this feature is enabled, the PGA disconnects itself from the external + inputs and auto-configures into offset measurement mode. With this field + set, run the ADC in the recommended settings and enable the maximum hardware + averaging to get the PGA offset number. The output is the + (PGA offset * (64+1)) for the given PGA setting. */ +#endif /* FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT */ +} adc16_pga_config_t; +#endif /* FSL_FEATURE_ADC16_HAS_PGA */ + +#if defined(__cplusplus) +extern "C" { +#endif + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @name Initialization + * @{ + */ + +/*! + * @brief Initializes the ADC16 module. + * + * @param base ADC16 peripheral base address. + * @param config Pointer to configuration structure. See "adc16_config_t". + */ +void ADC16_Init(ADC_Type *base, const adc16_config_t *config); + +/*! + * @brief De-initializes the ADC16 module. + * + * @param base ADC16 peripheral base address. + */ +void ADC16_Deinit(ADC_Type *base); + +/*! + * @brief Gets an available pre-defined settings for the converter's configuration. + * + * This function initializes the converter configuration structure with available settings. The default values are as follows. + * @code + * config->referenceVoltageSource = kADC16_ReferenceVoltageSourceVref; + * config->clockSource = kADC16_ClockSourceAsynchronousClock; + * config->enableAsynchronousClock = true; + * config->clockDivider = kADC16_ClockDivider8; + * config->resolution = kADC16_ResolutionSE12Bit; + * config->longSampleMode = kADC16_LongSampleDisabled; + * config->enableHighSpeed = false; + * config->enableLowPower = false; + * config->enableContinuousConversion = false; + * @endcode + * @param config Pointer to the configuration structure. + */ +void ADC16_GetDefaultConfig(adc16_config_t *config); + +#if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION +/*! + * @brief Automates the hardware calibration. + * + * This auto calibration helps to adjust the plus/minus side gain automatically. + * Execute the calibration before using the converter. Note that the hardware trigger should be used + * during the calibration. + * + * @param base ADC16 peripheral base address. + * + * @return Execution status. + * @retval kStatus_Success Calibration is done successfully. + * @retval kStatus_Fail Calibration has failed. + */ +status_t ADC16_DoAutoCalibration(ADC_Type *base); +#endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */ + +#if defined(FSL_FEATURE_ADC16_HAS_OFFSET_CORRECTION) && FSL_FEATURE_ADC16_HAS_OFFSET_CORRECTION +/*! + * @brief Sets the offset value for the conversion result. + * + * This offset value takes effect on the conversion result. If the offset value is not zero, the reading result + * is subtracted by it. Note, the hardware calibration fills the offset value automatically. + * + * @param base ADC16 peripheral base address. + * @param value Setting offset value. + */ +static inline void ADC16_SetOffsetValue(ADC_Type *base, int16_t value) +{ + base->OFS = (uint32_t)(value); +} +#endif /* FSL_FEATURE_ADC16_HAS_OFFSET_CORRECTION */ + +/* @} */ + +/*! + * @name Advanced Features + * @{ + */ + +#if defined(FSL_FEATURE_ADC16_HAS_DMA) && FSL_FEATURE_ADC16_HAS_DMA +/*! + * @brief Enables generating the DMA trigger when the conversion is complete. + * + * @param base ADC16 peripheral base address. + * @param enable Switcher of the DMA feature. "true" means enabled, "false" means not enabled. + */ +static inline void ADC16_EnableDMA(ADC_Type *base, bool enable) +{ + if (enable) + { + base->SC2 |= ADC_SC2_DMAEN_MASK; + } + else + { + base->SC2 &= ~ADC_SC2_DMAEN_MASK; + } +} +#endif /* FSL_FEATURE_ADC16_HAS_DMA */ + +/*! + * @brief Enables the hardware trigger mode. + * + * @param base ADC16 peripheral base address. + * @param enable Switcher of the hardware trigger feature. "true" means enabled, "false" means not enabled. + */ +static inline void ADC16_EnableHardwareTrigger(ADC_Type *base, bool enable) +{ + if (enable) + { + base->SC2 |= ADC_SC2_ADTRG_MASK; + } + else + { + base->SC2 &= ~ADC_SC2_ADTRG_MASK; + } +} + +#if defined(FSL_FEATURE_ADC16_HAS_MUX_SELECT) && FSL_FEATURE_ADC16_HAS_MUX_SELECT +/*! + * @brief Sets the channel mux mode. + * + * Some sample pins share the same channel index. The channel mux mode decides which pin is used for an + * indicated channel. + * + * @param base ADC16 peripheral base address. + * @param mode Setting channel mux mode. See "adc16_channel_mux_mode_t". + */ +void ADC16_SetChannelMuxMode(ADC_Type *base, adc16_channel_mux_mode_t mode); +#endif /* FSL_FEATURE_ADC16_HAS_MUX_SELECT */ + +/*! + * @brief Configures the hardware compare mode. + * + * The hardware compare mode provides a way to process the conversion result automatically by using hardware. Only the result + * in the compare range is available. To compare the range, see "adc16_hardware_compare_mode_t" or the appopriate reference + * manual for more information. + * + * @param base ADC16 peripheral base address. + * @param config Pointer to the "adc16_hardware_compare_config_t" structure. Passing "NULL" disables the feature. + */ +void ADC16_SetHardwareCompareConfig(ADC_Type *base, const adc16_hardware_compare_config_t *config); + +#if defined(FSL_FEATURE_ADC16_HAS_HW_AVERAGE) && FSL_FEATURE_ADC16_HAS_HW_AVERAGE +/*! + * @brief Sets the hardware average mode. + * + * The hardware average mode provides a way to process the conversion result automatically by using hardware. The multiple + * conversion results are accumulated and averaged internally making them easier to read. + * + * @param base ADC16 peripheral base address. + * @param mode Setting the hardware average mode. See "adc16_hardware_average_mode_t". + */ +void ADC16_SetHardwareAverage(ADC_Type *base, adc16_hardware_average_mode_t mode); +#endif /* FSL_FEATURE_ADC16_HAS_HW_AVERAGE */ + +#if defined(FSL_FEATURE_ADC16_HAS_PGA) && FSL_FEATURE_ADC16_HAS_PGA +/*! + * @brief Configures the PGA for the converter's front end. + * + * @param base ADC16 peripheral base address. + * @param config Pointer to the "adc16_pga_config_t" structure. Passing "NULL" disables the feature. + */ +void ADC16_SetPGAConfig(ADC_Type *base, const adc16_pga_config_t *config); +#endif /* FSL_FEATURE_ADC16_HAS_PGA */ + +/*! + * @brief Gets the status flags of the converter. + * + * @param base ADC16 peripheral base address. + * + * @return Flags' mask if indicated flags are asserted. See "_adc16_status_flags". + */ +uint32_t ADC16_GetStatusFlags(ADC_Type *base); + +/*! + * @brief Clears the status flags of the converter. + * + * @param base ADC16 peripheral base address. + * @param mask Mask value for the cleared flags. See "_adc16_status_flags". + */ +void ADC16_ClearStatusFlags(ADC_Type *base, uint32_t mask); + +/* @} */ + +/*! + * @name Conversion Channel + * @{ + */ + +/*! + * @brief Configures the conversion channel. + * + * This operation triggers the conversion when in software trigger mode. When in hardware trigger mode, this API + * configures the channel while the external trigger source helps to trigger the conversion. + * + * Note that the "Channel Group" has a detailed description. + * To allow sequential conversions of the ADC to be triggered by internal peripherals, the ADC has more than one + * group of status and control registers, one for each conversion. The channel group parameter indicates which group of + * registers are used, for example, channel group 0 is for Group A registers and channel group 1 is for Group B registers. The + * channel groups are used in a "ping-pong" approach to control the ADC operation. At any point, only one of + * the channel groups is actively controlling ADC conversions. The channel group 0 is used for both software and hardware + * trigger modes. Channel group 1 and greater indicates multiple channel group registers for + * use only in hardware trigger mode. See the chip configuration information in the appropriate MCU reference manual for the + * number of SC1n registers (channel groups) specific to this device. Channel group 1 or greater are not used + * for software trigger operation. Therefore, writing to these channel groups does not initiate a new conversion. + * Updating the channel group 0 while a different channel group is actively controlling a conversion is allowed and + * vice versa. Writing any of the channel group registers while that specific channel group is actively controlling a + * conversion aborts the current conversion. + * + * @param base ADC16 peripheral base address. + * @param channelGroup Channel group index. + * @param config Pointer to the "adc16_channel_config_t" structure for the conversion channel. + */ +void ADC16_SetChannelConfig(ADC_Type *base, uint32_t channelGroup, const adc16_channel_config_t *config); + +/*! + * @brief Gets the conversion value. + * + * @param base ADC16 peripheral base address. + * @param channelGroup Channel group index. + * + * @return Conversion value. + */ +static inline uint32_t ADC16_GetChannelConversionValue(ADC_Type *base, uint32_t channelGroup) +{ + assert(channelGroup < ADC_R_COUNT); + + return base->R[channelGroup]; +} + +/*! + * @brief Gets the status flags of channel. + * + * @param base ADC16 peripheral base address. + * @param channelGroup Channel group index. + * + * @return Flags' mask if indicated flags are asserted. See "_adc16_channel_status_flags". + */ +uint32_t ADC16_GetChannelStatusFlags(ADC_Type *base, uint32_t channelGroup); + +/* @} */ + +#if defined(__cplusplus) +} +#endif +/*! + * @} + */ +#endif /* _FSL_ADC16_H_ */ diff --git a/source/hic_hal/freescale/kl27z/fsl_flexio.c b/source/hic_hal/freescale/kl27z/fsl_flexio.c new file mode 100644 index 000000000..9cb5046e0 --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_flexio.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_flexio.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.flexio" +#endif + +/*< @brief user configurable flexio handle count. */ +#define FLEXIO_HANDLE_COUNT 2 + +/******************************************************************************* + * Variables + ******************************************************************************/ +/*! @brief Pointers to flexio bases for each instance. */ +FLEXIO_Type *const s_flexioBases[] = FLEXIO_BASE_PTRS; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Pointers to flexio clocks for each instance. */ +const clock_ip_name_t s_flexioClocks[] = FLEXIO_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/*< @brief pointer to array of FLEXIO handle. */ +static void *s_flexioHandle[FLEXIO_HANDLE_COUNT]; + +/*< @brief pointer to array of FLEXIO IP types. */ +static void *s_flexioType[FLEXIO_HANDLE_COUNT]; + +/*< @brief pointer to array of FLEXIO Isr. */ +static flexio_isr_t s_flexioIsr[FLEXIO_HANDLE_COUNT]; + +/******************************************************************************* + * Codes + ******************************************************************************/ + +/*! + * brief Get instance number for FLEXIO module. + * + * param base FLEXIO peripheral base address. + */ +uint32_t FLEXIO_GetInstance(FLEXIO_Type *base) +{ + uint32_t instance; + + /* Find the instance index from base address mappings. */ + for (instance = 0; instance < ARRAY_SIZE(s_flexioBases); instance++) + { + if (s_flexioBases[instance] == base) + { + break; + } + } + + assert(instance < ARRAY_SIZE(s_flexioBases)); + + return instance; +} + +/*! + * brief Configures the FlexIO with a FlexIO configuration. The configuration structure + * can be filled by the user or be set with default values by FLEXIO_GetDefaultConfig(). + * + * Example + code + flexio_config_t config = { + .enableFlexio = true, + .enableInDoze = false, + .enableInDebug = true, + .enableFastAccess = false + }; + FLEXIO_Configure(base, &config); + endcode + * + * param base FlexIO peripheral base address + * param userConfig pointer to flexio_config_t structure +*/ +void FLEXIO_Init(FLEXIO_Type *base, const flexio_config_t *userConfig) +{ + uint32_t ctrlReg = 0; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + CLOCK_EnableClock(s_flexioClocks[FLEXIO_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + FLEXIO_Reset(base); + + ctrlReg = base->CTRL; + ctrlReg &= ~(FLEXIO_CTRL_DOZEN_MASK | FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK); + ctrlReg |= (FLEXIO_CTRL_DBGE(userConfig->enableInDebug) | FLEXIO_CTRL_FASTACC(userConfig->enableFastAccess) | + FLEXIO_CTRL_FLEXEN(userConfig->enableFlexio)); + if (!userConfig->enableInDoze) + { + ctrlReg |= FLEXIO_CTRL_DOZEN_MASK; + } + + base->CTRL = ctrlReg; +} + +/*! + * brief Gates the FlexIO clock. Call this API to stop the FlexIO clock. + * + * note After calling this API, call the FLEXO_Init to use the FlexIO module. + * + * param base FlexIO peripheral base address + */ +void FLEXIO_Deinit(FLEXIO_Type *base) +{ + FLEXIO_Enable(base, false); +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + CLOCK_DisableClock(s_flexioClocks[FLEXIO_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +/*! + * brief Gets the default configuration to configure the FlexIO module. The configuration + * can used directly to call the FLEXIO_Configure(). + * + * Example: + code + flexio_config_t config; + FLEXIO_GetDefaultConfig(&config); + endcode + * + * param userConfig pointer to flexio_config_t structure +*/ +void FLEXIO_GetDefaultConfig(flexio_config_t *userConfig) +{ + assert(userConfig); + + /* Initializes the configure structure to zero. */ + memset(userConfig, 0, sizeof(*userConfig)); + + userConfig->enableFlexio = true; + userConfig->enableInDoze = false; + userConfig->enableInDebug = true; + userConfig->enableFastAccess = false; +} + +/*! + * brief Resets the FlexIO module. + * + * param base FlexIO peripheral base address + */ +void FLEXIO_Reset(FLEXIO_Type *base) +{ + /*do software reset, software reset operation affect all other FLEXIO registers except CTRL*/ + base->CTRL |= FLEXIO_CTRL_SWRST_MASK; + base->CTRL = 0; +} + +/*! + * brief Gets the shifter buffer address for the DMA transfer usage. + * + * param base FlexIO peripheral base address + * param type Shifter type of flexio_shifter_buffer_type_t + * param index Shifter index + * return Corresponding shifter buffer index + */ +uint32_t FLEXIO_GetShifterBufferAddress(FLEXIO_Type *base, flexio_shifter_buffer_type_t type, uint8_t index) +{ + assert(index < FLEXIO_SHIFTBUF_COUNT); + + uint32_t address = 0; + + switch (type) + { + case kFLEXIO_ShifterBuffer: + address = (uint32_t) & (base->SHIFTBUF[index]); + break; + + case kFLEXIO_ShifterBufferBitSwapped: + address = (uint32_t) & (base->SHIFTBUFBIS[index]); + break; + + case kFLEXIO_ShifterBufferByteSwapped: + address = (uint32_t) & (base->SHIFTBUFBYS[index]); + break; + + case kFLEXIO_ShifterBufferBitByteSwapped: + address = (uint32_t) & (base->SHIFTBUFBBS[index]); + break; + +#if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_BYTE_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_BYTE_SWAP + case kFLEXIO_ShifterBufferNibbleByteSwapped: + address = (uint32_t) & (base->SHIFTBUFNBS[index]); + break; + +#endif +#if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_HALF_WORD_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_HALF_WORD_SWAP + case kFLEXIO_ShifterBufferHalfWordSwapped: + address = (uint32_t) & (base->SHIFTBUFHWS[index]); + break; + +#endif +#if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_SWAP + case kFLEXIO_ShifterBufferNibbleSwapped: + address = (uint32_t) & (base->SHIFTBUFNIS[index]); + break; + +#endif + default: + break; + } + return address; +} + +/*! + * brief Configures the shifter with the shifter configuration. The configuration structure + * covers both the SHIFTCTL and SHIFTCFG registers. To configure the shifter to the proper + * mode, select which timer controls the shifter to shift, whether to generate start bit/stop + * bit, and the polarity of start bit and stop bit. + * + * Example + code + flexio_shifter_config_t config = { + .timerSelect = 0, + .timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive, + .pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection, + .pinPolarity = kFLEXIO_PinActiveLow, + .shifterMode = kFLEXIO_ShifterModeTransmit, + .inputSource = kFLEXIO_ShifterInputFromPin, + .shifterStop = kFLEXIO_ShifterStopBitHigh, + .shifterStart = kFLEXIO_ShifterStartBitLow + }; + FLEXIO_SetShifterConfig(base, &config); + endcode + * + * param base FlexIO peripheral base address + * param index Shifter index + * param shifterConfig Pointer to flexio_shifter_config_t structure +*/ +void FLEXIO_SetShifterConfig(FLEXIO_Type *base, uint8_t index, const flexio_shifter_config_t *shifterConfig) +{ + base->SHIFTCFG[index] = FLEXIO_SHIFTCFG_INSRC(shifterConfig->inputSource) +#if FSL_FEATURE_FLEXIO_HAS_PARALLEL_WIDTH + | FLEXIO_SHIFTCFG_PWIDTH(shifterConfig->parallelWidth) +#endif /* FSL_FEATURE_FLEXIO_HAS_PARALLEL_WIDTH */ + | FLEXIO_SHIFTCFG_SSTOP(shifterConfig->shifterStop) | + FLEXIO_SHIFTCFG_SSTART(shifterConfig->shifterStart); + + base->SHIFTCTL[index] = + FLEXIO_SHIFTCTL_TIMSEL(shifterConfig->timerSelect) | FLEXIO_SHIFTCTL_TIMPOL(shifterConfig->timerPolarity) | + FLEXIO_SHIFTCTL_PINCFG(shifterConfig->pinConfig) | FLEXIO_SHIFTCTL_PINSEL(shifterConfig->pinSelect) | + FLEXIO_SHIFTCTL_PINPOL(shifterConfig->pinPolarity) | FLEXIO_SHIFTCTL_SMOD(shifterConfig->shifterMode); +} + +/*! + * brief Configures the timer with the timer configuration. The configuration structure + * covers both the TIMCTL and TIMCFG registers. To configure the timer to the proper + * mode, select trigger source for timer and the timer pin output and the timing for timer. + * + * Example + code + flexio_timer_config_t config = { + .triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(0), + .triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow, + .triggerSource = kFLEXIO_TimerTriggerSourceInternal, + .pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection, + .pinSelect = 0, + .pinPolarity = kFLEXIO_PinActiveHigh, + .timerMode = kFLEXIO_TimerModeDual8BitBaudBit, + .timerOutput = kFLEXIO_TimerOutputZeroNotAffectedByReset, + .timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput, + .timerReset = kFLEXIO_TimerResetOnTimerPinEqualToTimerOutput, + .timerDisable = kFLEXIO_TimerDisableOnTimerCompare, + .timerEnable = kFLEXIO_TimerEnableOnTriggerHigh, + .timerStop = kFLEXIO_TimerStopBitEnableOnTimerDisable, + .timerStart = kFLEXIO_TimerStartBitEnabled + }; + FLEXIO_SetTimerConfig(base, &config); + endcode + * + * param base FlexIO peripheral base address + * param index Timer index + * param timerConfig Pointer to the flexio_timer_config_t structure +*/ +void FLEXIO_SetTimerConfig(FLEXIO_Type *base, uint8_t index, const flexio_timer_config_t *timerConfig) +{ + base->TIMCFG[index] = + FLEXIO_TIMCFG_TIMOUT(timerConfig->timerOutput) | FLEXIO_TIMCFG_TIMDEC(timerConfig->timerDecrement) | + FLEXIO_TIMCFG_TIMRST(timerConfig->timerReset) | FLEXIO_TIMCFG_TIMDIS(timerConfig->timerDisable) | + FLEXIO_TIMCFG_TIMENA(timerConfig->timerEnable) | FLEXIO_TIMCFG_TSTOP(timerConfig->timerStop) | + FLEXIO_TIMCFG_TSTART(timerConfig->timerStart); + + base->TIMCMP[index] = FLEXIO_TIMCMP_CMP(timerConfig->timerCompare); + + base->TIMCTL[index] = FLEXIO_TIMCTL_TRGSEL(timerConfig->triggerSelect) | + FLEXIO_TIMCTL_TRGPOL(timerConfig->triggerPolarity) | + FLEXIO_TIMCTL_TRGSRC(timerConfig->triggerSource) | + FLEXIO_TIMCTL_PINCFG(timerConfig->pinConfig) | FLEXIO_TIMCTL_PINSEL(timerConfig->pinSelect) | + FLEXIO_TIMCTL_PINPOL(timerConfig->pinPolarity) | FLEXIO_TIMCTL_TIMOD(timerConfig->timerMode); +} + +/*! + * brief Registers the handle and the interrupt handler for the FlexIO-simulated peripheral. + * + * param base Pointer to the FlexIO simulated peripheral type. + * param handle Pointer to the handler for FlexIO simulated peripheral. + * param isr FlexIO simulated peripheral interrupt handler. + * retval kStatus_Success Successfully create the handle. + * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range. + */ +status_t FLEXIO_RegisterHandleIRQ(void *base, void *handle, flexio_isr_t isr) +{ + assert(base); + assert(handle); + assert(isr); + + uint8_t index = 0; + + /* Find the an empty handle pointer to store the handle. */ + for (index = 0; index < FLEXIO_HANDLE_COUNT; index++) + { + if (s_flexioHandle[index] == NULL) + { + /* Register FLEXIO simulated driver base, handle and isr. */ + s_flexioType[index] = base; + s_flexioHandle[index] = handle; + s_flexioIsr[index] = isr; + break; + } + } + + if (index == FLEXIO_HANDLE_COUNT) + { + return kStatus_OutOfRange; + } + else + { + return kStatus_Success; + } +} + +/*! + * brief Unregisters the handle and the interrupt handler for the FlexIO-simulated peripheral. + * + * param base Pointer to the FlexIO simulated peripheral type. + * retval kStatus_Success Successfully create the handle. + * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range. + */ +status_t FLEXIO_UnregisterHandleIRQ(void *base) +{ + assert(base); + + uint8_t index = 0; + + /* Find the index from base address mappings. */ + for (index = 0; index < FLEXIO_HANDLE_COUNT; index++) + { + if (s_flexioType[index] == base) + { + /* Unregister FLEXIO simulated driver handle and isr. */ + s_flexioType[index] = NULL; + s_flexioHandle[index] = NULL; + s_flexioIsr[index] = NULL; + break; + } + } + + if (index == FLEXIO_HANDLE_COUNT) + { + return kStatus_OutOfRange; + } + else + { + return kStatus_Success; + } +} + +void FLEXIO_CommonIRQHandler(void) +{ + uint8_t index; + + for (index = 0; index < FLEXIO_HANDLE_COUNT; index++) + { + if (s_flexioHandle[index]) + { + s_flexioIsr[index](s_flexioType[index], s_flexioHandle[index]); + } + } +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +void FLEXIO_DriverIRQHandler(void) +{ + FLEXIO_CommonIRQHandler(); +} + +void FLEXIO0_DriverIRQHandler(void) +{ + FLEXIO_CommonIRQHandler(); +} + +void FLEXIO1_DriverIRQHandler(void) +{ + FLEXIO_CommonIRQHandler(); +} + +void UART2_FLEXIO_DriverIRQHandler(void) +{ + FLEXIO_CommonIRQHandler(); +} + +void FLEXIO2_DriverIRQHandler(void) +{ + FLEXIO_CommonIRQHandler(); +} + +void FLEXIO3_DriverIRQHandler(void) +{ + FLEXIO_CommonIRQHandler(); +} diff --git a/source/hic_hal/freescale/kl27z/fsl_flexio.h b/source/hic_hal/freescale/kl27z/fsl_flexio.h new file mode 100644 index 000000000..6a984040d --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_flexio.h @@ -0,0 +1,701 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_FLEXIO_H_ +#define _FSL_FLEXIO_H_ + +#include "fsl_common.h" +#include "fsl_clock.h" + +/*! + * @addtogroup flexio_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +/*! @brief FlexIO driver version 2.0.2. */ +#define FSL_FLEXIO_DRIVER_VERSION (MAKE_VERSION(2, 0, 2)) +/*@}*/ + +/*! @brief Calculate FlexIO timer trigger.*/ +#define FLEXIO_TIMER_TRIGGER_SEL_PININPUT(x) ((uint32_t)(x) << 1U) +#define FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(x) (((uint32_t)(x) << 2U) | 0x1U) +#define FLEXIO_TIMER_TRIGGER_SEL_TIMn(x) (((uint32_t)(x) << 2U) | 0x3U) + +/*! @brief Define time of timer trigger polarity.*/ +typedef enum _flexio_timer_trigger_polarity +{ + kFLEXIO_TimerTriggerPolarityActiveHigh = 0x0U, /*!< Active high. */ + kFLEXIO_TimerTriggerPolarityActiveLow = 0x1U, /*!< Active low. */ +} flexio_timer_trigger_polarity_t; + +/*! @brief Define type of timer trigger source.*/ +typedef enum _flexio_timer_trigger_source +{ + kFLEXIO_TimerTriggerSourceExternal = 0x0U, /*!< External trigger selected. */ + kFLEXIO_TimerTriggerSourceInternal = 0x1U, /*!< Internal trigger selected. */ +} flexio_timer_trigger_source_t; + +/*! @brief Define type of timer/shifter pin configuration.*/ +typedef enum _flexio_pin_config +{ + kFLEXIO_PinConfigOutputDisabled = 0x0U, /*!< Pin output disabled. */ + kFLEXIO_PinConfigOpenDrainOrBidirection = 0x1U, /*!< Pin open drain or bidirectional output enable. */ + kFLEXIO_PinConfigBidirectionOutputData = 0x2U, /*!< Pin bidirectional output data. */ + kFLEXIO_PinConfigOutput = 0x3U, /*!< Pin output. */ +} flexio_pin_config_t; + +/*! @brief Definition of pin polarity.*/ +typedef enum _flexio_pin_polarity +{ + kFLEXIO_PinActiveHigh = 0x0U, /*!< Active high. */ + kFLEXIO_PinActiveLow = 0x1U, /*!< Active low. */ +} flexio_pin_polarity_t; + +/*! @brief Define type of timer work mode.*/ +typedef enum _flexio_timer_mode +{ + kFLEXIO_TimerModeDisabled = 0x0U, /*!< Timer Disabled. */ + kFLEXIO_TimerModeDual8BitBaudBit = 0x1U, /*!< Dual 8-bit counters baud/bit mode. */ + kFLEXIO_TimerModeDual8BitPWM = 0x2U, /*!< Dual 8-bit counters PWM mode. */ + kFLEXIO_TimerModeSingle16Bit = 0x3U, /*!< Single 16-bit counter mode. */ +} flexio_timer_mode_t; + +/*! @brief Define type of timer initial output or timer reset condition.*/ +typedef enum _flexio_timer_output +{ + kFLEXIO_TimerOutputOneNotAffectedByReset = 0x0U, /*!< Logic one when enabled and is not affected by timer + reset. */ + kFLEXIO_TimerOutputZeroNotAffectedByReset = 0x1U, /*!< Logic zero when enabled and is not affected by timer + reset. */ + kFLEXIO_TimerOutputOneAffectedByReset = 0x2U, /*!< Logic one when enabled and on timer reset. */ + kFLEXIO_TimerOutputZeroAffectedByReset = 0x3U, /*!< Logic zero when enabled and on timer reset. */ +} flexio_timer_output_t; + +/*! @brief Define type of timer decrement.*/ +typedef enum _flexio_timer_decrement_source +{ + kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput = 0x0U, /*!< Decrement counter on FlexIO clock, Shift clock + equals Timer output. */ + kFLEXIO_TimerDecSrcOnTriggerInputShiftTimerOutput = 0x1U, /*!< Decrement counter on Trigger input (both edges), + Shift clock equals Timer output. */ + kFLEXIO_TimerDecSrcOnPinInputShiftPinInput = 0x2U, /*!< Decrement counter on Pin input (both edges), + Shift clock equals Pin input. */ + kFLEXIO_TimerDecSrcOnTriggerInputShiftTriggerInput = 0x3U, /*!< Decrement counter on Trigger input (both edges), + Shift clock equals Trigger input. */ +} flexio_timer_decrement_source_t; + +/*! @brief Define type of timer reset condition.*/ +typedef enum _flexio_timer_reset_condition +{ + kFLEXIO_TimerResetNever = 0x0U, /*!< Timer never reset. */ + kFLEXIO_TimerResetOnTimerPinEqualToTimerOutput = 0x2U, /*!< Timer reset on Timer Pin equal to Timer Output. */ + kFLEXIO_TimerResetOnTimerTriggerEqualToTimerOutput = 0x3U, /*!< Timer reset on Timer Trigger equal to + Timer Output. */ + kFLEXIO_TimerResetOnTimerPinRisingEdge = 0x4U, /*!< Timer reset on Timer Pin rising edge. */ + kFLEXIO_TimerResetOnTimerTriggerRisingEdge = 0x6U, /*!< Timer reset on Trigger rising edge. */ + kFLEXIO_TimerResetOnTimerTriggerBothEdge = 0x7U, /*!< Timer reset on Trigger rising or falling edge. */ +} flexio_timer_reset_condition_t; + +/*! @brief Define type of timer disable condition.*/ +typedef enum _flexio_timer_disable_condition +{ + kFLEXIO_TimerDisableNever = 0x0U, /*!< Timer never disabled. */ + kFLEXIO_TimerDisableOnPreTimerDisable = 0x1U, /*!< Timer disabled on Timer N-1 disable. */ + kFLEXIO_TimerDisableOnTimerCompare = 0x2U, /*!< Timer disabled on Timer compare. */ + kFLEXIO_TimerDisableOnTimerCompareTriggerLow = 0x3U, /*!< Timer disabled on Timer compare and Trigger Low. */ + kFLEXIO_TimerDisableOnPinBothEdge = 0x4U, /*!< Timer disabled on Pin rising or falling edge. */ + kFLEXIO_TimerDisableOnPinBothEdgeTriggerHigh = 0x5U, /*!< Timer disabled on Pin rising or falling edge provided + Trigger is high. */ + kFLEXIO_TimerDisableOnTriggerFallingEdge = 0x6U, /*!< Timer disabled on Trigger falling edge. */ +} flexio_timer_disable_condition_t; + +/*! @brief Define type of timer enable condition.*/ +typedef enum _flexio_timer_enable_condition +{ + kFLEXIO_TimerEnabledAlways = 0x0U, /*!< Timer always enabled. */ + kFLEXIO_TimerEnableOnPrevTimerEnable = 0x1U, /*!< Timer enabled on Timer N-1 enable. */ + kFLEXIO_TimerEnableOnTriggerHigh = 0x2U, /*!< Timer enabled on Trigger high. */ + kFLEXIO_TimerEnableOnTriggerHighPinHigh = 0x3U, /*!< Timer enabled on Trigger high and Pin high. */ + kFLEXIO_TimerEnableOnPinRisingEdge = 0x4U, /*!< Timer enabled on Pin rising edge. */ + kFLEXIO_TimerEnableOnPinRisingEdgeTriggerHigh = 0x5U, /*!< Timer enabled on Pin rising edge and Trigger high. */ + kFLEXIO_TimerEnableOnTriggerRisingEdge = 0x6U, /*!< Timer enabled on Trigger rising edge. */ + kFLEXIO_TimerEnableOnTriggerBothEdge = 0x7U, /*!< Timer enabled on Trigger rising or falling edge. */ +} flexio_timer_enable_condition_t; + +/*! @brief Define type of timer stop bit generate condition.*/ +typedef enum _flexio_timer_stop_bit_condition +{ + kFLEXIO_TimerStopBitDisabled = 0x0U, /*!< Stop bit disabled. */ + kFLEXIO_TimerStopBitEnableOnTimerCompare = 0x1U, /*!< Stop bit is enabled on timer compare. */ + kFLEXIO_TimerStopBitEnableOnTimerDisable = 0x2U, /*!< Stop bit is enabled on timer disable. */ + kFLEXIO_TimerStopBitEnableOnTimerCompareDisable = 0x3U, /*!< Stop bit is enabled on timer compare and timer + disable. */ +} flexio_timer_stop_bit_condition_t; + +/*! @brief Define type of timer start bit generate condition.*/ +typedef enum _flexio_timer_start_bit_condition +{ + kFLEXIO_TimerStartBitDisabled = 0x0U, /*!< Start bit disabled. */ + kFLEXIO_TimerStartBitEnabled = 0x1U, /*!< Start bit enabled. */ +} flexio_timer_start_bit_condition_t; + +/*! @brief Define type of timer polarity for shifter control. */ +typedef enum _flexio_shifter_timer_polarity +{ + kFLEXIO_ShifterTimerPolarityOnPositive = 0x0U, /*!< Shift on positive edge of shift clock. */ + kFLEXIO_ShifterTimerPolarityOnNegitive = 0x1U, /*!< Shift on negative edge of shift clock. */ +} flexio_shifter_timer_polarity_t; + +/*! @brief Define type of shifter working mode.*/ +typedef enum _flexio_shifter_mode +{ + kFLEXIO_ShifterDisabled = 0x0U, /*!< Shifter is disabled. */ + kFLEXIO_ShifterModeReceive = 0x1U, /*!< Receive mode. */ + kFLEXIO_ShifterModeTransmit = 0x2U, /*!< Transmit mode. */ + kFLEXIO_ShifterModeMatchStore = 0x4U, /*!< Match store mode. */ + kFLEXIO_ShifterModeMatchContinuous = 0x5U, /*!< Match continuous mode. */ +#if FSL_FEATURE_FLEXIO_HAS_STATE_MODE + kFLEXIO_ShifterModeState = 0x6U, /*!< SHIFTBUF contents are used for storing + programmable state attributes. */ +#endif /* FSL_FEATURE_FLEXIO_HAS_STATE_MODE */ +#if FSL_FEATURE_FLEXIO_HAS_LOGIC_MODE + kFLEXIO_ShifterModeLogic = 0x7U, /*!< SHIFTBUF contents are used for implementing + programmable logic look up table. */ +#endif /* FSL_FEATURE_FLEXIO_HAS_LOGIC_MODE */ +} flexio_shifter_mode_t; + +/*! @brief Define type of shifter input source.*/ +typedef enum _flexio_shifter_input_source +{ + kFLEXIO_ShifterInputFromPin = 0x0U, /*!< Shifter input from pin. */ + kFLEXIO_ShifterInputFromNextShifterOutput = 0x1U, /*!< Shifter input from Shifter N+1. */ +} flexio_shifter_input_source_t; + +/*! @brief Define of STOP bit configuration.*/ +typedef enum _flexio_shifter_stop_bit +{ + kFLEXIO_ShifterStopBitDisable = 0x0U, /*!< Disable shifter stop bit. */ + kFLEXIO_ShifterStopBitLow = 0x2U, /*!< Set shifter stop bit to logic low level. */ + kFLEXIO_ShifterStopBitHigh = 0x3U, /*!< Set shifter stop bit to logic high level. */ +} flexio_shifter_stop_bit_t; + +/*! @brief Define type of START bit configuration.*/ +typedef enum _flexio_shifter_start_bit +{ + kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable = 0x0U, /*!< Disable shifter start bit, transmitter loads + data on enable. */ + kFLEXIO_ShifterStartBitDisabledLoadDataOnShift = 0x1U, /*!< Disable shifter start bit, transmitter loads + data on first shift. */ + kFLEXIO_ShifterStartBitLow = 0x2U, /*!< Set shifter start bit to logic low level. */ + kFLEXIO_ShifterStartBitHigh = 0x3U, /*!< Set shifter start bit to logic high level. */ +} flexio_shifter_start_bit_t; + +/*! @brief Define FlexIO shifter buffer type*/ +typedef enum _flexio_shifter_buffer_type +{ + kFLEXIO_ShifterBuffer = 0x0U, /*!< Shifter Buffer N Register. */ + kFLEXIO_ShifterBufferBitSwapped = 0x1U, /*!< Shifter Buffer N Bit Byte Swapped Register. */ + kFLEXIO_ShifterBufferByteSwapped = 0x2U, /*!< Shifter Buffer N Byte Swapped Register. */ + kFLEXIO_ShifterBufferBitByteSwapped = 0x3U, /*!< Shifter Buffer N Bit Swapped Register. */ +#if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_BYTE_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_BYTE_SWAP + kFLEXIO_ShifterBufferNibbleByteSwapped = 0x4U, /*!< Shifter Buffer N Nibble Byte Swapped Register. */ +#endif /*FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_BYTE_SWAP*/ +#if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_HALF_WORD_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_HALF_WORD_SWAP + kFLEXIO_ShifterBufferHalfWordSwapped = 0x5U, /*!< Shifter Buffer N Half Word Swapped Register. */ +#endif +#if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_SWAP + kFLEXIO_ShifterBufferNibbleSwapped = 0x6U, /*!< Shifter Buffer N Nibble Swapped Register. */ +#endif +} flexio_shifter_buffer_type_t; + +/*! @brief Define FlexIO user configuration structure. */ +typedef struct _flexio_config_ +{ + bool enableFlexio; /*!< Enable/disable FlexIO module */ + bool enableInDoze; /*!< Enable/disable FlexIO operation in doze mode */ + bool enableInDebug; /*!< Enable/disable FlexIO operation in debug mode */ + bool enableFastAccess; /*!< Enable/disable fast access to FlexIO registers, fast access requires + the FlexIO clock to be at least twice the frequency of the bus clock. */ +} flexio_config_t; + +/*! @brief Define FlexIO timer configuration structure. */ +typedef struct _flexio_timer_config +{ + /* Trigger. */ + uint32_t triggerSelect; /*!< The internal trigger selection number using MACROs. */ + flexio_timer_trigger_polarity_t triggerPolarity; /*!< Trigger Polarity. */ + flexio_timer_trigger_source_t triggerSource; /*!< Trigger Source, internal (see 'trgsel') or external. */ + /* Pin. */ + flexio_pin_config_t pinConfig; /*!< Timer Pin Configuration. */ + uint32_t pinSelect; /*!< Timer Pin number Select. */ + flexio_pin_polarity_t pinPolarity; /*!< Timer Pin Polarity. */ + /* Timer. */ + flexio_timer_mode_t timerMode; /*!< Timer work Mode. */ + flexio_timer_output_t timerOutput; /*!< Configures the initial state of the Timer Output and + whether it is affected by the Timer reset. */ + flexio_timer_decrement_source_t timerDecrement; /*!< Configures the source of the Timer decrement and the + source of the Shift clock. */ + flexio_timer_reset_condition_t timerReset; /*!< Configures the condition that causes the timer counter + (and optionally the timer output) to be reset. */ + flexio_timer_disable_condition_t timerDisable; /*!< Configures the condition that causes the Timer to be + disabled and stop decrementing. */ + flexio_timer_enable_condition_t timerEnable; /*!< Configures the condition that causes the Timer to be + enabled and start decrementing. */ + flexio_timer_stop_bit_condition_t timerStop; /*!< Timer STOP Bit generation. */ + flexio_timer_start_bit_condition_t timerStart; /*!< Timer STRAT Bit generation. */ + uint32_t timerCompare; /*!< Value for Timer Compare N Register. */ +} flexio_timer_config_t; + +/*! @brief Define FlexIO shifter configuration structure. */ +typedef struct _flexio_shifter_config +{ + /* Timer. */ + uint32_t timerSelect; /*!< Selects which Timer is used for controlling the + logic/shift register and generating the Shift clock. */ + flexio_shifter_timer_polarity_t timerPolarity; /*!< Timer Polarity. */ + /* Pin. */ + flexio_pin_config_t pinConfig; /*!< Shifter Pin Configuration. */ + uint32_t pinSelect; /*!< Shifter Pin number Select. */ + flexio_pin_polarity_t pinPolarity; /*!< Shifter Pin Polarity. */ + /* Shifter. */ + flexio_shifter_mode_t shifterMode; /*!< Configures the mode of the Shifter. */ +#if FSL_FEATURE_FLEXIO_HAS_PARALLEL_WIDTH + uint32_t parallelWidth; /*!< Configures the parallel width when using parallel mode.*/ +#endif /* FSL_FEATURE_FLEXIO_HAS_PARALLEL_WIDTH */ + flexio_shifter_input_source_t inputSource; /*!< Selects the input source for the shifter. */ + flexio_shifter_stop_bit_t shifterStop; /*!< Shifter STOP bit. */ + flexio_shifter_start_bit_t shifterStart; /*!< Shifter START bit. */ +} flexio_shifter_config_t; + +/*! @brief typedef for FlexIO simulated driver interrupt handler.*/ +typedef void (*flexio_isr_t)(void *base, void *handle); + +/******************************************************************************* + * Variables + ******************************************************************************/ +/*! @brief Pointers to flexio bases for each instance. */ +extern FLEXIO_Type *const s_flexioBases[]; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Pointers to flexio clocks for each instance. */ +extern const clock_ip_name_t s_flexioClocks[]; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /*_cplusplus*/ + +/*! + * @name FlexIO Initialization and De-initialization + * @{ + */ + +/*! + * @brief Gets the default configuration to configure the FlexIO module. The configuration + * can used directly to call the FLEXIO_Configure(). + * + * Example: + @code + flexio_config_t config; + FLEXIO_GetDefaultConfig(&config); + @endcode + * + * @param userConfig pointer to flexio_config_t structure +*/ +void FLEXIO_GetDefaultConfig(flexio_config_t *userConfig); + +/*! + * @brief Configures the FlexIO with a FlexIO configuration. The configuration structure + * can be filled by the user or be set with default values by FLEXIO_GetDefaultConfig(). + * + * Example + @code + flexio_config_t config = { + .enableFlexio = true, + .enableInDoze = false, + .enableInDebug = true, + .enableFastAccess = false + }; + FLEXIO_Configure(base, &config); + @endcode + * + * @param base FlexIO peripheral base address + * @param userConfig pointer to flexio_config_t structure +*/ +void FLEXIO_Init(FLEXIO_Type *base, const flexio_config_t *userConfig); + +/*! + * @brief Gates the FlexIO clock. Call this API to stop the FlexIO clock. + * + * @note After calling this API, call the FLEXO_Init to use the FlexIO module. + * + * @param base FlexIO peripheral base address + */ +void FLEXIO_Deinit(FLEXIO_Type *base); + +/*! + * @brief Get instance number for FLEXIO module. + * + * @param base FLEXIO peripheral base address. + */ +uint32_t FLEXIO_GetInstance(FLEXIO_Type *base); + +/* @} */ + +/*! + * @name FlexIO Basic Operation + * @{ + */ + +/*! + * @brief Resets the FlexIO module. + * + * @param base FlexIO peripheral base address + */ +void FLEXIO_Reset(FLEXIO_Type *base); + +/*! + * @brief Enables the FlexIO module operation. + * + * @param base FlexIO peripheral base address + * @param enable true to enable, false to disable. + */ +static inline void FLEXIO_Enable(FLEXIO_Type *base, bool enable) +{ + if (enable) + { + base->CTRL |= FLEXIO_CTRL_FLEXEN_MASK; + } + else + { + base->CTRL &= ~FLEXIO_CTRL_FLEXEN_MASK; + } +} + +#if defined(FSL_FEATURE_FLEXIO_HAS_PIN_STATUS) && FSL_FEATURE_FLEXIO_HAS_PIN_STATUS +/*! + * @brief Reads the input data on each of the FlexIO pins. + * + * @param base FlexIO peripheral base address + * @return FlexIO pin input data + */ +static inline uint32_t FLEXIO_ReadPinInput(FLEXIO_Type *base) +{ + return base->PIN; +} +#endif /*FSL_FEATURE_FLEXIO_HAS_PIN_STATUS*/ + +#if defined(FSL_FEATURE_FLEXIO_HAS_STATE_MODE) && FSL_FEATURE_FLEXIO_HAS_STATE_MODE +/*! + * @brief Gets the current state pointer for state mode use. + * + * @param base FlexIO peripheral base address + * @return current State pointer + */ +static inline uint8_t FLEXIO_GetShifterState(FLEXIO_Type *base) +{ + return ((base->SHIFTSTATE) & FLEXIO_SHIFTSTATE_STATE_MASK); +} +#endif /*FSL_FEATURE_FLEXIO_HAS_STATE_MODE*/ + +/*! + * @brief Configures the shifter with the shifter configuration. The configuration structure + * covers both the SHIFTCTL and SHIFTCFG registers. To configure the shifter to the proper + * mode, select which timer controls the shifter to shift, whether to generate start bit/stop + * bit, and the polarity of start bit and stop bit. + * + * Example + @code + flexio_shifter_config_t config = { + .timerSelect = 0, + .timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive, + .pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection, + .pinPolarity = kFLEXIO_PinActiveLow, + .shifterMode = kFLEXIO_ShifterModeTransmit, + .inputSource = kFLEXIO_ShifterInputFromPin, + .shifterStop = kFLEXIO_ShifterStopBitHigh, + .shifterStart = kFLEXIO_ShifterStartBitLow + }; + FLEXIO_SetShifterConfig(base, &config); + @endcode + * + * @param base FlexIO peripheral base address + * @param index Shifter index + * @param shifterConfig Pointer to flexio_shifter_config_t structure +*/ +void FLEXIO_SetShifterConfig(FLEXIO_Type *base, uint8_t index, const flexio_shifter_config_t *shifterConfig); +/*! + * @brief Configures the timer with the timer configuration. The configuration structure + * covers both the TIMCTL and TIMCFG registers. To configure the timer to the proper + * mode, select trigger source for timer and the timer pin output and the timing for timer. + * + * Example + @code + flexio_timer_config_t config = { + .triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(0), + .triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow, + .triggerSource = kFLEXIO_TimerTriggerSourceInternal, + .pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection, + .pinSelect = 0, + .pinPolarity = kFLEXIO_PinActiveHigh, + .timerMode = kFLEXIO_TimerModeDual8BitBaudBit, + .timerOutput = kFLEXIO_TimerOutputZeroNotAffectedByReset, + .timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput, + .timerReset = kFLEXIO_TimerResetOnTimerPinEqualToTimerOutput, + .timerDisable = kFLEXIO_TimerDisableOnTimerCompare, + .timerEnable = kFLEXIO_TimerEnableOnTriggerHigh, + .timerStop = kFLEXIO_TimerStopBitEnableOnTimerDisable, + .timerStart = kFLEXIO_TimerStartBitEnabled + }; + FLEXIO_SetTimerConfig(base, &config); + @endcode + * + * @param base FlexIO peripheral base address + * @param index Timer index + * @param timerConfig Pointer to the flexio_timer_config_t structure +*/ +void FLEXIO_SetTimerConfig(FLEXIO_Type *base, uint8_t index, const flexio_timer_config_t *timerConfig); + +/* @} */ + +/*! + * @name FlexIO Interrupt Operation + * @{ + */ + +/*! + * @brief Enables the shifter status interrupt. The interrupt generates when the corresponding SSF is set. + * + * @param base FlexIO peripheral base address + * @param mask The shifter status mask which can be calculated by (1 << shifter index) + * @note For multiple shifter status interrupt enable, for example, two shifter status enable, can calculate + * the mask by using ((1 << shifter index0) | (1 << shifter index1)) + */ +static inline void FLEXIO_EnableShifterStatusInterrupts(FLEXIO_Type *base, uint32_t mask) +{ + base->SHIFTSIEN |= mask; +} + +/*! + * @brief Disables the shifter status interrupt. The interrupt won't generate when the corresponding SSF is set. + * + * @param base FlexIO peripheral base address + * @param mask The shifter status mask which can be calculated by (1 << shifter index) + * @note For multiple shifter status interrupt enable, for example, two shifter status enable, can calculate + * the mask by using ((1 << shifter index0) | (1 << shifter index1)) + */ +static inline void FLEXIO_DisableShifterStatusInterrupts(FLEXIO_Type *base, uint32_t mask) +{ + base->SHIFTSIEN &= ~mask; +} + +/*! + * @brief Enables the shifter error interrupt. The interrupt generates when the corresponding SEF is set. + * + * @param base FlexIO peripheral base address + * @param mask The shifter error mask which can be calculated by (1 << shifter index) + * @note For multiple shifter error interrupt enable, for example, two shifter error enable, can calculate + * the mask by using ((1 << shifter index0) | (1 << shifter index1)) + */ +static inline void FLEXIO_EnableShifterErrorInterrupts(FLEXIO_Type *base, uint32_t mask) +{ + base->SHIFTEIEN |= mask; +} + +/*! + * @brief Disables the shifter error interrupt. The interrupt won't generate when the corresponding SEF is set. + * + * @param base FlexIO peripheral base address + * @param mask The shifter error mask which can be calculated by (1 << shifter index) + * @note For multiple shifter error interrupt enable, for example, two shifter error enable, can calculate + * the mask by using ((1 << shifter index0) | (1 << shifter index1)) + */ +static inline void FLEXIO_DisableShifterErrorInterrupts(FLEXIO_Type *base, uint32_t mask) +{ + base->SHIFTEIEN &= ~mask; +} + +/*! + * @brief Enables the timer status interrupt. The interrupt generates when the corresponding SSF is set. + * + * @param base FlexIO peripheral base address + * @param mask The timer status mask which can be calculated by (1 << timer index) + * @note For multiple timer status interrupt enable, for example, two timer status enable, can calculate + * the mask by using ((1 << timer index0) | (1 << timer index1)) + */ +static inline void FLEXIO_EnableTimerStatusInterrupts(FLEXIO_Type *base, uint32_t mask) +{ + base->TIMIEN |= mask; +} + +/*! + * @brief Disables the timer status interrupt. The interrupt won't generate when the corresponding SSF is set. + * + * @param base FlexIO peripheral base address + * @param mask The timer status mask which can be calculated by (1 << timer index) + * @note For multiple timer status interrupt enable, for example, two timer status enable, can calculate + * the mask by using ((1 << timer index0) | (1 << timer index1)) + */ +static inline void FLEXIO_DisableTimerStatusInterrupts(FLEXIO_Type *base, uint32_t mask) +{ + base->TIMIEN &= ~mask; +} + +/* @} */ + +/*! + * @name FlexIO Status Operation + * @{ + */ + +/*! + * @brief Gets the shifter status flags. + * + * @param base FlexIO peripheral base address + * @return Shifter status flags + */ +static inline uint32_t FLEXIO_GetShifterStatusFlags(FLEXIO_Type *base) +{ + return ((base->SHIFTSTAT) & FLEXIO_SHIFTSTAT_SSF_MASK); +} + +/*! + * @brief Clears the shifter status flags. + * + * @param base FlexIO peripheral base address + * @param mask The shifter status mask which can be calculated by (1 << shifter index) + * @note For clearing multiple shifter status flags, for example, two shifter status flags, can calculate + * the mask by using ((1 << shifter index0) | (1 << shifter index1)) + */ +static inline void FLEXIO_ClearShifterStatusFlags(FLEXIO_Type *base, uint32_t mask) +{ + base->SHIFTSTAT = mask; +} + +/*! + * @brief Gets the shifter error flags. + * + * @param base FlexIO peripheral base address + * @return Shifter error flags + */ +static inline uint32_t FLEXIO_GetShifterErrorFlags(FLEXIO_Type *base) +{ + return ((base->SHIFTERR) & FLEXIO_SHIFTERR_SEF_MASK); +} + +/*! + * @brief Clears the shifter error flags. + * + * @param base FlexIO peripheral base address + * @param mask The shifter error mask which can be calculated by (1 << shifter index) + * @note For clearing multiple shifter error flags, for example, two shifter error flags, can calculate + * the mask by using ((1 << shifter index0) | (1 << shifter index1)) + */ +static inline void FLEXIO_ClearShifterErrorFlags(FLEXIO_Type *base, uint32_t mask) +{ + base->SHIFTERR = mask; +} + +/*! + * @brief Gets the timer status flags. + * + * @param base FlexIO peripheral base address + * @return Timer status flags + */ +static inline uint32_t FLEXIO_GetTimerStatusFlags(FLEXIO_Type *base) +{ + return ((base->TIMSTAT) & FLEXIO_TIMSTAT_TSF_MASK); +} + +/*! + * @brief Clears the timer status flags. + * + * @param base FlexIO peripheral base address + * @param mask The timer status mask which can be calculated by (1 << timer index) + * @note For clearing multiple timer status flags, for example, two timer status flags, can calculate + * the mask by using ((1 << timer index0) | (1 << timer index1)) + */ +static inline void FLEXIO_ClearTimerStatusFlags(FLEXIO_Type *base, uint32_t mask) +{ + base->TIMSTAT = mask; +} + +/* @} */ + +/*! + * @name FlexIO DMA Operation + * @{ + */ + +/*! + * @brief Enables/disables the shifter status DMA. The DMA request generates when the corresponding SSF is set. + * + * @note For multiple shifter status DMA enables, for example, calculate + * the mask by using ((1 << shifter index0) | (1 << shifter index1)) + * + * @param base FlexIO peripheral base address + * @param mask The shifter status mask which can be calculated by (1 << shifter index) + * @param enable True to enable, false to disable. + */ +static inline void FLEXIO_EnableShifterStatusDMA(FLEXIO_Type *base, uint32_t mask, bool enable) +{ + if (enable) + { + base->SHIFTSDEN |= mask; + } + else + { + base->SHIFTSDEN &= ~mask; + } +} + +/*! + * @brief Gets the shifter buffer address for the DMA transfer usage. + * + * @param base FlexIO peripheral base address + * @param type Shifter type of flexio_shifter_buffer_type_t + * @param index Shifter index + * @return Corresponding shifter buffer index + */ +uint32_t FLEXIO_GetShifterBufferAddress(FLEXIO_Type *base, flexio_shifter_buffer_type_t type, uint8_t index); + +/*! + * @brief Registers the handle and the interrupt handler for the FlexIO-simulated peripheral. + * + * @param base Pointer to the FlexIO simulated peripheral type. + * @param handle Pointer to the handler for FlexIO simulated peripheral. + * @param isr FlexIO simulated peripheral interrupt handler. + * @retval kStatus_Success Successfully create the handle. + * @retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range. + */ +status_t FLEXIO_RegisterHandleIRQ(void *base, void *handle, flexio_isr_t isr); + +/*! + * @brief Unregisters the handle and the interrupt handler for the FlexIO-simulated peripheral. + * + * @param base Pointer to the FlexIO simulated peripheral type. + * @retval kStatus_Success Successfully create the handle. + * @retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range. + */ +status_t FLEXIO_UnregisterHandleIRQ(void *base); +/* @} */ + +#if defined(__cplusplus) +} +#endif /*_cplusplus*/ +/*@}*/ + +#endif /*_FSL_FLEXIO_H_*/ diff --git a/source/hic_hal/freescale/kl27z/fsl_gpio.c b/source/hic_hal/freescale/kl27z/fsl_gpio.c new file mode 100644 index 000000000..7f2b16bea --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_gpio.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_gpio.h" + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.gpio" +#endif + +/******************************************************************************* + * Variables + ******************************************************************************/ + +#if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) +static PORT_Type *const s_portBases[] = PORT_BASE_PTRS; +static GPIO_Type *const s_gpioBases[] = GPIO_BASE_PTRS; +#endif + +#if defined(FSL_FEATURE_SOC_FGPIO_COUNT) && FSL_FEATURE_SOC_FGPIO_COUNT + +#if defined(FSL_FEATURE_PCC_HAS_FGPIO_CLOCK_GATE_CONTROL) && FSL_FEATURE_PCC_HAS_FGPIO_CLOCK_GATE_CONTROL + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Array to map FGPIO instance number to clock name. */ +static const clock_ip_name_t s_fgpioClockName[] = FGPIO_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +#endif /* FSL_FEATURE_PCC_HAS_FGPIO_CLOCK_GATE_CONTROL */ + +#endif /* FSL_FEATURE_SOC_FGPIO_COUNT */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +#if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) +/*! + * @brief Gets the GPIO instance according to the GPIO base + * + * @param base GPIO peripheral base pointer(PTA, PTB, PTC, etc.) + * @retval GPIO instance + */ +static uint32_t GPIO_GetInstance(GPIO_Type *base); +#endif +/******************************************************************************* + * Code + ******************************************************************************/ +#if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) +static uint32_t GPIO_GetInstance(GPIO_Type *base) +{ + uint32_t instance; + + /* Find the instance index from base address mappings. */ + for (instance = 0; instance < ARRAY_SIZE(s_gpioBases); instance++) + { + if (s_gpioBases[instance] == base) + { + break; + } + } + + assert(instance < ARRAY_SIZE(s_gpioBases)); + + return instance; +} +#endif +/*! + * brief Initializes a GPIO pin used by the board. + * + * To initialize the GPIO, define a pin configuration, as either input or output, in the user file. + * Then, call the GPIO_PinInit() function. + * + * This is an example to define an input pin or an output pin configuration. + * code + * Define a digital input pin configuration, + * gpio_pin_config_t config = + * { + * kGPIO_DigitalInput, + * 0, + * } + * Define a digital output pin configuration, + * gpio_pin_config_t config = + * { + * kGPIO_DigitalOutput, + * 0, + * } + * endcode + * + * param base GPIO peripheral base pointer (GPIOA, GPIOB, GPIOC, and so on.) + * param pin GPIO port pin number + * param config GPIO pin configuration pointer + */ +void GPIO_PinInit(GPIO_Type *base, uint32_t pin, const gpio_pin_config_t *config) +{ + assert(NULL != config); + + uint32_t u32flag = 1; + + if (config->pinDirection == kGPIO_DigitalInput) + { + base->PDDR &= ~(u32flag << pin); + } + else + { + GPIO_PinWrite(base, pin, config->outputLogic); + base->PDDR |= (u32flag << pin); + } +} + +#if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) +/*! + * brief Reads the GPIO port interrupt status flag. + * + * If a pin is configured to generate the DMA request, the corresponding flag + * is cleared automatically at the completion of the requested DMA transfer. + * Otherwise, the flag remains set until a logic one is written to that flag. + * If configured for a level sensitive interrupt that remains asserted, the flag + * is set again immediately. + * + * param base GPIO peripheral base pointer (GPIOA, GPIOB, GPIOC, and so on.) + * retval The current GPIO port interrupt status flag, for example, 0x00010001 means the + * pin 0 and 17 have the interrupt. + */ +uint32_t GPIO_PortGetInterruptFlags(GPIO_Type *base) +{ + uint8_t instance; + PORT_Type *portBase; + instance = (uint8_t)GPIO_GetInstance(base); + portBase = s_portBases[instance]; + return portBase->ISFR; +} +#endif +#if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) +/*! + * brief Clears multiple GPIO pin interrupt status flags. + * + * param base GPIO peripheral base pointer (GPIOA, GPIOB, GPIOC, and so on.) + * param mask GPIO pin number macro + */ +void GPIO_PortClearInterruptFlags(GPIO_Type *base, uint32_t mask) +{ + uint8_t instance; + PORT_Type *portBase; + instance = (uint8_t)GPIO_GetInstance(base); + portBase = s_portBases[instance]; + portBase->ISFR = mask; +} +#else +/*! + * brief Clears GPIO pin interrupt status flags. + * + * param base GPIO peripheral base pointer (GPIOA, GPIOB, GPIOC, and so on.) + * param mask GPIO pin number macro + */ +void GPIO_GpioClearInterruptFlags(GPIO_Type *base, uint32_t mask) +{ + base->ISFR[0] = mask; +} +#endif + +#if defined(FSL_FEATURE_GPIO_HAS_ATTRIBUTE_CHECKER) && FSL_FEATURE_GPIO_HAS_ATTRIBUTE_CHECKER +/*! + * brief The GPIO module supports a device-specific number of data ports, organized as 32-bit + * words/8-bit Bytes. Each 32-bit/8-bit data port includes a GACR register, which defines the byte-level + * attributes required for a successful access to the GPIO programming model. If the GPIO module's GACR register + * organized as 32-bit words, the attribute controls for the 4 data bytes in the GACR follow a standard little + * endian data convention. + * + * param base GPIO peripheral base pointer (GPIOA, GPIOB, GPIOC, and so on.) + * param mask GPIO pin number macro + */ +void GPIO_CheckAttributeBytes(GPIO_Type *base, gpio_checker_attribute_t attribute) +{ +#if defined(FSL_FEATURE_GPIO_ATTRIBUTE_CHECKER_WORD_WIDTH) && FSL_FEATURE_GPIO_ATTRIBUTE_CHECKER_WORD_WIDTH + base->GACR = ((uint32_t)attribute << GPIO_GACR_ACB0_SHIFT) | ((uint32_t)attribute << GPIO_GACR_ACB1_SHIFT) | + ((uint32_t)attribute << GPIO_GACR_ACB2_SHIFT) | ((uint32_t)attribute << GPIO_GACR_ACB3_SHIFT); +#elif defined(FSL_FEATURE_GPIO_ATTRIBUTE_CHECKER_BYTE_WIDTH) && FSL_FEATURE_GPIO_ATTRIBUTE_CHECKER_BYTE_WIDTH + base->GACR = ((uint8_t)attribute << GPIO_GACR_ACB_SHIFT); +#endif +} +#endif + +#if defined(FSL_FEATURE_SOC_FGPIO_COUNT) && FSL_FEATURE_SOC_FGPIO_COUNT + +/******************************************************************************* + * Variables + ******************************************************************************/ +#if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) +static FGPIO_Type *const s_fgpioBases[] = FGPIO_BASE_PTRS; +#endif +/******************************************************************************* + * Prototypes + ******************************************************************************/ +#if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) +/*! + * @brief Gets the FGPIO instance according to the GPIO base + * + * @param base FGPIO peripheral base pointer(PTA, PTB, PTC, etc.) + * @retval FGPIO instance + */ +static uint32_t FGPIO_GetInstance(FGPIO_Type *base); +#endif +/******************************************************************************* + * Code + ******************************************************************************/ +#if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) +static uint32_t FGPIO_GetInstance(FGPIO_Type *base) +{ + uint32_t instance; + + /* Find the instance index from base address mappings. */ + for (instance = 0; instance < ARRAY_SIZE(s_fgpioBases); instance++) + { + if (s_fgpioBases[instance] == base) + { + break; + } + } + + assert(instance < ARRAY_SIZE(s_fgpioBases)); + + return instance; +} +#endif +#if defined(FSL_FEATURE_PCC_HAS_FGPIO_CLOCK_GATE_CONTROL) && FSL_FEATURE_PCC_HAS_FGPIO_CLOCK_GATE_CONTROL +/*! + * brief Initializes the FGPIO peripheral. + * + * This function ungates the FGPIO clock. + * + * param base FGPIO peripheral base pointer (FGPIOA, FGPIOB, FGPIOC, and so on.) + */ +void FGPIO_PortInit(FGPIO_Type *base) +{ +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Ungate FGPIO periphral clock */ + CLOCK_EnableClock(s_fgpioClockName[FGPIO_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} +#endif /* FSL_FEATURE_PCC_HAS_FGPIO_CLOCK_GATE_CONTROL */ + +/*! + * brief Initializes a FGPIO pin used by the board. + * + * To initialize the FGPIO driver, define a pin configuration, as either input or output, in the user file. + * Then, call the FGPIO_PinInit() function. + * + * This is an example to define an input pin or an output pin configuration: + * code + * Define a digital input pin configuration, + * gpio_pin_config_t config = + * { + * kGPIO_DigitalInput, + * 0, + * } + * Define a digital output pin configuration, + * gpio_pin_config_t config = + * { + * kGPIO_DigitalOutput, + * 0, + * } + * endcode + * + * param base FGPIO peripheral base pointer (FGPIOA, FGPIOB, FGPIOC, and so on.) + * param pin FGPIO port pin number + * param config FGPIO pin configuration pointer + */ +void FGPIO_PinInit(FGPIO_Type *base, uint32_t pin, const gpio_pin_config_t *config) +{ + assert(NULL != config); + + uint32_t u32flag = 1; + + if (config->pinDirection == kGPIO_DigitalInput) + { + base->PDDR &= ~(u32flag << pin); + } + else + { + FGPIO_PinWrite(base, pin, config->outputLogic); + base->PDDR |= (u32flag << pin); + } +} +#if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) +/*! + * brief Reads the FGPIO port interrupt status flag. + * + * If a pin is configured to generate the DMA request, the corresponding flag + * is cleared automatically at the completion of the requested DMA transfer. + * Otherwise, the flag remains set until a logic one is written to that flag. + * If configured for a level-sensitive interrupt that remains asserted, the flag + * is set again immediately. + * + * param base FGPIO peripheral base pointer (FGPIOA, FGPIOB, FGPIOC, and so on.) + * retval The current FGPIO port interrupt status flags, for example, 0x00010001 means the + * pin 0 and 17 have the interrupt. + */ +uint32_t FGPIO_PortGetInterruptFlags(FGPIO_Type *base) +{ + uint8_t instance; + instance = (uint8_t)FGPIO_GetInstance(base); + PORT_Type *portBase; + portBase = s_portBases[instance]; + return portBase->ISFR; +} + +/*! + * brief Clears the multiple FGPIO pin interrupt status flag. + * + * param base FGPIO peripheral base pointer (FGPIOA, FGPIOB, FGPIOC, and so on.) + * param mask FGPIO pin number macro + */ +void FGPIO_PortClearInterruptFlags(FGPIO_Type *base, uint32_t mask) +{ + uint8_t instance; + instance = (uint8_t)FGPIO_GetInstance(base); + PORT_Type *portBase; + portBase = s_portBases[instance]; + portBase->ISFR = mask; +} +#endif +#if defined(FSL_FEATURE_FGPIO_HAS_ATTRIBUTE_CHECKER) && FSL_FEATURE_FGPIO_HAS_ATTRIBUTE_CHECKER +/*! + * brief The FGPIO module supports a device-specific number of data ports, organized as 32-bit + * words. Each 32-bit data port includes a GACR register, which defines the byte-level + * attributes required for a successful access to the GPIO programming model. The attribute controls for the 4 data + * bytes in the GACR follow a standard little endian + * data convention. + * + * param base FGPIO peripheral base pointer (FGPIOA, FGPIOB, FGPIOC, and so on.) + * param mask FGPIO pin number macro + */ +void FGPIO_CheckAttributeBytes(FGPIO_Type *base, gpio_checker_attribute_t attribute) +{ + base->GACR = (attribute << FGPIO_GACR_ACB0_SHIFT) | (attribute << FGPIO_GACR_ACB1_SHIFT) | + (attribute << FGPIO_GACR_ACB2_SHIFT) | (attribute << FGPIO_GACR_ACB3_SHIFT); +} +#endif + +#endif /* FSL_FEATURE_SOC_FGPIO_COUNT */ diff --git a/source/hic_hal/freescale/kl27z/fsl_gpio.h b/source/hic_hal/freescale/kl27z/fsl_gpio.h new file mode 100644 index 000000000..14ea5094e --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_gpio.h @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_GPIO_H_ +#define _FSL_GPIO_H_ + +#include "fsl_common.h" + +/*! + * @addtogroup gpio + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +/*! @brief GPIO driver version 2.4.1. */ +#define FSL_GPIO_DRIVER_VERSION (MAKE_VERSION(2, 4, 1)) +/*@}*/ + +/*! @brief GPIO direction definition */ +typedef enum _gpio_pin_direction +{ + kGPIO_DigitalInput = 0U, /*!< Set current pin as digital input*/ + kGPIO_DigitalOutput = 1U, /*!< Set current pin as digital output*/ +} gpio_pin_direction_t; + +#if defined(FSL_FEATURE_GPIO_HAS_ATTRIBUTE_CHECKER) && FSL_FEATURE_GPIO_HAS_ATTRIBUTE_CHECKER +/*! @brief GPIO checker attribute */ +typedef enum _gpio_checker_attribute +{ + kGPIO_UsernonsecureRWUsersecureRWPrivilegedsecureRW = + 0x00U, /*!< User nonsecure:Read+Write; User Secure:Read+Write; Privileged Secure:Read+Write */ + kGPIO_UsernonsecureRUsersecureRWPrivilegedsecureRW = + 0x01U, /*!< User nonsecure:Read; User Secure:Read+Write; Privileged Secure:Read+Write */ + kGPIO_UsernonsecureNUsersecureRWPrivilegedsecureRW = + 0x02U, /*!< User nonsecure:None; User Secure:Read+Write; Privileged Secure:Read+Write */ + kGPIO_UsernonsecureRUsersecureRPrivilegedsecureRW = + 0x03U, /*!< User nonsecure:Read; User Secure:Read; Privileged Secure:Read+Write */ + kGPIO_UsernonsecureNUsersecureRPrivilegedsecureRW = + 0x04U, /*!< User nonsecure:None; User Secure:Read; Privileged Secure:Read+Write */ + kGPIO_UsernonsecureNUsersecureNPrivilegedsecureRW = + 0x05U, /*!< User nonsecure:None; User Secure:None; Privileged Secure:Read+Write */ + kGPIO_UsernonsecureNUsersecureNPrivilegedsecureR = + 0x06U, /*!< User nonsecure:None; User Secure:None; Privileged Secure:Read */ + kGPIO_UsernonsecureNUsersecureNPrivilegedsecureN = + 0x07U, /*!< User nonsecure:None; User Secure:None; Privileged Secure:None */ + kGPIO_IgnoreAttributeCheck = 0x80U, /*!< Ignores the attribute check */ +} gpio_checker_attribute_t; +#endif + +/*! + * @brief The GPIO pin configuration structure. + * + * Each pin can only be configured as either an output pin or an input pin at a time. + * If configured as an input pin, leave the outputConfig unused. + * Note that in some use cases, the corresponding port property should be configured in advance + * with the PORT_SetPinConfig(). + */ +typedef struct _gpio_pin_config +{ + gpio_pin_direction_t pinDirection; /*!< GPIO direction, input or output */ + /* Output configurations; ignore if configured as an input pin */ + uint8_t outputLogic; /*!< Set a default output logic, which has no use in input */ +} gpio_pin_config_t; + +#if (defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) +/*! @brief Configures the interrupt generation condition. */ +typedef enum _gpio_interrupt_config +{ + kGPIO_InterruptStatusFlagDisabled = 0x0U, /*!< Interrupt status flag is disabled. */ + kGPIO_DMARisingEdge = 0x1U, /*!< ISF flag and DMA request on rising edge. */ + kGPIO_DMAFallingEdge = 0x2U, /*!< ISF flag and DMA request on falling edge. */ + kGPIO_DMAEitherEdge = 0x3U, /*!< ISF flag and DMA request on either edge. */ + kGPIO_FlagRisingEdge = 0x05U, /*!< Flag sets on rising edge. */ + kGPIO_FlagFallingEdge = 0x06U, /*!< Flag sets on falling edge. */ + kGPIO_FlagEitherEdge = 0x07U, /*!< Flag sets on either edge. */ + kGPIO_InterruptLogicZero = 0x8U, /*!< Interrupt when logic zero. */ + kGPIO_InterruptRisingEdge = 0x9U, /*!< Interrupt on rising edge. */ + kGPIO_InterruptFallingEdge = 0xAU, /*!< Interrupt on falling edge. */ + kGPIO_InterruptEitherEdge = 0xBU, /*!< Interrupt on either edge. */ + kGPIO_InterruptLogicOne = 0xCU, /*!< Interrupt when logic one. */ + kGPIO_ActiveHighTriggerOutputEnable = 0xDU, /*!< Enable active high-trigger output. */ + kGPIO_ActiveLowTriggerOutputEnable = 0xEU, /*!< Enable active low-trigger output. */ +} gpio_interrupt_config_t; +#endif +/*! @} */ + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @addtogroup gpio_driver + * @{ + */ + +/*! @name GPIO Configuration */ +/*@{*/ + +/*! + * @brief Initializes a GPIO pin used by the board. + * + * To initialize the GPIO, define a pin configuration, as either input or output, in the user file. + * Then, call the GPIO_PinInit() function. + * + * This is an example to define an input pin or an output pin configuration. + * @code + * Define a digital input pin configuration, + * gpio_pin_config_t config = + * { + * kGPIO_DigitalInput, + * 0, + * } + * Define a digital output pin configuration, + * gpio_pin_config_t config = + * { + * kGPIO_DigitalOutput, + * 0, + * } + * @endcode + * + * @param base GPIO peripheral base pointer (GPIOA, GPIOB, GPIOC, and so on.) + * @param pin GPIO port pin number + * @param config GPIO pin configuration pointer + */ +void GPIO_PinInit(GPIO_Type *base, uint32_t pin, const gpio_pin_config_t *config); + +/*@}*/ + +/*! @name GPIO Output Operations */ +/*@{*/ + +/*! + * @brief Sets the output level of the multiple GPIO pins to the logic 1 or 0. + * + * @param base GPIO peripheral base pointer (GPIOA, GPIOB, GPIOC, and so on.) + * @param pin GPIO pin number + * @param output GPIO pin output logic level. + * - 0: corresponding pin output low-logic level. + * - 1: corresponding pin output high-logic level. + */ +static inline void GPIO_PinWrite(GPIO_Type *base, uint32_t pin, uint8_t output) +{ + uint32_t u32flag = 1; + + if (output == 0U) + { + base->PCOR = u32flag << pin; + } + else + { + base->PSOR = u32flag << pin; + } +} + +/*! + * @brief Sets the output level of the multiple GPIO pins to the logic 1. + * + * @param base GPIO peripheral base pointer (GPIOA, GPIOB, GPIOC, and so on.) + * @param mask GPIO pin number macro + */ +static inline void GPIO_PortSet(GPIO_Type *base, uint32_t mask) +{ + base->PSOR = mask; +} + +/*! + * @brief Sets the output level of the multiple GPIO pins to the logic 0. + * + * @param base GPIO peripheral base pointer (GPIOA, GPIOB, GPIOC, and so on.) + * @param mask GPIO pin number macro + */ +static inline void GPIO_PortClear(GPIO_Type *base, uint32_t mask) +{ + base->PCOR = mask; +} + +/*! + * @brief Reverses the current output logic of the multiple GPIO pins. + * + * @param base GPIO peripheral base pointer (GPIOA, GPIOB, GPIOC, and so on.) + * @param mask GPIO pin number macro + */ +static inline void GPIO_PortToggle(GPIO_Type *base, uint32_t mask) +{ + base->PTOR = mask; +} + +/*@}*/ + +/*! @name GPIO Input Operations */ +/*@{*/ + +/*! + * @brief Reads the current input value of the GPIO port. + * + * @param base GPIO peripheral base pointer (GPIOA, GPIOB, GPIOC, and so on.) + * @param pin GPIO pin number + * @retval GPIO port input value + * - 0: corresponding pin input low-logic level. + * - 1: corresponding pin input high-logic level. + */ +static inline uint32_t GPIO_PinRead(GPIO_Type *base, uint32_t pin) +{ + return (((base->PDIR) >> pin) & 0x01U); +} + +/*@}*/ + +/*! @name GPIO Interrupt */ +/*@{*/ +#if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) +/*! + * @brief Reads the GPIO port interrupt status flag. + * + * If a pin is configured to generate the DMA request, the corresponding flag + * is cleared automatically at the completion of the requested DMA transfer. + * Otherwise, the flag remains set until a logic one is written to that flag. + * If configured for a level sensitive interrupt that remains asserted, the flag + * is set again immediately. + * + * @param base GPIO peripheral base pointer (GPIOA, GPIOB, GPIOC, and so on.) + * @retval The current GPIO port interrupt status flag, for example, 0x00010001 means the + * pin 0 and 17 have the interrupt. + */ +uint32_t GPIO_PortGetInterruptFlags(GPIO_Type *base); + +/*! + * @brief Clears multiple GPIO pin interrupt status flags. + * + * @param base GPIO peripheral base pointer (GPIOA, GPIOB, GPIOC, and so on.) + * @param mask GPIO pin number macro + */ +void GPIO_PortClearInterruptFlags(GPIO_Type *base, uint32_t mask); +#else +/*! + * @brief Configures the gpio pin interrupt/DMA request. + * + * @param base GPIO peripheral base pointer. + * @param pin GPIO pin number. + * @param config GPIO pin interrupt configuration. + * - #kGPIO_InterruptStatusFlagDisabled: Interrupt/DMA request disabled. + * - #kGPIO_DMARisingEdge : DMA request on rising edge(if the DMA requests exit). + * - #kGPIO_DMAFallingEdge: DMA request on falling edge(if the DMA requests exit). + * - #kGPIO_DMAEitherEdge : DMA request on either edge(if the DMA requests exit). + * - #kGPIO_FlagRisingEdge : Flag sets on rising edge(if the Flag states exit). + * - #kGPIO_FlagFallingEdge : Flag sets on falling edge(if the Flag states exit). + * - #kGPIO_FlagEitherEdge : Flag sets on either edge(if the Flag states exit). + * - #kGPIO_InterruptLogicZero : Interrupt when logic zero. + * - #kGPIO_InterruptRisingEdge : Interrupt on rising edge. + * - #kGPIO_InterruptFallingEdge: Interrupt on falling edge. + * - #kGPIO_InterruptEitherEdge : Interrupt on either edge. + * - #kGPIO_InterruptLogicOne : Interrupt when logic one. + * - #kGPIO_ActiveHighTriggerOutputEnable : Enable active high-trigger output (if the trigger states exit). + * - #kGPIO_ActiveLowTriggerOutputEnable : Enable active low-trigger output (if the trigger states exit). + */ +static inline void GPIO_SetPinInterruptConfig(GPIO_Type *base, uint32_t pin, gpio_interrupt_config_t config) +{ + assert(base); + + base->ICR[pin] = (base->ICR[pin] & ~GPIO_ICR_IRQC_MASK) | GPIO_ICR_IRQC(config); +} +/*! + * brief Clears GPIO pin interrupt status flags. + * + * param base GPIO peripheral base pointer (GPIOA, GPIOB, GPIOC, and so on.) + * param mask GPIO pin number macro + */ +void GPIO_GpioClearInterruptFlags(GPIO_Type *base, uint32_t mask); +/*! + * @brief Reads the GPIO DMA request flags. + * The corresponding flag will be cleared automatically at the completion of the requested + * DMA transfer + */ +static inline uint32_t GPIO_GetPinsDMARequestFlags(GPIO_Type *base) +{ + assert(base); + return (base->ISFR[1]); +} + +/*! + * @brief Sets the GPIO interrupt configuration in PCR register for multiple pins. + * + * @param base GPIO peripheral base pointer. + * @param mask GPIO pin number macro. + * @param config GPIO pin interrupt configuration. + * - #kGPIO_InterruptStatusFlagDisabled: Interrupt disabled. + * - #kGPIO_DMARisingEdge : DMA request on rising edge(if the DMA requests exit). + * - #kGPIO_DMAFallingEdge: DMA request on falling edge(if the DMA requests exit). + * - #kGPIO_DMAEitherEdge : DMA request on either edge(if the DMA requests exit). + * - #kGPIO_FlagRisingEdge : Flag sets on rising edge(if the Flag states exit). + * - #kGPIO_FlagFallingEdge : Flag sets on falling edge(if the Flag states exit). + * - #kGPIO_FlagEitherEdge : Flag sets on either edge(if the Flag states exit). + * - #kGPIO_InterruptLogicZero : Interrupt when logic zero. + * - #kGPIO_InterruptRisingEdge : Interrupt on rising edge. + * - #kGPIO_InterruptFallingEdge: Interrupt on falling edge. + * - #kGPIO_InterruptEitherEdge : Interrupt on either edge. + * - #kGPIO_InterruptLogicOne : Interrupt when logic one. + * - #kGPIO_ActiveHighTriggerOutputEnable : Enable active high-trigger output (if the trigger states exit). + * - #kGPIO_ActiveLowTriggerOutputEnable : Enable active low-trigger output (if the trigger states exit).. + */ +static inline void GPIO_SetMultipleInterruptPinsConfig(GPIO_Type *base, uint32_t mask, gpio_interrupt_config_t config) +{ + assert(base); + + if (mask & 0xffffU) + { + base->GICLR = (GPIO_ICR_IRQC(config)) | (mask & 0xffffU); + } + mask = mask >> 16; + if (mask) + { + base->GICHR = (GPIO_ICR_IRQC(config)) | (mask & 0xffffU); + } +} +#endif + +#if defined(FSL_FEATURE_GPIO_HAS_ATTRIBUTE_CHECKER) && FSL_FEATURE_GPIO_HAS_ATTRIBUTE_CHECKER +/*! + * brief The GPIO module supports a device-specific number of data ports, organized as 32-bit + * words/8-bit Bytes. Each 32-bit/8-bit data port includes a GACR register, which defines the byte-level + * attributes required for a successful access to the GPIO programming model. If the GPIO module's GACR register + * organized as 32-bit words, the attribute controls for the 4 data bytes in the GACR follow a standard little + * endian data convention. + * + * @param base GPIO peripheral base pointer (GPIOA, GPIOB, GPIOC, and so on.) + * @param mask GPIO pin number macro + */ +void GPIO_CheckAttributeBytes(GPIO_Type *base, gpio_checker_attribute_t attribute); +#endif + +/*@}*/ +/*! @} */ + +/*! + * @addtogroup fgpio_driver + * @{ + */ + +/* + * Introduces the FGPIO feature. + * + * The FGPIO features are only support on some Kinetis MCUs. The FGPIO registers are aliased to the IOPORT + * interface. Accesses via the IOPORT interface occur in parallel with any instruction fetches and + * complete in a single cycle. This aliased Fast GPIO memory map is called FGPIO. + */ + +#if defined(FSL_FEATURE_SOC_FGPIO_COUNT) && FSL_FEATURE_SOC_FGPIO_COUNT + +/*! @name FGPIO Configuration */ +/*@{*/ + +#if defined(FSL_FEATURE_PCC_HAS_FGPIO_CLOCK_GATE_CONTROL) && FSL_FEATURE_PCC_HAS_FGPIO_CLOCK_GATE_CONTROL +/*! + * @brief Initializes the FGPIO peripheral. + * + * This function ungates the FGPIO clock. + * + * @param base FGPIO peripheral base pointer (FGPIOA, FGPIOB, FGPIOC, and so on.) + */ +void FGPIO_PortInit(FGPIO_Type *base); +#endif /* FSL_FEATURE_PCC_HAS_FGPIO_CLOCK_GATE_CONTROL */ + +/*! + * @brief Initializes a FGPIO pin used by the board. + * + * To initialize the FGPIO driver, define a pin configuration, as either input or output, in the user file. + * Then, call the FGPIO_PinInit() function. + * + * This is an example to define an input pin or an output pin configuration: + * @code + * Define a digital input pin configuration, + * gpio_pin_config_t config = + * { + * kGPIO_DigitalInput, + * 0, + * } + * Define a digital output pin configuration, + * gpio_pin_config_t config = + * { + * kGPIO_DigitalOutput, + * 0, + * } + * @endcode + * + * @param base FGPIO peripheral base pointer (FGPIOA, FGPIOB, FGPIOC, and so on.) + * @param pin FGPIO port pin number + * @param config FGPIO pin configuration pointer + */ +void FGPIO_PinInit(FGPIO_Type *base, uint32_t pin, const gpio_pin_config_t *config); + +/*@}*/ + +/*! @name FGPIO Output Operations */ +/*@{*/ + +/*! + * @brief Sets the output level of the multiple FGPIO pins to the logic 1 or 0. + * + * @param base FGPIO peripheral base pointer (FGPIOA, FGPIOB, FGPIOC, and so on.) + * @param pin FGPIO pin number + * @param output FGPIOpin output logic level. + * - 0: corresponding pin output low-logic level. + * - 1: corresponding pin output high-logic level. + */ +static inline void FGPIO_PinWrite(FGPIO_Type *base, uint32_t pin, uint8_t output) +{ + uint32_t u32flag = 1; + + if (output == 0U) + { + base->PCOR = u32flag << pin; + } + else + { + base->PSOR = u32flag << pin; + } +} + +/*! + * @brief Sets the output level of the multiple FGPIO pins to the logic 1. + * + * @param base FGPIO peripheral base pointer (FGPIOA, FGPIOB, FGPIOC, and so on.) + * @param mask FGPIO pin number macro + */ +static inline void FGPIO_PortSet(FGPIO_Type *base, uint32_t mask) +{ + base->PSOR = mask; +} + +/*! + * @brief Sets the output level of the multiple FGPIO pins to the logic 0. + * + * @param base FGPIO peripheral base pointer (FGPIOA, FGPIOB, FGPIOC, and so on.) + * @param mask FGPIO pin number macro + */ +static inline void FGPIO_PortClear(FGPIO_Type *base, uint32_t mask) +{ + base->PCOR = mask; +} + +/*! + * @brief Reverses the current output logic of the multiple FGPIO pins. + * + * @param base FGPIO peripheral base pointer (FGPIOA, FGPIOB, FGPIOC, and so on.) + * @param mask FGPIO pin number macro + */ +static inline void FGPIO_PortToggle(FGPIO_Type *base, uint32_t mask) +{ + base->PTOR = mask; +} +/*@}*/ + +/*! @name FGPIO Input Operations */ +/*@{*/ + +/*! + * @brief Reads the current input value of the FGPIO port. + * + * @param base FGPIO peripheral base pointer (FGPIOA, FGPIOB, FGPIOC, and so on.) + * @param pin FGPIO pin number + * @retval FGPIO port input value + * - 0: corresponding pin input low-logic level. + * - 1: corresponding pin input high-logic level. + */ +static inline uint32_t FGPIO_PinRead(FGPIO_Type *base, uint32_t pin) +{ + return (((base->PDIR) >> pin) & 0x01U); +} +/*@}*/ + +/*! @name FGPIO Interrupt */ +/*@{*/ +#if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) + +/*! + * @brief Reads the FGPIO port interrupt status flag. + * + * If a pin is configured to generate the DMA request, the corresponding flag + * is cleared automatically at the completion of the requested DMA transfer. + * Otherwise, the flag remains set until a logic one is written to that flag. + * If configured for a level-sensitive interrupt that remains asserted, the flag + * is set again immediately. + * + * @param base FGPIO peripheral base pointer (FGPIOA, FGPIOB, FGPIOC, and so on.) + * @retval The current FGPIO port interrupt status flags, for example, 0x00010001 means the + * pin 0 and 17 have the interrupt. + */ +uint32_t FGPIO_PortGetInterruptFlags(FGPIO_Type *base); + +/*! + * @brief Clears the multiple FGPIO pin interrupt status flag. + * + * @param base FGPIO peripheral base pointer (FGPIOA, FGPIOB, FGPIOC, and so on.) + * @param mask FGPIO pin number macro + */ +void FGPIO_PortClearInterruptFlags(FGPIO_Type *base, uint32_t mask); +#endif +#if defined(FSL_FEATURE_GPIO_HAS_ATTRIBUTE_CHECKER) && FSL_FEATURE_GPIO_HAS_ATTRIBUTE_CHECKER +/*! + * @brief The FGPIO module supports a device-specific number of data ports, organized as 32-bit + * words. Each 32-bit data port includes a GACR register, which defines the byte-level + * attributes required for a successful access to the GPIO programming model. The attribute controls for the 4 data + * bytes in the GACR follow a standard little endian + * data convention. + * + * @param base FGPIO peripheral base pointer (FGPIOA, FGPIOB, FGPIOC, and so on.) + * @param mask FGPIO pin number macro + */ +void FGPIO_CheckAttributeBytes(FGPIO_Type *base, gpio_checker_attribute_t attribute); +#endif + +/*@}*/ + +#endif /* FSL_FEATURE_SOC_FGPIO_COUNT */ + +#if defined(__cplusplus) +} +#endif + +/*! + * @} + */ + +#endif /* _FSL_GPIO_H_*/ diff --git a/source/hic_hal/freescale/kl27z/fsl_i2c.h b/source/hic_hal/freescale/kl27z/fsl_i2c.h new file mode 100644 index 000000000..f67c977bc --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_i2c.h @@ -0,0 +1,795 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_I2C_H_ +#define _FSL_I2C_H_ + +#include "fsl_common.h" + +/*! + * @addtogroup i2c_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +/*! @brief I2C driver version 2.0.7. */ +#define FSL_I2C_DRIVER_VERSION (MAKE_VERSION(2, 0, 7)) +/*@}*/ + +/*! @brief Timeout times for waiting flag. */ +#ifndef I2C_WAIT_TIMEOUT +#define I2C_WAIT_TIMEOUT 0U /* Define to zero means keep waiting until the flag is assert/deassert. */ +#endif + +/*! @brief Mater Fast ack control, control if master needs to manually write ack, this is used to +low the speed of transfer for SoCs with feature FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING */ +#ifndef I2C_MASTER_FACK_CONTROL +#define I2C_MASTER_FACK_CONTROL 0U /* Default defines to zero means master will send ack automatically. */ +#endif + +#if (defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT || \ + defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT) +#define I2C_HAS_STOP_DETECT +#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT / FSL_FEATURE_I2C_HAS_STOP_DETECT */ + +/*! @brief I2C status return codes. */ +enum _i2c_status +{ + kStatus_I2C_Busy = MAKE_STATUS(kStatusGroup_I2C, 0), /*!< I2C is busy with current transfer. */ + kStatus_I2C_Idle = MAKE_STATUS(kStatusGroup_I2C, 1), /*!< Bus is Idle. */ + kStatus_I2C_Nak = MAKE_STATUS(kStatusGroup_I2C, 2), /*!< NAK received during transfer. */ + kStatus_I2C_ArbitrationLost = MAKE_STATUS(kStatusGroup_I2C, 3), /*!< Arbitration lost during transfer. */ + kStatus_I2C_Timeout = MAKE_STATUS(kStatusGroup_I2C, 4), /*!< Timeout poling status flags. */ + kStatus_I2C_Addr_Nak = MAKE_STATUS(kStatusGroup_I2C, 5), /*!< NAK received during the address probe. */ +}; + +/*! + * @brief I2C peripheral flags + * + * The following status register flags can be cleared: + * - #kI2C_ArbitrationLostFlag + * - #kI2C_IntPendingFlag + * - #kI2C_StartDetectFlag + * - #kI2C_StopDetectFlag + * + * @note These enumerations are meant to be OR'd together to form a bit mask. + * + */ +enum _i2c_flags +{ + kI2C_ReceiveNakFlag = I2C_S_RXAK_MASK, /*!< I2C receive NAK flag. */ + kI2C_IntPendingFlag = I2C_S_IICIF_MASK, /*!< I2C interrupt pending flag. */ + kI2C_TransferDirectionFlag = I2C_S_SRW_MASK, /*!< I2C transfer direction flag. */ + kI2C_RangeAddressMatchFlag = I2C_S_RAM_MASK, /*!< I2C range address match flag. */ + kI2C_ArbitrationLostFlag = I2C_S_ARBL_MASK, /*!< I2C arbitration lost flag. */ + kI2C_BusBusyFlag = I2C_S_BUSY_MASK, /*!< I2C bus busy flag. */ + kI2C_AddressMatchFlag = I2C_S_IAAS_MASK, /*!< I2C address match flag. */ + kI2C_TransferCompleteFlag = I2C_S_TCF_MASK, /*!< I2C transfer complete flag. */ +#ifdef I2C_HAS_STOP_DETECT + kI2C_StopDetectFlag = I2C_FLT_STOPF_MASK << 8, /*!< I2C stop detect flag. */ +#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT / FSL_FEATURE_I2C_HAS_STOP_DETECT */ + +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + kI2C_StartDetectFlag = I2C_FLT_STARTF_MASK << 8, /*!< I2C start detect flag. */ +#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */ +}; + +/*! @brief I2C feature interrupt source. */ +enum _i2c_interrupt_enable +{ + kI2C_GlobalInterruptEnable = I2C_C1_IICIE_MASK, /*!< I2C global interrupt. */ + +#if defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT + kI2C_StopDetectInterruptEnable = I2C_FLT_STOPIE_MASK, /*!< I2C stop detect interrupt. */ +#endif /* FSL_FEATURE_I2C_HAS_STOP_DETECT */ + +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + kI2C_StartStopDetectInterruptEnable = I2C_FLT_SSIE_MASK, /*!< I2C start&stop detect interrupt. */ +#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */ +}; + +/*! @brief The direction of master and slave transfers. */ +typedef enum _i2c_direction +{ + kI2C_Write = 0x0U, /*!< Master transmits to the slave. */ + kI2C_Read = 0x1U, /*!< Master receives from the slave. */ +} i2c_direction_t; + +/*! @brief Addressing mode. */ +typedef enum _i2c_slave_address_mode +{ + kI2C_Address7bit = 0x0U, /*!< 7-bit addressing mode. */ + kI2C_RangeMatch = 0X2U, /*!< Range address match addressing mode. */ +} i2c_slave_address_mode_t; + +/*! @brief I2C transfer control flag. */ +enum _i2c_master_transfer_flags +{ + kI2C_TransferDefaultFlag = 0x0U, /*!< A transfer starts with a start signal, stops with a stop signal. */ + kI2C_TransferNoStartFlag = 0x1U, /*!< A transfer starts without a start signal, only support write only or + write+read with no start flag, do not support read only with no start flag. */ + kI2C_TransferRepeatedStartFlag = 0x2U, /*!< A transfer starts with a repeated start signal. */ + kI2C_TransferNoStopFlag = 0x4U, /*!< A transfer ends without a stop signal. */ +}; + +/*! + * @brief Set of events sent to the callback for nonblocking slave transfers. + * + * These event enumerations are used for two related purposes. First, a bit mask created by OR'ing together + * events is passed to I2C_SlaveTransferNonBlocking() to specify which events to enable. + * Then, when the slave callback is invoked, it is passed the current event through its @a transfer + * parameter. + * + * @note These enumerations are meant to be OR'd together to form a bit mask of events. + */ +typedef enum _i2c_slave_transfer_event +{ + kI2C_SlaveAddressMatchEvent = 0x01U, /*!< Received the slave address after a start or repeated start. */ + kI2C_SlaveTransmitEvent = 0x02U, /*!< A callback is requested to provide data to transmit + (slave-transmitter role). */ + kI2C_SlaveReceiveEvent = 0x04U, /*!< A callback is requested to provide a buffer in which to place received + data (slave-receiver role). */ + kI2C_SlaveTransmitAckEvent = 0x08U, /*!< A callback needs to either transmit an ACK or NACK. */ +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + kI2C_SlaveStartEvent = 0x10U, /*!< A start/repeated start was detected. */ +#endif + kI2C_SlaveCompletionEvent = 0x20U, /*!< A stop was detected or finished transfer, completing the transfer. */ + kI2C_SlaveGenaralcallEvent = 0x40U, /*!< Received the general call address after a start or repeated start. */ + + /*! A bit mask of all available events. */ + kI2C_SlaveAllEvents = kI2C_SlaveAddressMatchEvent | kI2C_SlaveTransmitEvent | kI2C_SlaveReceiveEvent | +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + kI2C_SlaveStartEvent | +#endif + kI2C_SlaveCompletionEvent | kI2C_SlaveGenaralcallEvent, +} i2c_slave_transfer_event_t; + +/*! @brief I2C master user configuration. */ +typedef struct _i2c_master_config +{ + bool enableMaster; /*!< Enables the I2C peripheral at initialization time. */ +#if defined(FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF) && FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF + bool enableStopHold; /*!< Controls the stop hold enable. */ +#endif +#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE + bool enableDoubleBuffering; /*!< Controls double buffer enable; notice that + enabling the double buffer disables the clock stretch. */ +#endif + uint32_t baudRate_Bps; /*!< Baud rate configuration of I2C peripheral. */ + uint8_t glitchFilterWidth; /*!< Controls the width of the glitch. */ +} i2c_master_config_t; + +/*! @brief I2C slave user configuration. */ +typedef struct _i2c_slave_config +{ + bool enableSlave; /*!< Enables the I2C peripheral at initialization time. */ + bool enableGeneralCall; /*!< Enables the general call addressing mode. */ + bool enableWakeUp; /*!< Enables/disables waking up MCU from low-power mode. */ +#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE + bool enableDoubleBuffering; /*!< Controls a double buffer enable; notice that + enabling the double buffer disables the clock stretch. */ +#endif + bool enableBaudRateCtl; /*!< Enables/disables independent slave baud rate on SCL in very fast I2C modes. */ + uint16_t slaveAddress; /*!< A slave address configuration. */ + uint16_t upperAddress; /*!< A maximum boundary slave address used in a range matching mode. */ + i2c_slave_address_mode_t + addressingMode; /*!< An addressing mode configuration of i2c_slave_address_mode_config_t. */ + uint32_t sclStopHoldTime_ns; /*!< the delay from the rising edge of SCL (I2C clock) to the rising edge of SDA (I2C + data) while SCL is high (stop condition), SDA hold time and SCL start hold time + are also configured according to the SCL stop hold time. */ +} i2c_slave_config_t; + +/*! @brief I2C master handle typedef. */ +typedef struct _i2c_master_handle i2c_master_handle_t; + +/*! @brief I2C master transfer callback typedef. */ +typedef void (*i2c_master_transfer_callback_t)(I2C_Type *base, + i2c_master_handle_t *handle, + status_t status, + void *userData); + +/*! @brief I2C slave handle typedef. */ +typedef struct _i2c_slave_handle i2c_slave_handle_t; + +/*! @brief I2C master transfer structure. */ +typedef struct _i2c_master_transfer +{ + uint32_t flags; /*!< A transfer flag which controls the transfer. */ + uint8_t slaveAddress; /*!< 7-bit slave address. */ + i2c_direction_t direction; /*!< A transfer direction, read or write. */ + uint32_t subaddress; /*!< A sub address. Transferred MSB first. */ + uint8_t subaddressSize; /*!< A size of the command buffer. */ + uint8_t *volatile data; /*!< A transfer buffer. */ + volatile size_t dataSize; /*!< A transfer size. */ +} i2c_master_transfer_t; + +/*! @brief I2C master handle structure. */ +struct _i2c_master_handle +{ + i2c_master_transfer_t transfer; /*!< I2C master transfer copy. */ + size_t transferSize; /*!< Total bytes to be transferred. */ + uint8_t state; /*!< A transfer state maintained during transfer. */ + i2c_master_transfer_callback_t completionCallback; /*!< A callback function called when the transfer is finished. */ + void *userData; /*!< A callback parameter passed to the callback function. */ +}; + +/*! @brief I2C slave transfer structure. */ +typedef struct _i2c_slave_transfer +{ + i2c_slave_transfer_event_t event; /*!< A reason that the callback is invoked. */ + uint8_t *volatile data; /*!< A transfer buffer. */ + volatile size_t dataSize; /*!< A transfer size. */ + status_t completionStatus; /*!< Success or error code describing how the transfer completed. Only applies for + #kI2C_SlaveCompletionEvent. */ + size_t transferredCount; /*!< A number of bytes actually transferred since the start or since the last repeated + start. */ +} i2c_slave_transfer_t; + +/*! @brief I2C slave transfer callback typedef. */ +typedef void (*i2c_slave_transfer_callback_t)(I2C_Type *base, i2c_slave_transfer_t *xfer, void *userData); + +/*! @brief I2C slave handle structure. */ +struct _i2c_slave_handle +{ + volatile bool isBusy; /*!< Indicates whether a transfer is busy. */ + i2c_slave_transfer_t transfer; /*!< I2C slave transfer copy. */ + uint32_t eventMask; /*!< A mask of enabled events. */ + i2c_slave_transfer_callback_t callback; /*!< A callback function called at the transfer event. */ + void *userData; /*!< A callback parameter passed to the callback. */ +}; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /*_cplusplus. */ + +/*! + * @name Initialization and deinitialization + * @{ + */ + +/*! + * @brief Initializes the I2C peripheral. Call this API to ungate the I2C clock + * and configure the I2C with master configuration. + * + * @note This API should be called at the beginning of the application. + * Otherwise, any operation to the I2C module can cause a hard fault + * because the clock is not enabled. The configuration structure can be custom filled + * or it can be set with default values by using the I2C_MasterGetDefaultConfig(). + * After calling this API, the master is ready to transfer. + * This is an example. + * @code + * i2c_master_config_t config = { + * .enableMaster = true, + * .enableStopHold = false, + * .highDrive = false, + * .baudRate_Bps = 100000, + * .glitchFilterWidth = 0 + * }; + * I2C_MasterInit(I2C0, &config, 12000000U); + * @endcode + * + * @param base I2C base pointer + * @param masterConfig A pointer to the master configuration structure + * @param srcClock_Hz I2C peripheral clock frequency in Hz + */ +void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uint32_t srcClock_Hz); + +/*! + * @brief Initializes the I2C peripheral. Call this API to ungate the I2C clock + * and initialize the I2C with the slave configuration. + * + * @note This API should be called at the beginning of the application. + * Otherwise, any operation to the I2C module can cause a hard fault + * because the clock is not enabled. The configuration structure can partly be set + * with default values by I2C_SlaveGetDefaultConfig() or it can be custom filled by the user. + * This is an example. + * @code + * i2c_slave_config_t config = { + * .enableSlave = true, + * .enableGeneralCall = false, + * .addressingMode = kI2C_Address7bit, + * .slaveAddress = 0x1DU, + * .enableWakeUp = false, + * .enablehighDrive = false, + * .enableBaudRateCtl = false, + * .sclStopHoldTime_ns = 4000 + * }; + * I2C_SlaveInit(I2C0, &config, 12000000U); + * @endcode + * + * @param base I2C base pointer + * @param slaveConfig A pointer to the slave configuration structure + * @param srcClock_Hz I2C peripheral clock frequency in Hz + */ +void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig, uint32_t srcClock_Hz); + +/*! + * @brief De-initializes the I2C master peripheral. Call this API to gate the I2C clock. + * The I2C master module can't work unless the I2C_MasterInit is called. + * @param base I2C base pointer + */ +void I2C_MasterDeinit(I2C_Type *base); + +/*! + * @brief De-initializes the I2C slave peripheral. Calling this API gates the I2C clock. + * The I2C slave module can't work unless the I2C_SlaveInit is called to enable the clock. + * @param base I2C base pointer + */ +void I2C_SlaveDeinit(I2C_Type *base); + +/*! + * @brief Get instance number for I2C module. + * + * @param base I2C peripheral base address. + */ +uint32_t I2C_GetInstance(I2C_Type *base); + +/*! + * @brief Sets the I2C master configuration structure to default values. + * + * The purpose of this API is to get the configuration structure initialized for use in the I2C_MasterConfigure(). + * Use the initialized structure unchanged in the I2C_MasterConfigure() or modify + * the structure before calling the I2C_MasterConfigure(). + * This is an example. + * @code + * i2c_master_config_t config; + * I2C_MasterGetDefaultConfig(&config); + * @endcode + * @param masterConfig A pointer to the master configuration structure. + */ +void I2C_MasterGetDefaultConfig(i2c_master_config_t *masterConfig); + +/*! + * @brief Sets the I2C slave configuration structure to default values. + * + * The purpose of this API is to get the configuration structure initialized for use in the I2C_SlaveConfigure(). + * Modify fields of the structure before calling the I2C_SlaveConfigure(). + * This is an example. + * @code + * i2c_slave_config_t config; + * I2C_SlaveGetDefaultConfig(&config); + * @endcode + * @param slaveConfig A pointer to the slave configuration structure. + */ +void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig); + +/*! + * @brief Enables or disables the I2C peripheral operation. + * + * @param base I2C base pointer + * @param enable Pass true to enable and false to disable the module. + */ +static inline void I2C_Enable(I2C_Type *base, bool enable) +{ + if (enable) + { + base->C1 |= I2C_C1_IICEN_MASK; + } + else + { + base->C1 &= ~(uint8_t)I2C_C1_IICEN_MASK; + } +} + +/* @} */ + +/*! + * @name Status + * @{ + */ + +/*! + * @brief Gets the I2C status flags. + * + * @param base I2C base pointer + * @return status flag, use status flag to AND #_i2c_flags to get the related status. + */ +uint32_t I2C_MasterGetStatusFlags(I2C_Type *base); + +/*! + * @brief Gets the I2C status flags. + * + * @param base I2C base pointer + * @return status flag, use status flag to AND #_i2c_flags to get the related status. + */ +static inline uint32_t I2C_SlaveGetStatusFlags(I2C_Type *base) +{ + return I2C_MasterGetStatusFlags(base); +} + +/*! + * @brief Clears the I2C status flag state. + * + * The following status register flags can be cleared kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag. + * + * @param base I2C base pointer + * @param statusMask The status flag mask, defined in type i2c_status_flag_t. + * The parameter can be any combination of the following values: + * @arg kI2C_StartDetectFlag (if available) + * @arg kI2C_StopDetectFlag (if available) + * @arg kI2C_ArbitrationLostFlag + * @arg kI2C_IntPendingFlagFlag + */ +static inline void I2C_MasterClearStatusFlags(I2C_Type *base, uint32_t statusMask) +{ +/* Must clear the STARTF / STOPF bits prior to clearing IICIF */ +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + if ((uint32_t)kI2C_StartDetectFlag == (statusMask & (uint32_t)kI2C_StartDetectFlag)) + { + /* Shift the odd-ball flags back into place. */ + base->FLT |= (uint8_t)(statusMask >> 8U); + } +#endif + +#ifdef I2C_HAS_STOP_DETECT + if ((uint32_t)kI2C_StopDetectFlag == (statusMask & (uint32_t)kI2C_StopDetectFlag)) + { + /* Shift the odd-ball flags back into place. */ + base->FLT |= (uint8_t)(statusMask >> 8U); + } +#endif + + base->S = (uint8_t)statusMask; +} + +/*! + * @brief Clears the I2C status flag state. + * + * The following status register flags can be cleared kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag + * + * @param base I2C base pointer + * @param statusMask The status flag mask, defined in type i2c_status_flag_t. + * The parameter can be any combination of the following values: + * @arg kI2C_StartDetectFlag (if available) + * @arg kI2C_StopDetectFlag (if available) + * @arg kI2C_ArbitrationLostFlag + * @arg kI2C_IntPendingFlagFlag + */ +static inline void I2C_SlaveClearStatusFlags(I2C_Type *base, uint32_t statusMask) +{ + I2C_MasterClearStatusFlags(base, statusMask); +} + +/* @} */ + +/*! + * @name Interrupts + * @{ + */ + +/*! + * @brief Enables I2C interrupt requests. + * + * @param base I2C base pointer + * @param mask interrupt source + * The parameter can be combination of the following source if defined: + * @arg kI2C_GlobalInterruptEnable + * @arg kI2C_StopDetectInterruptEnable/kI2C_StartDetectInterruptEnable + * @arg kI2C_SdaTimeoutInterruptEnable + */ +void I2C_EnableInterrupts(I2C_Type *base, uint32_t mask); + +/*! + * @brief Disables I2C interrupt requests. + * + * @param base I2C base pointer + * @param mask interrupt source + * The parameter can be combination of the following source if defined: + * @arg kI2C_GlobalInterruptEnable + * @arg kI2C_StopDetectInterruptEnable/kI2C_StartDetectInterruptEnable + * @arg kI2C_SdaTimeoutInterruptEnable + */ +void I2C_DisableInterrupts(I2C_Type *base, uint32_t mask); + +/*! + * @name DMA Control + * @{ + */ +#if defined(FSL_FEATURE_I2C_HAS_DMA_SUPPORT) && FSL_FEATURE_I2C_HAS_DMA_SUPPORT +/*! + * @brief Enables/disables the I2C DMA interrupt. + * + * @param base I2C base pointer + * @param enable true to enable, false to disable + */ +static inline void I2C_EnableDMA(I2C_Type *base, bool enable) +{ + if (enable) + { + base->C1 |= I2C_C1_DMAEN_MASK; + } + else + { + base->C1 &= ~(uint8_t)I2C_C1_DMAEN_MASK; + } +} + +#endif /* FSL_FEATURE_I2C_HAS_DMA_SUPPORT */ + +/*! + * @brief Gets the I2C tx/rx data register address. This API is used to provide a transfer address + * for I2C DMA transfer configuration. + * + * @param base I2C base pointer + * @return data register address + */ +static inline uint32_t I2C_GetDataRegAddr(I2C_Type *base) +{ + return (uint32_t)(&(base->D)); +} + +/* @} */ +/*! + * @name Bus Operations + * @{ + */ + +/*! + * @brief Sets the I2C master transfer baud rate. + * + * @param base I2C base pointer + * @param baudRate_Bps the baud rate value in bps + * @param srcClock_Hz Source clock + */ +void I2C_MasterSetBaudRate(I2C_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz); + +/*! + * @brief Sends a START on the I2C bus. + * + * This function is used to initiate a new master mode transfer by sending the START signal. + * The slave address is sent following the I2C START signal. + * + * @param base I2C peripheral base pointer + * @param address 7-bit slave device address. + * @param direction Master transfer directions(transmit/receive). + * @retval kStatus_Success Successfully send the start signal. + * @retval kStatus_I2C_Busy Current bus is busy. + */ +status_t I2C_MasterStart(I2C_Type *base, uint8_t address, i2c_direction_t direction); + +/*! + * @brief Sends a STOP signal on the I2C bus. + * + * @retval kStatus_Success Successfully send the stop signal. + * @retval kStatus_I2C_Timeout Send stop signal failed, timeout. + */ +status_t I2C_MasterStop(I2C_Type *base); + +/*! + * @brief Sends a REPEATED START on the I2C bus. + * + * @param base I2C peripheral base pointer + * @param address 7-bit slave device address. + * @param direction Master transfer directions(transmit/receive). + * @retval kStatus_Success Successfully send the start signal. + * @retval kStatus_I2C_Busy Current bus is busy but not occupied by current I2C master. + */ +status_t I2C_MasterRepeatedStart(I2C_Type *base, uint8_t address, i2c_direction_t direction); + +/*! + * @brief Performs a polling send transaction on the I2C bus. + * + * @param base The I2C peripheral base pointer. + * @param txBuff The pointer to the data to be transferred. + * @param txSize The length in bytes of the data to be transferred. + * @param flags Transfer control flag to decide whether need to send a stop, use kI2C_TransferDefaultFlag + * to issue a stop and kI2C_TransferNoStop to not send a stop. + * @retval kStatus_Success Successfully complete the data transmission. + * @retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost. + * @retval kStataus_I2C_Nak Transfer error, receive NAK during transfer. + */ +status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize, uint32_t flags); + +/*! + * @brief Performs a polling receive transaction on the I2C bus. + * + * @note The I2C_MasterReadBlocking function stops the bus before reading the final byte. + * Without stopping the bus prior for the final read, the bus issues another read, resulting + * in garbage data being read into the data register. + * + * @param base I2C peripheral base pointer. + * @param rxBuff The pointer to the data to store the received data. + * @param rxSize The length in bytes of the data to be received. + * @param flags Transfer control flag to decide whether need to send a stop, use kI2C_TransferDefaultFlag + * to issue a stop and kI2C_TransferNoStop to not send a stop. + * @retval kStatus_Success Successfully complete the data transmission. + * @retval kStatus_I2C_Timeout Send stop signal failed, timeout. + */ +status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize, uint32_t flags); + +/*! + * @brief Performs a polling send transaction on the I2C bus. + * + * @param base The I2C peripheral base pointer. + * @param txBuff The pointer to the data to be transferred. + * @param txSize The length in bytes of the data to be transferred. + * @retval kStatus_Success Successfully complete the data transmission. + * @retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost. + * @retval kStataus_I2C_Nak Transfer error, receive NAK during transfer. + */ +status_t I2C_SlaveWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize); + +/*! + * @brief Performs a polling receive transaction on the I2C bus. + * + * @param base I2C peripheral base pointer. + * @param rxBuff The pointer to the data to store the received data. + * @param rxSize The length in bytes of the data to be received. + * @retval kStatus_Success Successfully complete data receive. + * @retval kStatus_I2C_Timeout Wait status flag timeout. + */ +status_t I2C_SlaveReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize); + +/*! + * @brief Performs a master polling transfer on the I2C bus. + * + * @note The API does not return until the transfer succeeds or fails due + * to arbitration lost or receiving a NAK. + * + * @param base I2C peripheral base address. + * @param xfer Pointer to the transfer structure. + * @retval kStatus_Success Successfully complete the data transmission. + * @retval kStatus_I2C_Busy Previous transmission still not finished. + * @retval kStatus_I2C_Timeout Transfer error, wait signal timeout. + * @retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost. + * @retval kStataus_I2C_Nak Transfer error, receive NAK during transfer. + */ +status_t I2C_MasterTransferBlocking(I2C_Type *base, i2c_master_transfer_t *xfer); + +/* @} */ + +/*! + * @name Transactional + * @{ + */ + +/*! + * @brief Initializes the I2C handle which is used in transactional functions. + * + * @param base I2C base pointer. + * @param handle pointer to i2c_master_handle_t structure to store the transfer state. + * @param callback pointer to user callback function. + * @param userData user parameter passed to the callback function. + */ +void I2C_MasterTransferCreateHandle(I2C_Type *base, + i2c_master_handle_t *handle, + i2c_master_transfer_callback_t callback, + void *userData); + +/*! + * @brief Performs a master interrupt non-blocking transfer on the I2C bus. + * + * @note Calling the API returns immediately after transfer initiates. The user needs + * to call I2C_MasterGetTransferCount to poll the transfer status to check whether + * the transfer is finished. If the return status is not kStatus_I2C_Busy, the transfer + * is finished. + * + * @param base I2C base pointer. + * @param handle pointer to i2c_master_handle_t structure which stores the transfer state. + * @param xfer pointer to i2c_master_transfer_t structure. + * @retval kStatus_Success Successfully start the data transmission. + * @retval kStatus_I2C_Busy Previous transmission still not finished. + * @retval kStatus_I2C_Timeout Transfer error, wait signal timeout. + */ +status_t I2C_MasterTransferNonBlocking(I2C_Type *base, i2c_master_handle_t *handle, i2c_master_transfer_t *xfer); + +/*! + * @brief Gets the master transfer status during a interrupt non-blocking transfer. + * + * @param base I2C base pointer. + * @param handle pointer to i2c_master_handle_t structure which stores the transfer state. + * @param count Number of bytes transferred so far by the non-blocking transaction. + * @retval kStatus_InvalidArgument count is Invalid. + * @retval kStatus_Success Successfully return the count. + */ +status_t I2C_MasterTransferGetCount(I2C_Type *base, i2c_master_handle_t *handle, size_t *count); + +/*! + * @brief Aborts an interrupt non-blocking transfer early. + * + * @note This API can be called at any time when an interrupt non-blocking transfer initiates + * to abort the transfer early. + * + * @param base I2C base pointer. + * @param handle pointer to i2c_master_handle_t structure which stores the transfer state + * @retval kStatus_I2C_Timeout Timeout during polling flag. + * @retval kStatus_Success Successfully abort the transfer. + */ +status_t I2C_MasterTransferAbort(I2C_Type *base, i2c_master_handle_t *handle); + +/*! + * @brief Master interrupt handler. + * + * @param base I2C base pointer. + * @param i2cHandle pointer to i2c_master_handle_t structure. + */ +void I2C_MasterTransferHandleIRQ(I2C_Type *base, void *i2cHandle); + +/*! + * @brief Initializes the I2C handle which is used in transactional functions. + * + * @param base I2C base pointer. + * @param handle pointer to i2c_slave_handle_t structure to store the transfer state. + * @param callback pointer to user callback function. + * @param userData user parameter passed to the callback function. + */ +void I2C_SlaveTransferCreateHandle(I2C_Type *base, + i2c_slave_handle_t *handle, + i2c_slave_transfer_callback_t callback, + void *userData); + +/*! + * @brief Starts accepting slave transfers. + * + * Call this API after calling the I2C_SlaveInit() and I2C_SlaveTransferCreateHandle() to start processing + * transactions driven by an I2C master. The slave monitors the I2C bus and passes events to the + * callback that was passed into the call to I2C_SlaveTransferCreateHandle(). The callback is always invoked + * from the interrupt context. + * + * The set of events received by the callback is customizable. To do so, set the @a eventMask parameter to + * the OR'd combination of #i2c_slave_transfer_event_t enumerators for the events you wish to receive. + * The #kI2C_SlaveTransmitEvent and #kLPI2C_SlaveReceiveEvent events are always enabled and do not need + * to be included in the mask. Alternatively, pass 0 to get a default set of only the transmit and + * receive events that are always enabled. In addition, the #kI2C_SlaveAllEvents constant is provided as + * a convenient way to enable all events. + * + * @param base The I2C peripheral base address. + * @param handle Pointer to #i2c_slave_handle_t structure which stores the transfer state. + * @param eventMask Bit mask formed by OR'ing together #i2c_slave_transfer_event_t enumerators to specify + * which events to send to the callback. Other accepted values are 0 to get a default set of + * only the transmit and receive events, and #kI2C_SlaveAllEvents to enable all events. + * + * @retval #kStatus_Success Slave transfers were successfully started. + * @retval #kStatus_I2C_Busy Slave transfers have already been started on this handle. + */ +status_t I2C_SlaveTransferNonBlocking(I2C_Type *base, i2c_slave_handle_t *handle, uint32_t eventMask); + +/*! + * @brief Aborts the slave transfer. + * + * @note This API can be called at any time to stop slave for handling the bus events. + * + * @param base I2C base pointer. + * @param handle pointer to i2c_slave_handle_t structure which stores the transfer state. + */ +void I2C_SlaveTransferAbort(I2C_Type *base, i2c_slave_handle_t *handle); + +/*! + * @brief Gets the slave transfer remaining bytes during a interrupt non-blocking transfer. + * + * @param base I2C base pointer. + * @param handle pointer to i2c_slave_handle_t structure. + * @param count Number of bytes transferred so far by the non-blocking transaction. + * @retval kStatus_InvalidArgument count is Invalid. + * @retval kStatus_Success Successfully return the count. + */ +status_t I2C_SlaveTransferGetCount(I2C_Type *base, i2c_slave_handle_t *handle, size_t *count); + +/*! + * @brief Slave interrupt handler. + * + * @param base I2C base pointer. + * @param i2cHandle pointer to i2c_slave_handle_t structure which stores the transfer state + */ +void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle); + +/* @} */ +#if defined(__cplusplus) +} +#endif /*_cplusplus. */ +/*@}*/ + +#endif /* _FSL_I2C_H_*/ diff --git a/source/hic_hal/freescale/kl27z/fsl_i2c_mod.c b/source/hic_hal/freescale/kl27z/fsl_i2c_mod.c new file mode 100644 index 000000000..7e7eaa323 --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_i2c_mod.c @@ -0,0 +1,2407 @@ +/* This is a modification of the default fsl_i2c.c driver. + * + * Needed in order to be able to identify slave address that triggered the + * kI2C_SlaveAddressMatchEvent from an address range configuration. + * Address is saved the i2c slave hanlder user data pointer, which is passed + * to the interrupt handler callback from the i2c_slave.c. + */ + +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "fsl_i2c.h" +#include "fsl_clock.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.i2c" +#endif + +/*! @brief i2c transfer state. */ +enum _i2c_transfer_states +{ + kIdleState = 0x0U, /*!< I2C bus idle. */ + kCheckAddressState = 0x1U, /*!< 7-bit address check state. */ + kSendCommandState = 0x2U, /*!< Send command byte phase. */ + kSendDataState = 0x3U, /*!< Send data transfer phase. */ + kReceiveDataBeginState = 0x4U, /*!< Receive data transfer phase begin. */ + kReceiveDataState = 0x5U, /*!< Receive data transfer phase. */ +}; + +/*! @brief Common sets of flags used by the driver. */ +enum _i2c_flag_constants +{ +/*! All flags which are cleared by the driver upon starting a transfer. */ +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + kClearFlags = kI2C_ArbitrationLostFlag | kI2C_IntPendingFlag | kI2C_StartDetectFlag | kI2C_StopDetectFlag, + kIrqFlags = kI2C_GlobalInterruptEnable | kI2C_StartStopDetectInterruptEnable, +#elif defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT + kClearFlags = kI2C_ArbitrationLostFlag | kI2C_IntPendingFlag | kI2C_StopDetectFlag, + kIrqFlags = kI2C_GlobalInterruptEnable | kI2C_StopDetectInterruptEnable, +#else + kClearFlags = kI2C_ArbitrationLostFlag | kI2C_IntPendingFlag, + kIrqFlags = kI2C_GlobalInterruptEnable, +#endif + +}; + +/*! @brief Typedef for interrupt handler. */ +typedef void (*i2c_isr_t)(I2C_Type *base, void *i2cHandle); + +/*! @brief static variable to keep current configured baudrate. */ +#if defined(I2C_MASTER_FACK_CONTROL) && I2C_MASTER_FACK_CONTROL +static uint32_t g_baudrate = 100000; +#endif + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief Set SCL/SDA hold time, this API receives SCL stop hold time, calculate the + * closest SCL divider and MULT value for the SDA hold time, SCL start and SCL stop + * hold time. To reduce the ROM size, SDA/SCL hold value mapping table is not provided, + * assume SCL divider = SCL stop hold value *2 to get the closest SCL divider value and MULT + * value, then the related SDA hold time, SCL start and SCL stop hold time is used. + * + * @param base I2C peripheral base address. + * @param sourceClock_Hz I2C functional clock frequency in Hertz. + * @param sclStopHoldTime_ns SCL stop hold time in ns. + */ +static void I2C_SetHoldTime(I2C_Type *base, uint32_t sclStopHoldTime_ns, uint32_t sourceClock_Hz); + +/*! + * @brief Set up master transfer, send slave address and decide the initial + * transfer state. + * + * @param base I2C peripheral base address. + * @param handle pointer to i2c_master_handle_t structure which stores the transfer state. + * @param xfer pointer to i2c_master_transfer_t structure. + */ +static status_t I2C_InitTransferStateMachine(I2C_Type *base, i2c_master_handle_t *handle, i2c_master_transfer_t *xfer); + +/*! + * @brief Check and clear status operation. + * + * @param base I2C peripheral base address. + * @param status current i2c hardware status. + * @retval kStatus_Success No error found. + * @retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost. + * @retval kStatus_I2C_Nak Received Nak error. + */ +static status_t I2C_CheckAndClearError(I2C_Type *base, uint32_t status); + +/*! + * @brief Master run transfer state machine to perform a byte of transfer. + * + * @param base I2C peripheral base address. + * @param handle pointer to i2c_master_handle_t structure which stores the transfer state + * @param isDone input param to get whether the thing is done, true is done + * @retval kStatus_Success No error found. + * @retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost. + * @retval kStatus_I2C_Nak Received Nak error. + * @retval kStatus_I2C_Timeout Transfer error, wait signal timeout. + */ +static status_t I2C_MasterTransferRunStateMachine(I2C_Type *base, i2c_master_handle_t *handle, bool *isDone); + +/*! + * @brief I2C common interrupt handler. + * + * @param base I2C peripheral base address. + * @param handle pointer to i2c_master_handle_t structure which stores the transfer state + */ +static void I2C_TransferCommonIRQHandler(I2C_Type *base, void *handle); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/*! @brief Pointers to i2c handles for each instance. */ +static void *s_i2cHandle[FSL_FEATURE_SOC_I2C_COUNT]; + +/*! @brief SCL clock divider used to calculate baudrate. */ +static const uint16_t s_i2cDividerTable[] = { + 20, 22, 24, 26, 28, 30, 34, 40, 28, 32, 36, 40, 44, 48, 56, 68, + 48, 56, 64, 72, 80, 88, 104, 128, 80, 96, 112, 128, 144, 160, 192, 240, + 160, 192, 224, 256, 288, 320, 384, 480, 320, 384, 448, 512, 576, 640, 768, 960, + 640, 768, 896, 1024, 1152, 1280, 1536, 1920, 1280, 1536, 1792, 2048, 2304, 2560, 3072, 3840}; + +/*! @brief Pointers to i2c IRQ number for each instance. */ +static const IRQn_Type s_i2cIrqs[] = I2C_IRQS; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Pointers to i2c clocks for each instance. */ +static const clock_ip_name_t s_i2cClocks[] = I2C_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/*! @brief Pointer to master IRQ handler for each instance. */ +static i2c_isr_t s_i2cMasterIsr; + +/*! @brief Pointer to slave IRQ handler for each instance. */ +static i2c_isr_t s_i2cSlaveIsr; + +/*! @brief Pointers to i2c bases for each instance. */ +static I2C_Type *const s_i2cBases[] = I2C_BASE_PTRS; +/******************************************************************************* + * Codes + ******************************************************************************/ + +/*! + * brief Get instance number for I2C module. + * + * param base I2C peripheral base address. + */ +uint32_t I2C_GetInstance(I2C_Type *base) +{ + uint32_t instance; + + /* Find the instance index from base address mappings. */ + for (instance = 0; instance < ARRAY_SIZE(s_i2cBases); instance++) + { + if (s_i2cBases[instance] == base) + { + break; + } + } + + assert(instance < ARRAY_SIZE(s_i2cBases)); + + return instance; +} + +static void I2C_SetHoldTime(I2C_Type *base, uint32_t sclStopHoldTime_ns, uint32_t sourceClock_Hz) +{ + uint32_t multiplier; + uint32_t computedSclHoldTime; + uint32_t absError; + uint32_t bestError = UINT32_MAX; + uint32_t bestMult = 0u; + uint32_t bestIcr = 0u; + uint32_t u32flag = 1u; + uint8_t mult; + uint8_t i; + + /* Search for the settings with the lowest error. Mult is the MULT field of the I2C_F register, + * and ranges from 0-2. It selects the multiplier factor for the divider. */ + /* SDA hold time = bus period (s) * mul * SDA hold value. */ + /* SCL start hold time = bus period (s) * mul * SCL start hold value. */ + /* SCL stop hold time = bus period (s) * mul * SCL stop hold value. */ + + for (mult = 0u; (mult <= 2u) && (bestError != 0u); ++mult) + { + multiplier = u32flag << mult; + + /* Scan table to find best match. */ + for (i = 0u; i < sizeof(s_i2cDividerTable) / sizeof(s_i2cDividerTable[0]); ++i) + { + /* Assume SCL hold(stop) value = s_i2cDividerTable[i]/2. */ + computedSclHoldTime = ((multiplier * s_i2cDividerTable[i]) * 500000U) / (sourceClock_Hz / 1000U); + absError = sclStopHoldTime_ns > computedSclHoldTime ? (sclStopHoldTime_ns - computedSclHoldTime) : + (computedSclHoldTime - sclStopHoldTime_ns); + + if (absError < bestError) + { + bestMult = mult; + bestIcr = i; + bestError = absError; + + /* If the error is 0, then we can stop searching because we won't find a better match. */ + if (absError == 0u) + { + break; + } + } + } + } + + /* Set frequency register based on best settings. */ + base->F = I2C_F_MULT(bestMult) | I2C_F_ICR(bestIcr); +} + +static status_t I2C_InitTransferStateMachine(I2C_Type *base, i2c_master_handle_t *handle, i2c_master_transfer_t *xfer) +{ + status_t result = kStatus_Success; + i2c_direction_t direction = xfer->direction; + + /* Initialize the handle transfer information. */ + handle->transfer = *xfer; + + /* Save total transfer size. */ + handle->transferSize = xfer->dataSize; + + /* Initial transfer state. */ + if (handle->transfer.subaddressSize > 0u) + { + if (xfer->direction == kI2C_Read) + { + direction = kI2C_Write; + } + } + + handle->state = (uint8_t)kCheckAddressState; + + /* Clear all status before transfer. */ + I2C_MasterClearStatusFlags(base, (uint32_t)kClearFlags); + + /* Handle no start option. */ + if (0U != (handle->transfer.flags & (uint32_t)kI2C_TransferNoStartFlag)) + { + /* No need to send start flag, directly go to send command or data */ + if (handle->transfer.subaddressSize > 0u) + { + handle->state = (uint8_t)kSendCommandState; + } + else + { + if (direction == kI2C_Write) + { + /* Next state, send data. */ + handle->state = (uint8_t)kSendDataState; + } + else + { + /* Only support write with no stop signal. */ + return kStatus_InvalidArgument; + } + } + + /* Wait for TCF bit and manually trigger tx interrupt. */ + while (0U == (base->S & (uint8_t)kI2C_TransferCompleteFlag)) + { + } + I2C_MasterTransferHandleIRQ(base, handle); + } + /* If repeated start is requested, send repeated start. */ + else if (0U != (handle->transfer.flags & (uint32_t)kI2C_TransferRepeatedStartFlag)) + { + result = I2C_MasterRepeatedStart(base, handle->transfer.slaveAddress, direction); + } + else /* For normal transfer, send start. */ + { + result = I2C_MasterStart(base, handle->transfer.slaveAddress, direction); + } + + return result; +} + +static status_t I2C_CheckAndClearError(I2C_Type *base, uint32_t status) +{ + status_t result = kStatus_Success; + + /* Check arbitration lost. */ + if (0U != (status & (uint32_t)kI2C_ArbitrationLostFlag)) + { + /* Clear arbitration lost flag. */ + base->S = (uint8_t)kI2C_ArbitrationLostFlag; + result = kStatus_I2C_ArbitrationLost; + } + /* Check NAK */ + else if (0U != (status & (uint32_t)kI2C_ReceiveNakFlag)) + { + result = kStatus_I2C_Nak; + } + else + { + } + + return result; +} + +static status_t I2C_MasterTransferRunStateMachine(I2C_Type *base, i2c_master_handle_t *handle, bool *isDone) +{ + status_t result = kStatus_Success; + uint32_t statusFlags = base->S; + *isDone = false; + volatile uint8_t dummy = 0; + uint32_t tmpDataSize = handle->transfer.dataSize; + bool ignoreNak = ((handle->state == (uint8_t)kSendDataState) && (tmpDataSize == 0U)) || + ((handle->state == (uint8_t)kReceiveDataState) && (tmpDataSize == 1U)); + + /* Add this to avoid build warning. */ + dummy++; + + /* Check & clear error flags. */ + result = I2C_CheckAndClearError(base, statusFlags); + + /* Ignore Nak when it's appeared for last byte. */ + if ((result == kStatus_I2C_Nak) && ignoreNak) + { + result = kStatus_Success; + } + + /* Handle Check address state to check the slave address is Acked in slave + probe application. */ + if (handle->state == (uint8_t)kCheckAddressState) + { + if (0U != (statusFlags & (uint8_t)kI2C_ReceiveNakFlag)) + { + result = kStatus_I2C_Addr_Nak; + } + else + { + if (handle->transfer.subaddressSize > 0U) + { + handle->state = (uint8_t)kSendCommandState; + } + else + { + if (handle->transfer.direction == kI2C_Write) + { + /* Next state, send data. */ + handle->state = (uint8_t)kSendDataState; + } + else + { + /* Next state, receive data begin. */ + handle->state = (uint8_t)kReceiveDataBeginState; + } + } + } + } + + if (0 != result) + { + return result; + } + + /* Run state machine. */ + switch (handle->state) + { + /* Send I2C command. */ + case (uint8_t)kSendCommandState: + if (0U != (handle->transfer.subaddressSize)) + { + handle->transfer.subaddressSize--; + base->D = (uint8_t)((handle->transfer.subaddress) >> (8U * handle->transfer.subaddressSize)); + } + else + { + if (handle->transfer.direction == kI2C_Write) + { + /* Send first byte of data. */ + if (handle->transfer.dataSize > 0U) + { + /* Next state, send data. */ + handle->state = (uint8_t)kSendDataState; + base->D = *handle->transfer.data; + handle->transfer.data++; + handle->transfer.dataSize--; + } + else + { + *isDone = true; + } + } + else + { + /* Send repeated start and slave address. */ + result = I2C_MasterRepeatedStart(base, handle->transfer.slaveAddress, kI2C_Read); + + /* Next state, receive data begin. */ + handle->state = (uint8_t)kReceiveDataBeginState; + } + } + break; + + /* Send I2C data. */ + case (uint8_t)kSendDataState: + /* Send one byte of data. */ + if (handle->transfer.dataSize > 0U) + { + base->D = *handle->transfer.data; + handle->transfer.data++; + handle->transfer.dataSize--; + } + else + { + *isDone = true; + } + break; + + /* Start I2C data receive. */ + case (uint8_t)kReceiveDataBeginState: + +#if defined(I2C_MASTER_FACK_CONTROL) && I2C_MASTER_FACK_CONTROL + base->SMB |= I2C_SMB_FACK_MASK; +#endif + + base->C1 &= ~(uint8_t)(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + + /* Read dummy to release the bus. */ + dummy = base->D; + + if (handle->transfer.dataSize == 1U) + { + /* Issue NACK on read. */ + base->C1 |= I2C_C1_TXAK_MASK; +#if defined(I2C_MASTER_FACK_CONTROL) && I2C_MASTER_FACK_CONTROL + base->SMB &= ~(uint8_t)I2C_SMB_FACK_MASK; +#endif + } + + /* Next state, receive data. */ + handle->state = (uint8_t)kReceiveDataState; + break; + + /* Receive I2C data. */ + case (uint8_t)kReceiveDataState: + /* Receive one byte of data. */ + if (0U != (handle->transfer.dataSize--)) + { + if (handle->transfer.dataSize == 0U) + { + *isDone = true; + + /* Send stop if kI2C_TransferNoStop is not asserted. */ + if (0U == (handle->transfer.flags & (uint32_t)kI2C_TransferNoStopFlag)) + { + result = I2C_MasterStop(base); + } + else + { + base->C1 |= I2C_C1_TX_MASK; + } + } + + /* Read the data byte into the transfer buffer. */ + *handle->transfer.data = base->D; + handle->transfer.data++; + +#if defined(I2C_MASTER_FACK_CONTROL) && I2C_MASTER_FACK_CONTROL + if (handle->transfer.dataSize != 0U) + { + /* Clear the TXAK flag. */ + base->C1 &= ~(uint8_t)I2C_C1_TXAK_MASK; + + for (uint32_t i = SystemCoreClock / (2U * g_baudrate); i > 0U; i--) + { + __NOP(); + } + + /* Do dummy read. */ + dummy = base->D; + } +#endif + if (handle->transfer.dataSize == 1U) + { + /* Issue NACK on read. */ + base->C1 |= I2C_C1_TXAK_MASK; +#if defined(I2C_MASTER_FACK_CONTROL) && I2C_MASTER_FACK_CONTROL + base->SMB &= ~(uint8_t)I2C_SMB_FACK_MASK; +#endif + } + } + + break; + + default: + break; + } + + return result; +} + +static void I2C_TransferCommonIRQHandler(I2C_Type *base, void *handle) +{ + uint8_t tmpS = base->S; + uint8_t tmpC1 = base->C1; + + /* Check if master interrupt. */ + if ((0U != (tmpC1 & I2C_C1_MST_MASK)) || (0U != (tmpS & (uint8_t)kI2C_ArbitrationLostFlag))) + { + s_i2cMasterIsr(base, handle); + } + else + { + s_i2cSlaveIsr(base, handle); + } + __DSB(); +} + +/*! + * brief Initializes the I2C peripheral. Call this API to ungate the I2C clock + * and configure the I2C with master configuration. + * + * note This API should be called at the beginning of the application. + * Otherwise, any operation to the I2C module can cause a hard fault + * because the clock is not enabled. The configuration structure can be custom filled + * or it can be set with default values by using the I2C_MasterGetDefaultConfig(). + * After calling this API, the master is ready to transfer. + * This is an example. + * code + * i2c_master_config_t config = { + * .enableMaster = true, + * .enableStopHold = false, + * .highDrive = false, + * .baudRate_Bps = 100000, + * .glitchFilterWidth = 0 + * }; + * I2C_MasterInit(I2C0, &config, 12000000U); + * endcode + * + * param base I2C base pointer + * param masterConfig A pointer to the master configuration structure + * param srcClock_Hz I2C peripheral clock frequency in Hz + */ +void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uint32_t srcClock_Hz) +{ + assert(NULL != masterConfig); + assert(0U != srcClock_Hz); + + /* Temporary register for filter read. */ + uint8_t fltReg; +#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE + uint8_t s2Reg; +#endif +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Enable I2C clock. */ + CLOCK_EnableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* Reset the module. */ + base->A1 = 0; + base->F = 0; + base->C1 = 0; + base->S = 0xFFU; + base->C2 = 0; +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + base->FLT = 0x50U; +#elif defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT + base->FLT = 0x40U; +#endif + base->RA = 0; + + /* Disable I2C prior to configuring it. */ + base->C1 &= ~(uint8_t)(I2C_C1_IICEN_MASK); + + /* Clear all flags. */ + I2C_MasterClearStatusFlags(base, (uint32_t)kClearFlags); + + /* Configure baud rate. */ + I2C_MasterSetBaudRate(base, masterConfig->baudRate_Bps, srcClock_Hz); + + /* Read out the FLT register. */ + fltReg = base->FLT; + +#if defined(FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF) && FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF + /* Configure the stop / hold enable. */ + fltReg &= ~(uint8_t)(I2C_FLT_SHEN_MASK); + fltReg |= I2C_FLT_SHEN(masterConfig->enableStopHold); +#endif + + /* Configure the glitch filter value. */ + fltReg &= ~(uint8_t)(I2C_FLT_FLT_MASK); + fltReg |= I2C_FLT_FLT(masterConfig->glitchFilterWidth); + + /* Write the register value back to the filter register. */ + base->FLT = fltReg; + +/* Enable/Disable double buffering. */ +#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE + s2Reg = (uint8_t)(base->S2 & (~I2C_S2_DFEN_MASK)); + base->S2 = s2Reg | I2C_S2_DFEN(masterConfig->enableDoubleBuffering); +#endif + + /* Enable the I2C peripheral based on the configuration. */ + base->C1 = I2C_C1_IICEN(masterConfig->enableMaster); +} + +/*! + * brief De-initializes the I2C master peripheral. Call this API to gate the I2C clock. + * The I2C master module can't work unless the I2C_MasterInit is called. + * param base I2C base pointer + */ +void I2C_MasterDeinit(I2C_Type *base) +{ + /* Disable I2C module. */ + I2C_Enable(base, false); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Disable I2C clock. */ + CLOCK_DisableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +/*! + * brief Sets the I2C master configuration structure to default values. + * + * The purpose of this API is to get the configuration structure initialized for use in the I2C_MasterConfigure(). + * Use the initialized structure unchanged in the I2C_MasterConfigure() or modify + * the structure before calling the I2C_MasterConfigure(). + * This is an example. + * code + * i2c_master_config_t config; + * I2C_MasterGetDefaultConfig(&config); + * endcode + * param masterConfig A pointer to the master configuration structure. + */ +void I2C_MasterGetDefaultConfig(i2c_master_config_t *masterConfig) +{ + assert(NULL != masterConfig); + + /* Initializes the configure structure to zero. */ + (void)memset(masterConfig, 0, sizeof(*masterConfig)); + + /* Default baud rate at 100kbps. */ + masterConfig->baudRate_Bps = 100000U; + +/* Default stop hold enable is disabled. */ +#if defined(FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF) && FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF + masterConfig->enableStopHold = false; +#endif + + /* Default glitch filter value is no filter. */ + masterConfig->glitchFilterWidth = 0U; + +/* Default enable double buffering. */ +#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE + masterConfig->enableDoubleBuffering = true; +#endif + + /* Enable the I2C peripheral. */ + masterConfig->enableMaster = true; +} + +/*! + * brief Enables I2C interrupt requests. + * + * param base I2C base pointer + * param mask interrupt source + * The parameter can be combination of the following source if defined: + * arg kI2C_GlobalInterruptEnable + * arg kI2C_StopDetectInterruptEnable/kI2C_StartDetectInterruptEnable + * arg kI2C_SdaTimeoutInterruptEnable + */ +void I2C_EnableInterrupts(I2C_Type *base, uint32_t mask) +{ +#ifdef I2C_HAS_STOP_DETECT + uint8_t fltReg; +#endif + + if (0U != (mask & (uint32_t)kI2C_GlobalInterruptEnable)) + { + base->C1 |= I2C_C1_IICIE_MASK; + } + +#if defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT + if (0U != (mask & (uint32_t)kI2C_StopDetectInterruptEnable)) + { + fltReg = base->FLT; + + /* Keep STOPF flag. */ + fltReg &= ~I2C_FLT_STOPF_MASK; + + /* Stop detect enable. */ + fltReg |= I2C_FLT_STOPIE_MASK; + base->FLT = fltReg; + } +#endif /* FSL_FEATURE_I2C_HAS_STOP_DETECT */ + +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + if (0U != (mask & (uint32_t)kI2C_StartStopDetectInterruptEnable)) + { + fltReg = base->FLT; + + /* Keep STARTF and STOPF flags. */ + fltReg &= ~(uint8_t)(I2C_FLT_STOPF_MASK | I2C_FLT_STARTF_MASK); + + /* Start and stop detect enable. */ + fltReg |= I2C_FLT_SSIE_MASK; + base->FLT = fltReg; + } +#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */ +} + +/*! + * brief Disables I2C interrupt requests. + * + * param base I2C base pointer + * param mask interrupt source + * The parameter can be combination of the following source if defined: + * arg kI2C_GlobalInterruptEnable + * arg kI2C_StopDetectInterruptEnable/kI2C_StartDetectInterruptEnable + * arg kI2C_SdaTimeoutInterruptEnable + */ +void I2C_DisableInterrupts(I2C_Type *base, uint32_t mask) +{ + if (0U != (mask & (uint32_t)kI2C_GlobalInterruptEnable)) + { + base->C1 &= ~(uint8_t)I2C_C1_IICIE_MASK; + } + +#if defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT + if (0U != (mask & (uint32_t)kI2C_StopDetectInterruptEnable)) + { + base->FLT &= ~(I2C_FLT_STOPIE_MASK | I2C_FLT_STOPF_MASK); + } +#endif /* FSL_FEATURE_I2C_HAS_STOP_DETECT */ + +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + if (0U != (mask & (uint32_t)kI2C_StartStopDetectInterruptEnable)) + { + base->FLT &= ~(uint8_t)(I2C_FLT_SSIE_MASK | I2C_FLT_STOPF_MASK | I2C_FLT_STARTF_MASK); + } +#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */ +} + +/*! + * brief Sets the I2C master transfer baud rate. + * + * param base I2C base pointer + * param baudRate_Bps the baud rate value in bps + * param srcClock_Hz Source clock + */ +void I2C_MasterSetBaudRate(I2C_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz) +{ + uint32_t multiplier; + uint32_t computedRate; + uint32_t absError; + uint32_t bestError = UINT32_MAX; + uint32_t bestMult = 0u; + uint32_t bestIcr = 0u; + uint32_t u32flag = 1u; + uint8_t mult; + uint8_t i; + + /* Search for the settings with the lowest error. Mult is the MULT field of the I2C_F register, + * and ranges from 0-2. It selects the multiplier factor for the divider. */ + for (mult = 0u; (mult <= 2u) && (bestError != 0u); ++mult) + { + multiplier = u32flag << mult; + + /* Scan table to find best match. */ + for (i = 0u; i < sizeof(s_i2cDividerTable) / sizeof(uint16_t); ++i) + { + computedRate = srcClock_Hz / (multiplier * s_i2cDividerTable[i]); + absError = baudRate_Bps > computedRate ? (baudRate_Bps - computedRate) : (computedRate - baudRate_Bps); + + if (absError < bestError) + { + bestMult = mult; + bestIcr = i; + bestError = absError; + + /* If the error is 0, then we can stop searching because we won't find a better match. */ + if (absError == 0u) + { + break; + } + } + } + } + +#if defined(I2C_MASTER_FACK_CONTROL) && I2C_MASTER_FACK_CONTROL + g_baudrate = baudRate_Bps; +#endif + /* Set frequency register based on best settings. */ + base->F = I2C_F_MULT(bestMult) | I2C_F_ICR(bestIcr); +} + +/*! + * brief Sends a START on the I2C bus. + * + * This function is used to initiate a new master mode transfer by sending the START signal. + * The slave address is sent following the I2C START signal. + * + * param base I2C peripheral base pointer + * param address 7-bit slave device address. + * param direction Master transfer directions(transmit/receive). + * retval kStatus_Success Successfully send the start signal. + * retval kStatus_I2C_Busy Current bus is busy. + */ +status_t I2C_MasterStart(I2C_Type *base, uint8_t address, i2c_direction_t direction) +{ + status_t result = kStatus_Success; + uint32_t statusFlags = I2C_MasterGetStatusFlags(base); + + /* Return an error if the bus is already in use. */ + if (0U != (statusFlags & (uint32_t)kI2C_BusBusyFlag)) + { + result = kStatus_I2C_Busy; + } + else + { + /* Send the START signal. */ + base->C1 |= I2C_C1_MST_MASK | I2C_C1_TX_MASK; + +#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING +#if I2C_WAIT_TIMEOUT + uint32_t waitTimes = I2C_WAIT_TIMEOUT; + while ((0U == (base->S2 & I2C_S2_EMPTY_MASK)) && (--waitTimes)) + { + } + if (waitTimes == 0) + { + return kStatus_I2C_Timeout; + } +#else + while (0U == (base->S2 & I2C_S2_EMPTY_MASK)) + { + } +#endif +#endif /* FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING */ + + base->D = (uint8_t)(((uint32_t)address) << 1U | ((direction == kI2C_Read) ? 1U : 0U)); + } + + return result; +} + +/*! + * brief Sends a REPEATED START on the I2C bus. + * + * param base I2C peripheral base pointer + * param address 7-bit slave device address. + * param direction Master transfer directions(transmit/receive). + * retval kStatus_Success Successfully send the start signal. + * retval kStatus_I2C_Busy Current bus is busy but not occupied by current I2C master. + */ +status_t I2C_MasterRepeatedStart(I2C_Type *base, uint8_t address, i2c_direction_t direction) +{ + status_t result = kStatus_Success; + uint8_t savedMult; + uint32_t statusFlags = I2C_MasterGetStatusFlags(base); + uint8_t timeDelay = 6; + + /* Return an error if the bus is already in use, but not by us. */ + if ((0U == (base->C1 & I2C_C1_MST_MASK)) && (0U != (statusFlags & (uint32_t)kI2C_BusBusyFlag))) + { + result = kStatus_I2C_Busy; + } + else + { + savedMult = base->F; + base->F = savedMult & (~(uint8_t)I2C_F_MULT_MASK); + + /* We are already in a transfer, so send a repeated start. */ + base->C1 |= I2C_C1_RSTA_MASK | I2C_C1_TX_MASK; + + /* Restore the multiplier factor. */ + base->F = savedMult; + + /* Add some delay to wait the Re-Start signal. */ + while (0U != (timeDelay--)) + { + __NOP(); + } + +#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING +#if I2C_WAIT_TIMEOUT + uint32_t waitTimes = I2C_WAIT_TIMEOUT; + while ((!(base->S2 & I2C_S2_EMPTY_MASK)) && (--waitTimes)) + { + } + if (waitTimes == 0) + { + return kStatus_I2C_Timeout; + } +#else + while (0U == (base->S2 & I2C_S2_EMPTY_MASK)) + { + } +#endif +#endif /* FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING */ + + base->D = (uint8_t)(((uint32_t)address) << 1U | ((direction == kI2C_Read) ? 1U : 0U)); + } + + return result; +} + +/*! + * brief Sends a STOP signal on the I2C bus. + * + * retval kStatus_Success Successfully send the stop signal. + * retval kStatus_I2C_Timeout Send stop signal failed, timeout. + */ +status_t I2C_MasterStop(I2C_Type *base) +{ + status_t result = kStatus_Success; + + /* Issue the STOP command on the bus. */ + base->C1 &= ~(uint8_t)(I2C_C1_MST_MASK | I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + +#if I2C_WAIT_TIMEOUT + uint32_t waitTimes = I2C_WAIT_TIMEOUT; + /* Wait until bus not busy. */ + while ((base->S & (uint8_t)kI2C_BusBusyFlag) && (--waitTimes)) + { + } + + if (waitTimes == 0) + { + result = kStatus_I2C_Timeout; + } +#else + /* Wait until data transfer complete. */ + while (0U != (base->S & (uint8_t)kI2C_BusBusyFlag)) + { + } +#endif + + return result; +} + +/*! + * brief Gets the I2C status flags. + * + * param base I2C base pointer + * return status flag, use status flag to AND #_i2c_flags to get the related status. + */ +uint32_t I2C_MasterGetStatusFlags(I2C_Type *base) +{ + uint32_t statusFlags = base->S; + +#ifdef I2C_HAS_STOP_DETECT + /* Look up the STOPF bit from the filter register. */ + if (0U != (base->FLT & I2C_FLT_STOPF_MASK)) + { + statusFlags |= (uint32_t)kI2C_StopDetectFlag; + } +#endif + +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + /* Look up the STARTF bit from the filter register. */ + if (0U != (base->FLT & I2C_FLT_STARTF_MASK)) + { + statusFlags |= (uint32_t)kI2C_StartDetectFlag; + } +#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */ + + return statusFlags; +} + +/*! + * brief Performs a polling send transaction on the I2C bus. + * + * param base The I2C peripheral base pointer. + * param txBuff The pointer to the data to be transferred. + * param txSize The length in bytes of the data to be transferred. + * param flags Transfer control flag to decide whether need to send a stop, use kI2C_TransferDefaultFlag + * to issue a stop and kI2C_TransferNoStop to not send a stop. + * retval kStatus_Success Successfully complete the data transmission. + * retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost. + * retval kStataus_I2C_Nak Transfer error, receive NAK during transfer. + */ +status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize, uint32_t flags) +{ + status_t result = kStatus_Success; + uint8_t statusFlags = 0; + +#if I2C_WAIT_TIMEOUT + uint32_t waitTimes = I2C_WAIT_TIMEOUT; + /* Wait until the data register is ready for transmit. */ + while ((!(base->S & kI2C_TransferCompleteFlag)) && (--waitTimes)) + { + } + if (waitTimes == 0) + { + return kStatus_I2C_Timeout; + } +#else + /* Wait until the data register is ready for transmit. */ + while (0U == (base->S & (uint8_t)kI2C_TransferCompleteFlag)) + { + } +#endif + + /* Clear the IICIF flag. */ + base->S = (uint8_t)kI2C_IntPendingFlag; + + /* Setup the I2C peripheral to transmit data. */ + base->C1 |= I2C_C1_TX_MASK; + + while (0U != (txSize--)) + { + /* Send a byte of data. */ + base->D = *txBuff++; + +#if I2C_WAIT_TIMEOUT + waitTimes = I2C_WAIT_TIMEOUT; + /* Wait until data transfer complete. */ + while ((!(base->S & kI2C_IntPendingFlag)) && (--waitTimes)) + { + } + if (waitTimes == 0) + { + return kStatus_I2C_Timeout; + } +#else + /* Wait until data transfer complete. */ + while (0U == (base->S & (uint8_t)kI2C_IntPendingFlag)) + { + } +#endif + statusFlags = base->S; + + /* Clear the IICIF flag. */ + base->S = (uint8_t)kI2C_IntPendingFlag; + + /* Check if arbitration lost or no acknowledgement (NAK), return failure status. */ + if (0U != (statusFlags & (uint8_t)kI2C_ArbitrationLostFlag)) + { + base->S = (uint8_t)kI2C_ArbitrationLostFlag; + result = kStatus_I2C_ArbitrationLost; + } + + if ((0U != (statusFlags & (uint8_t)kI2C_ReceiveNakFlag)) && (0U != txSize)) + { + base->S = (uint8_t)kI2C_ReceiveNakFlag; + result = kStatus_I2C_Nak; + } + + if (result != kStatus_Success) + { + /* Breaking out of the send loop. */ + break; + } + } + + if (((result == kStatus_Success) && (0U == (flags & (uint32_t)kI2C_TransferNoStopFlag))) || + (result == kStatus_I2C_Nak)) + { + /* Clear the IICIF flag. */ + base->S = (uint8_t)kI2C_IntPendingFlag; + + /* Send stop. */ + result = I2C_MasterStop(base); + } + + return result; +} + +/*! + * brief Performs a polling receive transaction on the I2C bus. + * + * note The I2C_MasterReadBlocking function stops the bus before reading the final byte. + * Without stopping the bus prior for the final read, the bus issues another read, resulting + * in garbage data being read into the data register. + * + * param base I2C peripheral base pointer. + * param rxBuff The pointer to the data to store the received data. + * param rxSize The length in bytes of the data to be received. + * param flags Transfer control flag to decide whether need to send a stop, use kI2C_TransferDefaultFlag + * to issue a stop and kI2C_TransferNoStop to not send a stop. + * retval kStatus_Success Successfully complete the data transmission. + * retval kStatus_I2C_Timeout Send stop signal failed, timeout. + */ +status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize, uint32_t flags) +{ + status_t result = kStatus_Success; + volatile uint8_t dummy = 0; + + /* Add this to avoid build warning. */ + dummy++; + +#if defined(I2C_MASTER_FACK_CONTROL) && I2C_MASTER_FACK_CONTROL + base->SMB |= I2C_SMB_FACK_MASK; +#endif + +#if I2C_WAIT_TIMEOUT + uint32_t waitTimes = I2C_WAIT_TIMEOUT; + /* Wait until the data register is ready for transmit. */ + while ((!(base->S & kI2C_TransferCompleteFlag)) && (--waitTimes)) + { + } + if (waitTimes == 0) + { + return kStatus_I2C_Timeout; + } +#else + /* Wait until the data register is ready for transmit. */ + while (0U == (base->S & (uint8_t)kI2C_TransferCompleteFlag)) + { + } +#endif + + /* Setup the I2C peripheral to receive data. */ + base->C1 &= ~(uint8_t)(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + + /* Do dummy read. */ + dummy = base->D; + + if (rxSize == 1U) + { + /* Issue NACK on read. */ + base->C1 |= I2C_C1_TXAK_MASK; +#if defined(I2C_MASTER_FACK_CONTROL) && I2C_MASTER_FACK_CONTROL + base->SMB &= ~(uint8_t)I2C_SMB_FACK_MASK; +#endif + } + + /* Clear the IICIF flag. */ + base->S = (uint8_t)kI2C_IntPendingFlag; + + while (0U != (rxSize--)) + { +#if I2C_WAIT_TIMEOUT + waitTimes = I2C_WAIT_TIMEOUT; + /* Wait until data transfer complete. */ + while ((0U == (base->S & (uint8_t)kI2C_IntPendingFlag)) && (--waitTimes)) + { + } + if (waitTimes == 0) + { + return kStatus_I2C_Timeout; + } +#else + /* Wait until data transfer complete. */ + while (0U == (base->S & (uint8_t)kI2C_IntPendingFlag)) + { + } +#endif + + if (rxSize == 0U) + { + if (0U == (flags & (uint32_t)kI2C_TransferNoStopFlag)) + { + /* Issue STOP command before reading last byte. */ + result = I2C_MasterStop(base); + } + else + { + /* Change direction to Tx to avoid extra clocks. */ + base->C1 |= I2C_C1_TX_MASK; + } + } + + /* Read from the data register. */ + *rxBuff++ = base->D; + +#if defined(I2C_MASTER_FACK_CONTROL) && I2C_MASTER_FACK_CONTROL + if (rxSize != 0U) + { + /* Clear the TXAK flag. */ + base->C1 &= ~(uint8_t)I2C_C1_TXAK_MASK; + + for (uint32_t i = (SystemCoreClock / (2U * g_baudrate)); i > 0U; i--) + { + __NOP(); + } + + /* Do dummy read. */ + dummy = base->D; + } +#endif + + if (rxSize == 1U) + { + base->C1 |= I2C_C1_TXAK_MASK; +#if defined(I2C_MASTER_FACK_CONTROL) && I2C_MASTER_FACK_CONTROL + /* Issue NACK on read. */ + base->SMB &= ~(uint8_t)I2C_SMB_FACK_MASK; +#endif + } + + /* Clear the IICIF flag. */ + base->S = (uint8_t)kI2C_IntPendingFlag; + } + + return result; +} + +/*! + * brief Performs a master polling transfer on the I2C bus. + * + * note The API does not return until the transfer succeeds or fails due + * to arbitration lost or receiving a NAK. + * + * param base I2C peripheral base address. + * param xfer Pointer to the transfer structure. + * retval kStatus_Success Successfully complete the data transmission. + * retval kStatus_I2C_Busy Previous transmission still not finished. + * retval kStatus_I2C_Timeout Transfer error, wait signal timeout. + * retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost. + * retval kStataus_I2C_Nak Transfer error, receive NAK during transfer. + */ +status_t I2C_MasterTransferBlocking(I2C_Type *base, i2c_master_transfer_t *xfer) +{ + assert(NULL != xfer); + + i2c_direction_t direction = xfer->direction; + status_t result = kStatus_Success; + + /* Clear all status before transfer. */ + I2C_MasterClearStatusFlags(base, (uint32_t)kClearFlags); + +#if I2C_WAIT_TIMEOUT + uint32_t waitTimes = I2C_WAIT_TIMEOUT; + /* Wait until the data register is ready for transmit. */ + while ((0U == (base->S & kI2C_TransferCompleteFlag)) && (0U != (--waitTimes))) + { + } + if (waitTimes == 0U) + { + return kStatus_I2C_Timeout; + } +#else + /* Wait until the data register is ready for transmit. */ + while (0U == (base->S & (uint8_t)kI2C_TransferCompleteFlag)) + { + } +#endif + + /* Change to send write address when it's a read operation with command. */ + if ((xfer->subaddressSize > 0U) && (xfer->direction == kI2C_Read)) + { + direction = kI2C_Write; + } + + /* Handle no start option, only support write with no start signal. */ + if (0U != (xfer->flags & (uint32_t)kI2C_TransferNoStartFlag)) + { + if (direction == kI2C_Read) + { + return kStatus_InvalidArgument; + } + } + /* If repeated start is requested, send repeated start. */ + else if (0U != (xfer->flags & (uint32_t)kI2C_TransferRepeatedStartFlag)) + { + result = I2C_MasterRepeatedStart(base, xfer->slaveAddress, direction); + } + else /* For normal transfer, send start. */ + { + result = I2C_MasterStart(base, xfer->slaveAddress, direction); + } + + if (0U == (xfer->flags & (uint32_t)kI2C_TransferNoStartFlag)) + { + /* Return if error. */ + if (0 != result) + { + return result; + } + +#if I2C_WAIT_TIMEOUT + waitTimes = I2C_WAIT_TIMEOUT; + /* Wait until data transfer complete. */ + while ((!(base->S & kI2C_IntPendingFlag)) && (--waitTimes)) + { + } + if (waitTimes == 0) + { + return kStatus_I2C_Timeout; + } +#else + /* Wait until data transfer complete. */ + while (0U == (base->S & (uint8_t)kI2C_IntPendingFlag)) + { + } +#endif + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + /* Return if error. */ + if (0 != result) + { + if (result == kStatus_I2C_Nak) + { + result = kStatus_I2C_Addr_Nak; + + (void)I2C_MasterStop(base); + } + + return result; + } + } + + /* Send subaddress. */ + if (0U != (xfer->subaddressSize)) + { + do + { + /* Clear interrupt pending flag. */ + base->S = (uint8_t)kI2C_IntPendingFlag; + + xfer->subaddressSize--; + base->D = (uint8_t)((xfer->subaddress) >> (8U * xfer->subaddressSize)); + +#if I2C_WAIT_TIMEOUT + waitTimes = I2C_WAIT_TIMEOUT; + /* Wait until data transfer complete. */ + while ((!(base->S & kI2C_IntPendingFlag)) && (--waitTimes)) + { + } + if (waitTimes == 0) + { + return kStatus_I2C_Timeout; + } +#else + /* Wait until data transfer complete. */ + while (0U == (base->S & (uint8_t)kI2C_IntPendingFlag)) + { + } +#endif + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + if (0 != result) + { + if (result == kStatus_I2C_Nak) + { + (void)I2C_MasterStop(base); + } + + return result; + } + + } while (xfer->subaddressSize > 0u); + + if (xfer->direction == kI2C_Read) + { + /* Clear pending flag. */ + base->S = (uint8_t)kI2C_IntPendingFlag; + + /* Send repeated start and slave address. */ + result = I2C_MasterRepeatedStart(base, xfer->slaveAddress, kI2C_Read); + + /* Return if error. */ + if (0 != result) + { + return result; + } + +#if I2C_WAIT_TIMEOUT + waitTimes = I2C_WAIT_TIMEOUT; + /* Wait until data transfer complete. */ + while ((!(base->S & kI2C_IntPendingFlag)) && (--waitTimes)) + { + } + if (waitTimes == 0) + { + return kStatus_I2C_Timeout; + } +#else + /* Wait until data transfer complete. */ + while (0U == (base->S & (uint8_t)kI2C_IntPendingFlag)) + { + } +#endif + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + if (0 != result) + { + if (result == kStatus_I2C_Nak) + { + result = kStatus_I2C_Addr_Nak; + + (void)I2C_MasterStop(base); + } + + return result; + } + } + } + + /* Transmit data. */ + if (xfer->direction == kI2C_Write) + { + if (xfer->dataSize > 0U) + { + uint8_t *tmpData = xfer->data; + size_t tmpDataSize = xfer->dataSize; + uint32_t tmpFlags = xfer->flags; + /* Send Data. */ + result = I2C_MasterWriteBlocking(base, tmpData, tmpDataSize, tmpFlags); + } + else if (0U == (xfer->flags & (uint32_t)kI2C_TransferNoStopFlag)) + { + /* Send stop. */ + result = I2C_MasterStop(base); + } + else + { + /* Add this to fix MISRA C2012 rule15.7 issue: Empty else without comment. */ + } + } + + /* Receive Data. */ + if ((xfer->dataSize > 0u) && (xfer->direction == kI2C_Read)) + { + uint8_t *tmpData = xfer->data; + size_t tmpDataSize = xfer->dataSize; + uint32_t tmpFlags = xfer->flags; + + result = I2C_MasterReadBlocking(base, tmpData, tmpDataSize, tmpFlags); + } + + return result; +} + +/*! + * brief Initializes the I2C handle which is used in transactional functions. + * + * param base I2C base pointer. + * param handle pointer to i2c_master_handle_t structure to store the transfer state. + * param callback pointer to user callback function. + * param userData user parameter passed to the callback function. + */ +void I2C_MasterTransferCreateHandle(I2C_Type *base, + i2c_master_handle_t *handle, + i2c_master_transfer_callback_t callback, + void *userData) +{ + assert(NULL != handle); + + uint32_t instance = I2C_GetInstance(base); + + /* Zero handle. */ + (void)memset(handle, 0, sizeof(*handle)); + + /* Set callback and userData. */ + handle->completionCallback = callback; + handle->userData = userData; + + /* Save the context in global variables to support the double weak mechanism. */ + s_i2cHandle[instance] = handle; + + /* Save master interrupt handler. */ + s_i2cMasterIsr = I2C_MasterTransferHandleIRQ; + + /* Enable NVIC interrupt. */ + (void)EnableIRQ(s_i2cIrqs[instance]); +} + +/*! + * brief Performs a master interrupt non-blocking transfer on the I2C bus. + * + * note Calling the API returns immediately after transfer initiates. The user needs + * to call I2C_MasterGetTransferCount to poll the transfer status to check whether + * the transfer is finished. If the return status is not kStatus_I2C_Busy, the transfer + * is finished. + * + * param base I2C base pointer. + * param handle pointer to i2c_master_handle_t structure which stores the transfer state. + * param xfer pointer to i2c_master_transfer_t structure. + * retval kStatus_Success Successfully start the data transmission. + * retval kStatus_I2C_Busy Previous transmission still not finished. + * retval kStatus_I2C_Timeout Transfer error, wait signal timeout. + */ +status_t I2C_MasterTransferNonBlocking(I2C_Type *base, i2c_master_handle_t *handle, i2c_master_transfer_t *xfer) +{ + assert(NULL != handle); + assert(NULL != xfer); + + status_t result = kStatus_Success; + + /* Check if the I2C bus is idle - if not return busy status. */ + if (handle->state != (uint8_t)kIdleState) + { + result = kStatus_I2C_Busy; + } + else + { + /* Start up the master transfer state machine. */ + result = I2C_InitTransferStateMachine(base, handle, xfer); + + if (result == kStatus_Success) + { + /* Enable the I2C interrupts. */ + I2C_EnableInterrupts(base, (uint32_t)kI2C_GlobalInterruptEnable); + } + } + + return result; +} + +/*! + * brief Aborts an interrupt non-blocking transfer early. + * + * note This API can be called at any time when an interrupt non-blocking transfer initiates + * to abort the transfer early. + * + * param base I2C base pointer. + * param handle pointer to i2c_master_handle_t structure which stores the transfer state + * retval kStatus_I2C_Timeout Timeout during polling flag. + * retval kStatus_Success Successfully abort the transfer. + */ +status_t I2C_MasterTransferAbort(I2C_Type *base, i2c_master_handle_t *handle) +{ + assert(NULL != handle); + + volatile uint8_t dummy = 0; +#if I2C_WAIT_TIMEOUT + uint32_t waitTimes = I2C_WAIT_TIMEOUT; +#endif + + /* Add this to avoid build warning. */ + dummy++; + + /* Disable interrupt. */ + I2C_DisableInterrupts(base, (uint32_t)kI2C_GlobalInterruptEnable); + + /* Reset the state to idle. */ + handle->state = (uint8_t)kIdleState; + + /* If the bus is already in use, but not by us */ + if (0U == (base->C1 & I2C_C1_MST_MASK)) + { + return kStatus_I2C_Busy; + } + + /* Send STOP signal. */ + if (handle->transfer.direction == kI2C_Read) + { + base->C1 |= I2C_C1_TXAK_MASK; + +#if I2C_WAIT_TIMEOUT + /* Wait until data transfer complete. */ + while ((0U == (base->S & (uint8_t)kI2C_IntPendingFlag)) && (--waitTimes)) + { + } + if (waitTimes == 0) + { + return kStatus_I2C_Timeout; + } +#else + /* Wait until data transfer complete. */ + while (0U == (base->S & (uint8_t)kI2C_IntPendingFlag)) + { + } +#endif + base->S = (uint8_t)kI2C_IntPendingFlag; + + base->C1 &= ~(uint8_t)(I2C_C1_MST_MASK | I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + dummy = base->D; + } + else + { +#if I2C_WAIT_TIMEOUT + /* Wait until data transfer complete. */ + while ((0U == (base->S & (uint8_t)kI2C_IntPendingFlag)) && (--waitTimes)) + { + } + if (waitTimes == 0) + { + return kStatus_I2C_Timeout; + } +#else + /* Wait until data transfer complete. */ + while (0U == (base->S & (uint8_t)kI2C_IntPendingFlag)) + { + } +#endif + base->S = (uint8_t)kI2C_IntPendingFlag; + base->C1 &= ~(uint8_t)(I2C_C1_MST_MASK | I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + } + + return kStatus_Success; +} + +/*! + * brief Gets the master transfer status during a interrupt non-blocking transfer. + * + * param base I2C base pointer. + * param handle pointer to i2c_master_handle_t structure which stores the transfer state. + * param count Number of bytes transferred so far by the non-blocking transaction. + * retval kStatus_InvalidArgument count is Invalid. + * retval kStatus_Success Successfully return the count. + */ +status_t I2C_MasterTransferGetCount(I2C_Type *base, i2c_master_handle_t *handle, size_t *count) +{ + assert(NULL != handle); + + if (NULL == count) + { + return kStatus_InvalidArgument; + } + + *count = handle->transferSize - handle->transfer.dataSize; + + return kStatus_Success; +} + +/*! + * brief Master interrupt handler. + * + * param base I2C base pointer. + * param i2cHandle pointer to i2c_master_handle_t structure. + */ +void I2C_MasterTransferHandleIRQ(I2C_Type *base, void *i2cHandle) +{ + assert(NULL != i2cHandle); + + i2c_master_handle_t *handle = (i2c_master_handle_t *)i2cHandle; + status_t result = kStatus_Success; + bool isDone; + + /* Clear the interrupt flag. */ + base->S = (uint8_t)kI2C_IntPendingFlag; + + /* Check transfer complete flag. */ + result = I2C_MasterTransferRunStateMachine(base, handle, &isDone); + + if ((true == isDone) || (0 != result)) + { + /* Send stop command if transfer done or received Nak. */ + if ((0U == (handle->transfer.flags & (uint32_t)kI2C_TransferNoStopFlag)) || (result == kStatus_I2C_Nak) || + (result == kStatus_I2C_Addr_Nak)) + { + /* Ensure stop command is a need. */ + if (0U != (base->C1 & I2C_C1_MST_MASK)) + { + if (I2C_MasterStop(base) != kStatus_Success) + { + result = kStatus_I2C_Timeout; + } + } + } + + /* Restore handle to idle state. */ + handle->state = (uint8_t)kIdleState; + + /* Disable interrupt. */ + I2C_DisableInterrupts(base, (uint32_t)kI2C_GlobalInterruptEnable); + + /* Call the callback function after the function has completed. */ + if (NULL != (handle->completionCallback)) + { + handle->completionCallback(base, handle, result, handle->userData); + } + } +} + +/*! + * brief Initializes the I2C peripheral. Call this API to ungate the I2C clock + * and initialize the I2C with the slave configuration. + * + * note This API should be called at the beginning of the application. + * Otherwise, any operation to the I2C module can cause a hard fault + * because the clock is not enabled. The configuration structure can partly be set + * with default values by I2C_SlaveGetDefaultConfig() or it can be custom filled by the user. + * This is an example. + * code + * i2c_slave_config_t config = { + * .enableSlave = true, + * .enableGeneralCall = false, + * .addressingMode = kI2C_Address7bit, + * .slaveAddress = 0x1DU, + * .enableWakeUp = false, + * .enablehighDrive = false, + * .enableBaudRateCtl = false, + * .sclStopHoldTime_ns = 4000 + * }; + * I2C_SlaveInit(I2C0, &config, 12000000U); + * endcode + * + * param base I2C base pointer + * param slaveConfig A pointer to the slave configuration structure + * param srcClock_Hz I2C peripheral clock frequency in Hz + */ +void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig, uint32_t srcClock_Hz) +{ + assert(NULL != slaveConfig); + + uint8_t tmpReg; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + CLOCK_EnableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* Reset the module. */ + base->A1 = 0; + base->F = 0; + base->C1 = 0; + base->S = 0xFFU; + base->C2 = 0; +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + base->FLT = 0x50U; +#elif defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT + base->FLT = 0x40U; +#endif + base->RA = 0; + + /* Configure addressing mode. */ + switch (slaveConfig->addressingMode) + { + case kI2C_Address7bit: + base->A1 = (uint8_t)(((uint32_t)(slaveConfig->slaveAddress)) << 1U); + break; + + case kI2C_RangeMatch: + assert(slaveConfig->slaveAddress < slaveConfig->upperAddress); + base->A1 = (uint8_t)(((uint32_t)(slaveConfig->slaveAddress)) << 1U); + base->RA = (uint8_t)(((uint32_t)(slaveConfig->upperAddress)) << 1U); + base->C2 |= I2C_C2_RMEN_MASK; + break; + + default: + break; + } + + /* Configure low power wake up feature. */ + tmpReg = base->C1; + tmpReg &= ~(uint8_t)I2C_C1_WUEN_MASK; + base->C1 = tmpReg | I2C_C1_WUEN(slaveConfig->enableWakeUp) | I2C_C1_IICEN(slaveConfig->enableSlave); + + /* Configure general call & baud rate control. */ + tmpReg = base->C2; + tmpReg &= ~(uint8_t)(I2C_C2_SBRC_MASK | I2C_C2_GCAEN_MASK); + tmpReg |= I2C_C2_SBRC(slaveConfig->enableBaudRateCtl) | I2C_C2_GCAEN(slaveConfig->enableGeneralCall); + base->C2 = tmpReg; + +/* Enable/Disable double buffering. */ +#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE + tmpReg = (uint8_t)(base->S2 & (~I2C_S2_DFEN_MASK)); + base->S2 = tmpReg | I2C_S2_DFEN(slaveConfig->enableDoubleBuffering); +#endif + + /* Set hold time. */ + I2C_SetHoldTime(base, slaveConfig->sclStopHoldTime_ns, srcClock_Hz); +} + +/*! + * brief De-initializes the I2C slave peripheral. Calling this API gates the I2C clock. + * The I2C slave module can't work unless the I2C_SlaveInit is called to enable the clock. + * param base I2C base pointer + */ +void I2C_SlaveDeinit(I2C_Type *base) +{ + /* Disable I2C module. */ + I2C_Enable(base, false); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Disable I2C clock. */ + CLOCK_DisableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +/*! + * brief Sets the I2C slave configuration structure to default values. + * + * The purpose of this API is to get the configuration structure initialized for use in the I2C_SlaveConfigure(). + * Modify fields of the structure before calling the I2C_SlaveConfigure(). + * This is an example. + * code + * i2c_slave_config_t config; + * I2C_SlaveGetDefaultConfig(&config); + * endcode + * param slaveConfig A pointer to the slave configuration structure. + */ +void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig) +{ + assert(NULL != slaveConfig); + + /* Initializes the configure structure to zero. */ + (void)memset(slaveConfig, 0, sizeof(*slaveConfig)); + + /* By default slave is addressed with 7-bit address. */ + slaveConfig->addressingMode = kI2C_Address7bit; + + /* General call mode is disabled by default. */ + slaveConfig->enableGeneralCall = false; + + /* Slave address match waking up MCU from low power mode is disabled. */ + slaveConfig->enableWakeUp = false; + + /* Independent slave mode baud rate at maximum frequency is disabled. */ + slaveConfig->enableBaudRateCtl = false; + +/* Default enable double buffering. */ +#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE + slaveConfig->enableDoubleBuffering = true; +#endif + + /* Set default SCL stop hold time to 4us which is minimum requirement in I2C spec. */ + slaveConfig->sclStopHoldTime_ns = 4000; + + /* Enable the I2C peripheral. */ + slaveConfig->enableSlave = true; +} + +/*! + * brief Performs a polling send transaction on the I2C bus. + * + * param base The I2C peripheral base pointer. + * param txBuff The pointer to the data to be transferred. + * param txSize The length in bytes of the data to be transferred. + * retval kStatus_Success Successfully complete the data transmission. + * retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost. + * retval kStataus_I2C_Nak Transfer error, receive NAK during transfer. + */ +status_t I2C_SlaveWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize) +{ + status_t result = kStatus_Success; + volatile uint8_t dummy = 0; + + /* Add this to avoid build warning. */ + dummy++; + +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + /* Check start flag. */ + while (0U == (base->FLT & I2C_FLT_STARTF_MASK)) + { + } + /* Clear STARTF flag. */ + base->FLT |= I2C_FLT_STARTF_MASK; + /* Clear the IICIF flag. */ + base->S = (uint8_t)kI2C_IntPendingFlag; +#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */ + +#if I2C_WAIT_TIMEOUT + uint32_t waitTimes = I2C_WAIT_TIMEOUT; + /* Wait until data transfer complete. */ + while ((!(base->S & kI2C_AddressMatchFlag)) && (--waitTimes)) + { + } + if (waitTimes == 0) + { + return kStatus_I2C_Timeout; + } +#else + /* Wait for address match flag. */ + while (0U == (base->S & (uint8_t)kI2C_AddressMatchFlag)) + { + } +#endif + /* Read dummy to release bus. */ + dummy = base->D; + + result = I2C_MasterWriteBlocking(base, txBuff, txSize, (uint32_t)kI2C_TransferNoStopFlag); + + /* Switch to receive mode. */ + base->C1 &= ~(uint8_t)(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + + /* Read dummy to release bus. */ + dummy = base->D; + + return result; +} + +/*! + * brief Performs a polling receive transaction on the I2C bus. + * + * param base I2C peripheral base pointer. + * param rxBuff The pointer to the data to store the received data. + * param rxSize The length in bytes of the data to be received. + * retval kStatus_Success Successfully complete data receive. + * retval kStatus_I2C_Timeout Wait status flag timeout. + */ +status_t I2C_SlaveReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize) +{ + status_t result = kStatus_Success; + volatile uint8_t dummy = 0; + + /* Add this to avoid build warning. */ + dummy++; + +/* Wait until address match. */ +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + /* Check start flag. */ + while (0U == (base->FLT & I2C_FLT_STARTF_MASK)) + { + } + /* Clear STARTF flag. */ + base->FLT |= I2C_FLT_STARTF_MASK; + /* Clear the IICIF flag. */ + base->S = (uint8_t)kI2C_IntPendingFlag; +#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */ + +#if I2C_WAIT_TIMEOUT + uint32_t waitTimes = I2C_WAIT_TIMEOUT; + /* Wait for address match and int pending flag. */ + while ((!(base->S & kI2C_AddressMatchFlag)) && (--waitTimes)) + { + } + if (waitTimes == 0) + { + return kStatus_I2C_Timeout; + } + + waitTimes = I2C_WAIT_TIMEOUT; + while ((!(base->S & kI2C_IntPendingFlag)) && (--waitTimes)) + { + } + if (waitTimes == 0) + { + return kStatus_I2C_Timeout; + } +#else + /* Wait for address match and int pending flag. */ + while (0U == (base->S & (uint8_t)kI2C_AddressMatchFlag)) + { + } + while (0U == (base->S & (uint8_t)kI2C_IntPendingFlag)) + { + } +#endif + + /* Read dummy to release bus. */ + dummy = base->D; + + /* Clear the IICIF flag. */ + base->S = (uint8_t)kI2C_IntPendingFlag; + + /* Setup the I2C peripheral to receive data. */ + base->C1 &= ~(uint8_t)(I2C_C1_TX_MASK); + + while (0U != (rxSize--)) + { +#if I2C_WAIT_TIMEOUT + waitTimes = I2C_WAIT_TIMEOUT; + /* Wait until data transfer complete. */ + while ((0U == (base->S & kI2C_IntPendingFlag)) && (--waitTimes)) + { + } + if (waitTimes == 0) + { + return kStatus_I2C_Timeout; + } +#else + /* Wait until data transfer complete. */ + while (0U == (base->S & (uint8_t)kI2C_IntPendingFlag)) + { + } +#endif + /* Clear the IICIF flag. */ + base->S = (uint8_t)kI2C_IntPendingFlag; + + /* Read from the data register. */ + *rxBuff++ = base->D; + } + + return result; +} + +/*! + * brief Initializes the I2C handle which is used in transactional functions. + * + * param base I2C base pointer. + * param handle pointer to i2c_slave_handle_t structure to store the transfer state. + * param callback pointer to user callback function. + * param userData user parameter passed to the callback function. + */ +void I2C_SlaveTransferCreateHandle(I2C_Type *base, + i2c_slave_handle_t *handle, + i2c_slave_transfer_callback_t callback, + void *userData) +{ + assert(NULL != handle); + + uint32_t instance = I2C_GetInstance(base); + + /* Zero handle. */ + (void)memset(handle, 0, sizeof(*handle)); + + /* Set callback and userData. */ + handle->callback = callback; + handle->userData = userData; + + /* Save the context in global variables to support the double weak mechanism. */ + s_i2cHandle[instance] = handle; + + /* Save slave interrupt handler. */ + s_i2cSlaveIsr = I2C_SlaveTransferHandleIRQ; + + /* Enable NVIC interrupt. */ + (void)EnableIRQ(s_i2cIrqs[instance]); +} + +/*! + * brief Starts accepting slave transfers. + * + * Call this API after calling the I2C_SlaveInit() and I2C_SlaveTransferCreateHandle() to start processing + * transactions driven by an I2C master. The slave monitors the I2C bus and passes events to the + * callback that was passed into the call to I2C_SlaveTransferCreateHandle(). The callback is always invoked + * from the interrupt context. + * + * The set of events received by the callback is customizable. To do so, set the a eventMask parameter to + * the OR'd combination of #i2c_slave_transfer_event_t enumerators for the events you wish to receive. + * The #kI2C_SlaveTransmitEvent and #kLPI2C_SlaveReceiveEvent events are always enabled and do not need + * to be included in the mask. Alternatively, pass 0 to get a default set of only the transmit and + * receive events that are always enabled. In addition, the #kI2C_SlaveAllEvents constant is provided as + * a convenient way to enable all events. + * + * param base The I2C peripheral base address. + * param handle Pointer to #i2c_slave_handle_t structure which stores the transfer state. + * param eventMask Bit mask formed by OR'ing together #i2c_slave_transfer_event_t enumerators to specify + * which events to send to the callback. Other accepted values are 0 to get a default set of + * only the transmit and receive events, and #kI2C_SlaveAllEvents to enable all events. + * + * retval #kStatus_Success Slave transfers were successfully started. + * retval #kStatus_I2C_Busy Slave transfers have already been started on this handle. + */ +status_t I2C_SlaveTransferNonBlocking(I2C_Type *base, i2c_slave_handle_t *handle, uint32_t eventMask) +{ + assert(NULL != handle); + + /* Check if the I2C bus is idle - if not return busy status. */ + if (true == handle->isBusy) + { + return kStatus_I2C_Busy; + } + else + { + /* Disable LPI2C IRQ sources while we configure stuff. */ + I2C_DisableInterrupts(base, (uint32_t)kIrqFlags); + + /* Clear transfer in handle. */ + (void)memset(&handle->transfer, 0, sizeof(handle->transfer)); + + /* Record that we're busy. */ + handle->isBusy = true; + + /* Set up event mask. tx and rx are always enabled. */ + handle->eventMask = eventMask | (uint32_t)kI2C_SlaveTransmitEvent | (uint32_t)kI2C_SlaveReceiveEvent | + (uint32_t)kI2C_SlaveGenaralcallEvent; + + /* Clear all flags. */ + I2C_SlaveClearStatusFlags(base, (uint32_t)kClearFlags); + + /* Enable I2C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */ + I2C_EnableInterrupts(base, (uint32_t)kIrqFlags); + } + + return kStatus_Success; +} + +/*! + * brief Aborts the slave transfer. + * + * note This API can be called at any time to stop slave for handling the bus events. + * + * param base I2C base pointer. + * param handle pointer to i2c_slave_handle_t structure which stores the transfer state. + */ +void I2C_SlaveTransferAbort(I2C_Type *base, i2c_slave_handle_t *handle) +{ + assert(NULL != handle); + + if (true == handle->isBusy) + { + /* Disable interrupts. */ + I2C_DisableInterrupts(base, (uint32_t)kIrqFlags); + + /* Reset transfer info. */ + (void)memset(&handle->transfer, 0, sizeof(handle->transfer)); + + /* Reset the state to idle. */ + handle->isBusy = false; + } +} + +/*! + * brief Gets the slave transfer remaining bytes during a interrupt non-blocking transfer. + * + * param base I2C base pointer. + * param handle pointer to i2c_slave_handle_t structure. + * param count Number of bytes transferred so far by the non-blocking transaction. + * retval kStatus_InvalidArgument count is Invalid. + * retval kStatus_Success Successfully return the count. + */ +status_t I2C_SlaveTransferGetCount(I2C_Type *base, i2c_slave_handle_t *handle, size_t *count) +{ + assert(NULL != handle); + + if (NULL == count) + { + return kStatus_InvalidArgument; + } + + /* Catch when there is not an active transfer. */ + if (false == handle->isBusy) + { + *count = 0; + return kStatus_NoTransferInProgress; + } + + /* For an active transfer, just return the count from the handle. */ + *count = handle->transfer.transferredCount; + + return kStatus_Success; +} + +/*! + * brief Slave interrupt handler. + * + * param base I2C base pointer. + * param i2cHandle pointer to i2c_slave_handle_t structure which stores the transfer state + */ +void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) +{ + assert(NULL != i2cHandle); + + uint16_t status; + bool doTransmit = false; + i2c_slave_handle_t *handle = (i2c_slave_handle_t *)i2cHandle; + i2c_slave_transfer_t *xfer; + volatile uint8_t dummy = 0; + size_t tmpDataSize = 0; + + /* Add this to avoid build warning. */ + dummy++; + + status = (uint16_t)I2C_SlaveGetStatusFlags(base); + xfer = &(handle->transfer); + +#ifdef I2C_HAS_STOP_DETECT + /* Check stop flag. */ + if (0U != (status & (uint16_t)kI2C_StopDetectFlag)) + { + I2C_MasterClearStatusFlags(base, (uint32_t)kI2C_StopDetectFlag); + + /* Clear the interrupt flag. */ + base->S = (uint8_t)kI2C_IntPendingFlag; + + /* Call slave callback if this is the STOP of the transfer. */ + if (true == handle->isBusy) + { + xfer->event = kI2C_SlaveCompletionEvent; + xfer->completionStatus = kStatus_Success; + handle->isBusy = false; + + if ((0U != (handle->eventMask & (uint32_t)xfer->event)) && (NULL != handle->callback)) + { + handle->callback(base, xfer, handle->userData); + } + } + + if (0U == (status & (uint16_t)kI2C_AddressMatchFlag)) + { + return; + } + } +#endif /* I2C_HAS_STOP_DETECT */ + +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + /* Check start flag. */ + if (0U != (status & (uint16_t)kI2C_StartDetectFlag)) + { + I2C_MasterClearStatusFlags(base, (uint32_t)kI2C_StartDetectFlag); + + /* Clear the interrupt flag. */ + base->S = (uint8_t)kI2C_IntPendingFlag; + + xfer->event = kI2C_SlaveStartEvent; + + if ((0U != (handle->eventMask & (uint32_t)xfer->event)) && (NULL != handle->callback)) + { + handle->callback(base, xfer, handle->userData); + } + + if (0U == (status & (uint16_t)kI2C_AddressMatchFlag)) + { + return; + } + } +#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */ + + /* Clear the interrupt flag. */ + base->S = (uint8_t)kI2C_IntPendingFlag; + + /* Check NAK */ + if (0U != (status & (uint16_t)kI2C_ReceiveNakFlag)) + { + /* Set receive mode. */ + base->C1 &= ~(uint8_t)(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + + /* Read dummy. */ + dummy = base->D; + + if (handle->transfer.dataSize != 0u) + { + xfer->event = kI2C_SlaveCompletionEvent; + xfer->completionStatus = kStatus_I2C_Nak; + handle->isBusy = false; + + if ((0U != (handle->eventMask & (uint32_t)xfer->event)) && (NULL != handle->callback)) + { + handle->callback(base, xfer, handle->userData); + } + } + else + { +#ifndef I2C_HAS_STOP_DETECT + xfer->event = kI2C_SlaveCompletionEvent; + xfer->completionStatus = kStatus_Success; + handle->isBusy = false; + + if ((0U != (handle->eventMask & (uint32_t)xfer->event)) && (NULL != handle->callback)) + { + handle->callback(base, xfer, handle->userData); + } +#endif /* !FSL_FEATURE_I2C_HAS_START_STOP_DETECT or !FSL_FEATURE_I2C_HAS_STOP_DETECT */ + } + } + /* Check address match. */ + else if (0U != (status & (uint16_t)kI2C_AddressMatchFlag)) + { + handle->isBusy = true; + xfer->event = kI2C_SlaveAddressMatchEvent; + + /* Slave transmit, master reading from slave. */ + if (0U != (status & (uint16_t)kI2C_TransferDirectionFlag)) + { + /* Change direction to send data. */ + base->C1 |= I2C_C1_TX_MASK; + + doTransmit = true; + // Store the slave address match + dummy = base->D; + } + else + { + /* Slave receive, master writing to slave. */ + base->C1 &= ~(uint8_t)(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + + /* Read dummy to release the bus. */ + // Which happens to contain the slave address match + dummy = base->D; + + if (dummy == 0u) + { + xfer->event = kI2C_SlaveGenaralcallEvent; + } + } + + if ((0U != (handle->eventMask & (uint32_t)xfer->event)) && (NULL != handle->callback)) + { + // Store the matched slave address in userData + *(uint8_t *)(handle->userData) = dummy; + handle->callback(base, xfer, handle->userData); + } + } + /* Check transfer complete flag. */ + else if (0U != (status & (uint16_t)kI2C_TransferCompleteFlag)) + { + /* Slave transmit, master reading from slave. */ + if (0U != (status & (uint16_t)kI2C_TransferDirectionFlag)) + { + doTransmit = true; + } + else + { + tmpDataSize = xfer->dataSize; + /* If we're out of data, invoke callback to get more. */ + if ((NULL == xfer->data) || (0U == tmpDataSize)) + { + xfer->event = kI2C_SlaveReceiveEvent; + + if (NULL != handle->callback) + { + handle->callback(base, xfer, handle->userData); + } + + /* Clear the transferred count now that we have a new buffer. */ + xfer->transferredCount = 0; + } + + /* Slave receive, master writing to slave. */ + uint8_t data = base->D; + + if (0U != (handle->transfer.dataSize)) + { + /* Receive data. */ + *handle->transfer.data++ = data; + handle->transfer.dataSize--; + xfer->transferredCount++; + if (0U == handle->transfer.dataSize) + { +#ifndef I2C_HAS_STOP_DETECT + xfer->event = kI2C_SlaveCompletionEvent; + xfer->completionStatus = kStatus_Success; + handle->isBusy = false; + + /* Proceed receive complete event. */ + if ((handle->eventMask & (uint32_t)xfer->event) && (handle->callback)) + { + handle->callback(base, xfer, handle->userData); + } +#endif /* !FSL_FEATURE_I2C_HAS_START_STOP_DETECT or !FSL_FEATURE_I2C_HAS_STOP_DETECT */ + } + } + } + } + else + { + /* Read dummy to release bus. */ + dummy = base->D; + } + + /* Send data if there is the need. */ + if (doTransmit) + { + tmpDataSize = xfer->dataSize; + /* If we're out of data, invoke callback to get more. */ + if ((NULL == xfer->data) || (0U == tmpDataSize)) + { + xfer->event = kI2C_SlaveTransmitEvent; + + if (NULL != handle->callback) + { + handle->callback(base, xfer, handle->userData); + } + + /* Clear the transferred count now that we have a new buffer. */ + xfer->transferredCount = 0; + } + + if (0U != (handle->transfer.dataSize)) + { + /* Send data. */ + base->D = *handle->transfer.data++; + handle->transfer.dataSize--; + xfer->transferredCount++; + } + else + { + /* Switch to receive mode. */ + base->C1 &= ~(uint8_t)(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + + /* Read dummy to release bus. */ + dummy = base->D; + +#ifndef I2C_HAS_STOP_DETECT + xfer->event = kI2C_SlaveCompletionEvent; + xfer->completionStatus = kStatus_Success; + handle->isBusy = false; + + /* Proceed txdone event. */ + if ((handle->eventMask & (uint32_t)xfer->event) && (handle->callback)) + { + handle->callback(base, xfer, handle->userData); + } +#endif /* !FSL_FEATURE_I2C_HAS_START_STOP_DETECT or !FSL_FEATURE_I2C_HAS_STOP_DETECT */ + } + } +} + +#if defined(I2C0) +void I2C0_DriverIRQHandler(void) +{ + I2C_TransferCommonIRQHandler(I2C0, s_i2cHandle[0]); +} +#endif + +#if defined(I2C1) +void I2C1_DriverIRQHandler(void) +{ + I2C_TransferCommonIRQHandler(I2C1, s_i2cHandle[1]); +} +#endif + +#if defined(I2C2) +void I2C2_DriverIRQHandler(void) +{ + I2C_TransferCommonIRQHandler(I2C2, s_i2cHandle[2]); +} +#endif + +#if defined(I2C3) +void I2C3_DriverIRQHandler(void) +{ + I2C_TransferCommonIRQHandler(I2C3, s_i2cHandle[3]); +} +#endif diff --git a/source/hic_hal/freescale/kl27z/fsl_llwu.c b/source/hic_hal/freescale/kl27z/fsl_llwu.c new file mode 100644 index 000000000..4436c6dd2 --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_llwu.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_llwu.h" + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.llwu" +#endif + +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) +/*! + * brief Sets the external input pin source mode. + * + * This function sets the external input pin source mode that is used + * as a wake up source. + * + * param base LLWU peripheral base address. + * param pinIndex A pin index to be enabled as an external wakeup source starting from 1. + * param pinMode A pin configuration mode defined in the llwu_external_pin_modes_t. + */ +void LLWU_SetExternalWakeupPinMode(LLWU_Type *base, uint32_t pinIndex, llwu_external_pin_mode_t pinMode) +{ +#if (defined(FSL_FEATURE_LLWU_REG_BITWIDTH) && (FSL_FEATURE_LLWU_REG_BITWIDTH == 32)) + volatile uint32_t *regBase; + uint32_t regOffset; + uint32_t reg; + + switch (pinIndex >> 4U) + { + case 0U: + regBase = &base->PE1; + break; +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 16)) + case 1U: + regBase = &base->PE2; + break; +#endif + default: + regBase = NULL; + break; + } +#else + volatile uint8_t *regBase; + uint8_t regOffset; + uint8_t reg; + switch (pinIndex >> 2U) + { + case 0U: + regBase = &base->PE1; + break; + case 1U: + regBase = &base->PE2; + break; +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 8)) + case 2U: + regBase = &base->PE3; + break; +#endif +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 12)) + case 3U: + regBase = &base->PE4; + break; +#endif +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 16)) + case 4U: + regBase = &base->PE5; + break; +#endif +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 20)) + case 5U: + regBase = &base->PE6; + break; +#endif +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 24)) + case 6U: + regBase = &base->PE7; + break; +#endif +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 28)) + case 7U: + regBase = &base->PE8; + break; +#endif + default: + regBase = NULL; + break; + } +#endif /* FSL_FEATURE_LLWU_REG_BITWIDTH == 32 */ + + if (NULL != regBase) + { + reg = *regBase; +#if (defined(FSL_FEATURE_LLWU_REG_BITWIDTH) && (FSL_FEATURE_LLWU_REG_BITWIDTH == 32)) + regOffset = ((pinIndex & 0x0FU) << 1U); +#else + regOffset = (uint8_t)((pinIndex & 0x03U) << 1U); +#endif + reg &= ~(0x3U << regOffset); + reg |= (uint8_t)((uint32_t)pinMode << regOffset); + *regBase = reg; + } +} + +/*! + * brief Gets the external wakeup source flag. + * + * This function checks the external pin flag to detect whether the MCU is + * woken up by the specific pin. + * + * param base LLWU peripheral base address. + * param pinIndex A pin index, which starts from 1. + * return True if the specific pin is a wakeup source. + */ +bool LLWU_GetExternalWakeupPinFlag(LLWU_Type *base, uint32_t pinIndex) +{ +#if (defined(FSL_FEATURE_LLWU_REG_BITWIDTH) && (FSL_FEATURE_LLWU_REG_BITWIDTH == 32)) + return (bool)(base->PF & (1U << pinIndex)); +#else + volatile uint8_t *regBase; + + switch (pinIndex >> 3U) + { +#if (defined(FSL_FEATURE_LLWU_HAS_PF) && FSL_FEATURE_LLWU_HAS_PF) + case 0U: + regBase = &base->PF1; + break; +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 8)) + case 1U: + regBase = &base->PF2; + break; +#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */ +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 16)) + case 2U: + regBase = &base->PF3; + break; +#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */ +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 24)) + case 3U: + regBase = &base->PF4; + break; +#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */ +#else + case 0U: + regBase = &base->F1; + break; +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 8)) + case 1U: + regBase = &base->F2; + break; +#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */ +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 16)) + case 2U: + regBase = &base->F3; + break; +#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */ +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 24)) + case 3U: + regBase = &base->F4; + break; +#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */ +#endif /* FSL_FEATURE_LLWU_HAS_PF */ + default: + regBase = NULL; + break; + } + + if (NULL != regBase) + { + if (0U != (*regBase & (1U << pinIndex % 8U))) + { + return true; + } + else + { + return false; + } + } + else + { + return false; + } +#endif /* FSL_FEATURE_LLWU_REG_BITWIDTH */ +} + +/*! + * brief Clears the external wakeup source flag. + * + * This function clears the external wakeup source flag for a specific pin. + * + * param base LLWU peripheral base address. + * param pinIndex A pin index, which starts from 1. + */ +void LLWU_ClearExternalWakeupPinFlag(LLWU_Type *base, uint32_t pinIndex) +{ +#if (defined(FSL_FEATURE_LLWU_REG_BITWIDTH) && (FSL_FEATURE_LLWU_REG_BITWIDTH == 32)) + base->PF = (1U << pinIndex); +#else + volatile uint8_t *regBase; + switch (pinIndex >> 3U) + { +#if (defined(FSL_FEATURE_LLWU_HAS_PF) && FSL_FEATURE_LLWU_HAS_PF) + case 0U: + regBase = &base->PF1; + break; +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 8)) + case 1U: + regBase = &base->PF2; + break; +#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */ +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 16)) + case 2U: + regBase = &base->PF3; + break; +#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */ +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 24)) + case 3U: + regBase = &base->PF4; + break; +#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */ +#else + case 0U: + regBase = &base->F1; + break; +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 8)) + case 1U: + regBase = &base->F2; + break; +#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */ +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 16)) + case 2U: + regBase = &base->F3; + break; +#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */ +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 24)) + case 3U: + regBase = &base->F4; + break; +#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */ +#endif /* FSL_FEATURE_LLWU_HAS_PF */ + default: + regBase = NULL; + break; + } + if (NULL != regBase) + { + *regBase = (1U << pinIndex % 8U); + } +#endif /* FSL_FEATURE_LLWU_REG_BITWIDTH */ +} +#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */ + +#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && FSL_FEATURE_LLWU_HAS_PIN_FILTER) +/*! + * brief Sets the pin filter configuration. + * + * This function sets the pin filter configuration. + * + * param base LLWU peripheral base address. + * param filterIndex A pin filter index used to enable/disable the digital filter, starting from 1. + * param filterMode A filter mode configuration + */ +void LLWU_SetPinFilterMode(LLWU_Type *base, uint32_t filterIndex, llwu_external_pin_filter_mode_t filterMode) +{ +#if (defined(FSL_FEATURE_LLWU_REG_BITWIDTH) && (FSL_FEATURE_LLWU_REG_BITWIDTH == 32)) + base->FILT = ((base->FILT) & ~((LLWU_FILT_FILTSEL1_MASK | LLWU_FILT_FILTE1_MASK) << ((filterIndex - 1U) * 8U))) | + ((LLWU_FILT_FILTSEL1(filterMode.pinIndex) | LLWU_FILT_FILTE1(filterMode.filterMode)) + << ((filterIndex - 1U) * 8U)) | + LLWU_FILT_FILTF1_MASK /* W1C to clear the FILTF flag bit. */ + ; +#else + volatile uint8_t *regBase; + + switch (filterIndex) + { + case 1U: + regBase = &base->FILT1; + break; +#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 1)) + case 2U: + regBase = &base->FILT2; + break; +#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */ +#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 2)) + case 3U: + regBase = &base->FILT3; + break; +#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */ +#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 3)) + case 4U: + regBase = &base->FILT4; + break; +#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */ + default: + regBase = NULL; + break; + } + + if (NULL != regBase) + { + *regBase = (uint8_t)((*regBase & ~(LLWU_FILT1_FILTSEL_MASK | LLWU_FILT1_FILTE_MASK)) | + LLWU_FILT1_FILTSEL(filterMode.pinIndex) | LLWU_FILT1_FILTE(filterMode.filterMode) | + LLWU_FILT1_FILTF_MASK) /* W1C to clear the FILTF flag bit. */ + ; + } +#endif /* FSL_FEATURE_LLWU_REG_BITWIDTH */ +} + +/*! + * brief Gets the pin filter configuration. + * + * This function gets the pin filter flag. + * + * param base LLWU peripheral base address. + * param filterIndex A pin filter index, which starts from 1. + * return True if the flag is a source of the existing low-leakage power mode. + */ +bool LLWU_GetPinFilterFlag(LLWU_Type *base, uint32_t filterIndex) +{ +#if (defined(FSL_FEATURE_LLWU_REG_BITWIDTH) && (FSL_FEATURE_LLWU_REG_BITWIDTH == 32)) + return (bool)(base->FILT & (1U << (filterIndex * 8U - 1))); +#else + bool status = false; + + switch (filterIndex) + { + case 1: + status = ((base->FILT1 & LLWU_FILT1_FILTF_MASK) != 0U); + break; +#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 1)) + case 2: + status = ((base->FILT2 & LLWU_FILT2_FILTF_MASK) != 0U); + break; +#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */ +#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 2)) + case 3: + status = (base->FILT3 & LLWU_FILT3_FILTF_MASK); + break; +#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */ +#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 3)) + case 4: + status = (base->FILT4 & LLWU_FILT4_FILTF_MASK); + break; +#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */ + default: + break; + } + + return status; +#endif /* FSL_FEATURE_LLWU_REG_BITWIDTH */ +} + +/*! + * brief Clears the pin filter configuration. + * + * This function clears the pin filter flag. + * + * param base LLWU peripheral base address. + * param filterIndex A pin filter index to clear the flag, starting from 1. + */ +void LLWU_ClearPinFilterFlag(LLWU_Type *base, uint32_t filterIndex) +{ +#if (defined(FSL_FEATURE_LLWU_REG_BITWIDTH) && (FSL_FEATURE_LLWU_REG_BITWIDTH == 32)) + uint32_t reg; + + reg = base->FILT; + switch (filterIndex) + { + case 1: + reg |= LLWU_FILT_FILTF1_MASK; + break; +#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 1)) + case 2: + reg |= LLWU_FILT_FILTF2_MASK; + break; +#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER > 1 */ +#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 2)) + case 3: + reg |= LLWU_FILT_FILTF3_MASK; + break; +#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER > 2 */ +#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 3)) + case 4: + reg |= LLWU_FILT_FILTF4_MASK; + break; +#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER > 3 */ + default: + break; + } + base->FILT = reg; +#else + volatile uint8_t *regBase; + uint8_t reg; + + switch (filterIndex) + { + case 1: + regBase = &base->FILT1; + break; +#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 1)) + case 2: + regBase = &base->FILT2; + break; +#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */ +#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 2)) + case 3: + regBase = &base->FILT3; + break; +#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */ +#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 3)) + case 4: + regBase = &base->FILT4; + break; +#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */ + default: + regBase = NULL; + break; + } + + if (NULL != regBase) + { + reg = *regBase; + reg |= LLWU_FILT1_FILTF_MASK; + *regBase = reg; + } +#endif /* FSL_FEATURE_LLWU_REG_BITWIDTH */ +} +#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */ + +#if (defined(FSL_FEATURE_LLWU_HAS_RESET_ENABLE) && FSL_FEATURE_LLWU_HAS_RESET_ENABLE) +/*! + * brief Sets the reset pin mode. + * + * This function determines how the reset pin is used as a low leakage mode exit source. + * + * param pinEnable Enable reset the pin filter + * param pinFilterEnable Specify whether the pin filter is enabled in Low-Leakage power mode. + */ +void LLWU_SetResetPinMode(LLWU_Type *base, bool pinEnable, bool pinFilterEnable) +{ + uint8_t reg; + + reg = base->RST; + reg &= ~(LLWU_RST_LLRSTE_MASK | LLWU_RST_RSTFILT_MASK); + reg |= (((uint32_t)pinEnable << LLWU_RST_LLRSTE_SHIFT) | ((uint32_t)pinFilterEnable << LLWU_RST_RSTFILT_SHIFT)); + base->RST = reg; +} +#endif /* FSL_FEATURE_LLWU_HAS_RESET_ENABLE */ diff --git a/source/hic_hal/freescale/kl27z/fsl_llwu.h b/source/hic_hal/freescale/kl27z/fsl_llwu.h new file mode 100644 index 000000000..ee1a68825 --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_llwu.h @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_LLWU_H_ +#define _FSL_LLWU_H_ + +#include "fsl_common.h" + +/*! @addtogroup llwu */ +/*! @{ */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +/*! @brief LLWU driver version 2.0.2. */ +#define FSL_LLWU_DRIVER_VERSION (MAKE_VERSION(2, 0, 2)) +/*@}*/ + +/*! + * @brief External input pin control modes + */ +typedef enum _llwu_external_pin_mode +{ + kLLWU_ExternalPinDisable = 0U, /*!< Pin disabled as a wakeup input. */ + kLLWU_ExternalPinRisingEdge = 1U, /*!< Pin enabled with the rising edge detection. */ + kLLWU_ExternalPinFallingEdge = 2U, /*!< Pin enabled with the falling edge detection.*/ + kLLWU_ExternalPinAnyEdge = 3U /*!< Pin enabled with any change detection. */ +} llwu_external_pin_mode_t; + +/*! + * @brief Digital filter control modes + */ +typedef enum _llwu_pin_filter_mode +{ + kLLWU_PinFilterDisable = 0U, /*!< Filter disabled. */ + kLLWU_PinFilterRisingEdge = 1U, /*!< Filter positive edge detection.*/ + kLLWU_PinFilterFallingEdge = 2U, /*!< Filter negative edge detection.*/ + kLLWU_PinFilterAnyEdge = 3U /*!< Filter any edge detection. */ +} llwu_pin_filter_mode_t; + +#if (defined(FSL_FEATURE_LLWU_HAS_VERID) && FSL_FEATURE_LLWU_HAS_VERID) +/*! + * @brief IP version ID definition. + */ +typedef struct _llwu_version_id +{ + uint16_t feature; /*!< A feature specification number. */ + uint8_t minor; /*!< The minor version number. */ + uint8_t major; /*!< The major version number. */ +} llwu_version_id_t; +#endif /* FSL_FEATURE_LLWU_HAS_VERID */ + +#if (defined(FSL_FEATURE_LLWU_HAS_PARAM) && FSL_FEATURE_LLWU_HAS_PARAM) +/*! + * @brief IP parameter definition. + */ +typedef struct _llwu_param +{ + uint8_t filters; /*!< A number of the pin filter. */ + uint8_t dmas; /*!< A number of the wakeup DMA. */ + uint8_t modules; /*!< A number of the wakeup module. */ + uint8_t pins; /*!< A number of the wake up pin. */ +} llwu_param_t; +#endif /* FSL_FEATURE_LLWU_HAS_PARAM */ + +#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && FSL_FEATURE_LLWU_HAS_PIN_FILTER) +/*! + * @brief An external input pin filter control structure + */ +typedef struct _llwu_external_pin_filter_mode +{ + uint32_t pinIndex; /*!< A pin number */ + llwu_pin_filter_mode_t filterMode; /*!< Filter mode */ +} llwu_external_pin_filter_mode_t; +#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */ + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name Low-Leakage Wakeup Unit Control APIs + * @{ + */ + +#if (defined(FSL_FEATURE_LLWU_HAS_VERID) && FSL_FEATURE_LLWU_HAS_VERID) +/*! + * @brief Gets the LLWU version ID. + * + * This function gets the LLWU version ID, including the major version number, + * the minor version number, and the feature specification number. + * + * @param base LLWU peripheral base address. + * @param versionId A pointer to the version ID structure. + */ +static inline void LLWU_GetVersionId(LLWU_Type *base, llwu_version_id_t *versionId) +{ + *((uint32_t *)versionId) = base->VERID; +} +#endif /* FSL_FEATURE_LLWU_HAS_VERID */ + +#if (defined(FSL_FEATURE_LLWU_HAS_PARAM) && FSL_FEATURE_LLWU_HAS_PARAM) +/*! + * @brief Gets the LLWU parameter. + * + * This function gets the LLWU parameter, including a wakeup pin number, a module + * number, a DMA number, and a pin filter number. + * + * @param base LLWU peripheral base address. + * @param param A pointer to the LLWU parameter structure. + */ +static inline void LLWU_GetParam(LLWU_Type *base, llwu_param_t *param) +{ + *((uint32_t *)param) = base->PARAM; +} +#endif /* FSL_FEATURE_LLWU_HAS_PARAM */ + +#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) +/*! + * @brief Sets the external input pin source mode. + * + * This function sets the external input pin source mode that is used + * as a wake up source. + * + * @param base LLWU peripheral base address. + * @param pinIndex A pin index to be enabled as an external wakeup source starting from 1. + * @param pinMode A pin configuration mode defined in the llwu_external_pin_modes_t. + */ +void LLWU_SetExternalWakeupPinMode(LLWU_Type *base, uint32_t pinIndex, llwu_external_pin_mode_t pinMode); + +/*! + * @brief Gets the external wakeup source flag. + * + * This function checks the external pin flag to detect whether the MCU is + * woken up by the specific pin. + * + * @param base LLWU peripheral base address. + * @param pinIndex A pin index, which starts from 1. + * @return True if the specific pin is a wakeup source. + */ +bool LLWU_GetExternalWakeupPinFlag(LLWU_Type *base, uint32_t pinIndex); + +/*! + * @brief Clears the external wakeup source flag. + * + * This function clears the external wakeup source flag for a specific pin. + * + * @param base LLWU peripheral base address. + * @param pinIndex A pin index, which starts from 1. + */ +void LLWU_ClearExternalWakeupPinFlag(LLWU_Type *base, uint32_t pinIndex); +#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */ + +#if (defined(FSL_FEATURE_LLWU_HAS_INTERNAL_MODULE) && FSL_FEATURE_LLWU_HAS_INTERNAL_MODULE) +/*! + * @brief Enables/disables the internal module source. + * + * This function enables/disables the internal module source mode that is used + * as a wake up source. + * + * @param base LLWU peripheral base address. + * @param moduleIndex A module index to be enabled as an internal wakeup source starting from 1. + * @param enable An enable or a disable setting + */ +static inline void LLWU_EnableInternalModuleInterruptWakup(LLWU_Type *base, uint32_t moduleIndex, bool enable) +{ + if (enable) + { + base->ME |= 1U << moduleIndex; + } + else + { + base->ME &= ~(1U << moduleIndex); + } +} + +#if (!(defined(FSL_FEATURE_LLWU_HAS_NO_INTERNAL_MODULE_WAKEUP_FLAG_REG) && \ + FSL_FEATURE_LLWU_HAS_NO_INTERNAL_MODULE_WAKEUP_FLAG_REG)) +/* Re-define the register which includes the internal wakeup module flag. */ +#if (defined(FSL_FEATURE_LLWU_REG_BITWIDTH) && (FSL_FEATURE_LLWU_REG_BITWIDTH == 32)) /* 32-bit LLWU. */ +#if (defined(FSL_FEATURE_LLWU_HAS_MF) && FSL_FEATURE_LLWU_HAS_MF) +#define INTERNAL_WAKEUP_MODULE_FLAG_REG MF +#else +#error "Unsupported internal module flag register." +#endif +#else /* 8-bit LLUW. */ +#if (defined(FSL_FEATURE_LLWU_HAS_MF) && FSL_FEATURE_LLWU_HAS_MF) +#define INTERNAL_WAKEUP_MODULE_FLAG_REG MF5 +#elif (defined(FSL_FEATURE_LLWU_HAS_PF) && FSL_FEATURE_LLWU_HAS_PF) +#define INTERNAL_WAKEUP_MODULE_FLAG_REG PF3 +#elif (!(defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 16))) +#define INTERNAL_WAKEUP_MODULE_FLAG_REG F3 +#else +#error "Unsupported internal module flag register." +#endif +#endif /* FSL_FEATURE_LLWU_REG_BITWIDTH */ + +/*! + * @brief Gets the external wakeup source flag. + * + * This function checks the external pin flag to detect whether the system is + * woken up by the specific pin. + * + * @param base LLWU peripheral base address. + * @param moduleIndex A module index, which starts from 1. + * @return True if the specific pin is a wake up source. + */ +static inline bool LLWU_GetInternalWakeupModuleFlag(LLWU_Type *base, uint32_t moduleIndex) +{ + return ((1U << moduleIndex) == (base->INTERNAL_WAKEUP_MODULE_FLAG_REG & (1U << moduleIndex))); +} +#endif /* FSL_FEATURE_LLWU_HAS_NO_INTERNAL_MODULE_WAKEUP_FLAG_REG */ +#endif /* FSL_FEATURE_LLWU_HAS_INTERNAL_MODULE */ + +#if (defined(FSL_FEATURE_LLWU_HAS_DMA_ENABLE_REG) && FSL_FEATURE_LLWU_HAS_DMA_ENABLE_REG) +/*! + * @brief Enables/disables the internal module DMA wakeup source. + * + * This function enables/disables the internal DMA that is used as a wake up source. + * + * @param base LLWU peripheral base address. + * @param moduleIndex An internal module index which is used as a DMA request source, starting from 1. + * @param enable Enable or disable the DMA request source + */ +static inline void LLWU_EnableInternalModuleDmaRequestWakup(LLWU_Type *base, uint32_t moduleIndex, bool enable) +{ + if (enable) + { + base->DE |= 1U << moduleIndex; + } + else + { + base->DE &= ~(1U << moduleIndex); + } +} +#endif /* FSL_FEATURE_LLWU_HAS_DMA_ENABLE_REG */ + +#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && FSL_FEATURE_LLWU_HAS_PIN_FILTER) +/*! + * @brief Sets the pin filter configuration. + * + * This function sets the pin filter configuration. + * + * @param base LLWU peripheral base address. + * @param filterIndex A pin filter index used to enable/disable the digital filter, starting from 1. + * @param filterMode A filter mode configuration + */ +void LLWU_SetPinFilterMode(LLWU_Type *base, uint32_t filterIndex, llwu_external_pin_filter_mode_t filterMode); + +/*! + * @brief Gets the pin filter configuration. + * + * This function gets the pin filter flag. + * + * @param base LLWU peripheral base address. + * @param filterIndex A pin filter index, which starts from 1. + * @return True if the flag is a source of the existing low-leakage power mode. + */ +bool LLWU_GetPinFilterFlag(LLWU_Type *base, uint32_t filterIndex); + +/*! + * @brief Clears the pin filter configuration. + * + * This function clears the pin filter flag. + * + * @param base LLWU peripheral base address. + * @param filterIndex A pin filter index to clear the flag, starting from 1. + */ +void LLWU_ClearPinFilterFlag(LLWU_Type *base, uint32_t filterIndex); + +#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */ + +#if (defined(FSL_FEATURE_LLWU_HAS_RESET_ENABLE) && FSL_FEATURE_LLWU_HAS_RESET_ENABLE) +/*! + * @brief Sets the reset pin mode. + * + * This function determines how the reset pin is used as a low leakage mode exit source. + * + * @param pinEnable Enable reset the pin filter + * @param pinFilterEnable Specify whether the pin filter is enabled in Low-Leakage power mode. + */ +void LLWU_SetResetPinMode(LLWU_Type *base, bool pinEnable, bool pinFilterEnable); +#endif /* FSL_FEATURE_LLWU_HAS_RESET_ENABLE */ + +/*@}*/ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ +#endif /* _FSL_LLWU_H_*/ diff --git a/source/hic_hal/freescale/kl27z/fsl_pmc.c b/source/hic_hal/freescale/kl27z/fsl_pmc.c new file mode 100644 index 000000000..c3cbaf0a4 --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_pmc.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "fsl_pmc.h" + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.pmc" +#endif + +#if (defined(FSL_FEATURE_PMC_HAS_PARAM) && FSL_FEATURE_PMC_HAS_PARAM) +/*! + * brief Gets the PMC parameter. + * + * This function gets the PMC parameter including the VLPO enable and the HVD enable. + * + * param base PMC peripheral base address. + * param param Pointer to PMC param structure. + */ +void PMC_GetParam(PMC_Type *base, pmc_param_t *param) +{ + uint32_t reg = base->PARAM; + ; + param->vlpoEnable = (bool)(reg & PMC_PARAM_VLPOE_MASK); + param->hvdEnable = (bool)(reg & PMC_PARAM_HVDE_MASK); +} +#endif /* FSL_FEATURE_PMC_HAS_PARAM */ + +/*! + * brief Configures the low-voltage detect setting. + * + * This function configures the low-voltage detect setting, including the trip + * point voltage setting, enables or disables the interrupt, enables or disables the system reset. + * + * param base PMC peripheral base address. + * param config Low-voltage detect configuration structure. + */ +void PMC_ConfigureLowVoltDetect(PMC_Type *base, const pmc_low_volt_detect_config_t *config) +{ + base->LVDSC1 = (uint8_t)((0U | +#if (defined(FSL_FEATURE_PMC_HAS_LVDV) && FSL_FEATURE_PMC_HAS_LVDV) + ((uint32_t)config->voltSelect << PMC_LVDSC1_LVDV_SHIFT) | +#endif + ((uint32_t)config->enableInt << PMC_LVDSC1_LVDIE_SHIFT) | + ((uint32_t)config->enableReset << PMC_LVDSC1_LVDRE_SHIFT) + /* Clear the Low Voltage Detect Flag with previous power detect setting */ + | PMC_LVDSC1_LVDACK_MASK)); +} + +/*! + * brief Configures the low-voltage warning setting. + * + * This function configures the low-voltage warning setting, including the trip + * point voltage setting and enabling or disabling the interrupt. + * + * param base PMC peripheral base address. + * param config Low-voltage warning configuration structure. + */ +void PMC_ConfigureLowVoltWarning(PMC_Type *base, const pmc_low_volt_warning_config_t *config) +{ + base->LVDSC2 = (uint8_t)((0U | +#if (defined(FSL_FEATURE_PMC_HAS_LVWV) && FSL_FEATURE_PMC_HAS_LVWV) + ((uint32_t)config->voltSelect << PMC_LVDSC2_LVWV_SHIFT) | +#endif + ((uint32_t)config->enableInt << PMC_LVDSC2_LVWIE_SHIFT) + /* Clear the Low Voltage Warning Flag with previous power detect setting */ + | PMC_LVDSC2_LVWACK_MASK)); +} + +#if (defined(FSL_FEATURE_PMC_HAS_HVDSC1) && FSL_FEATURE_PMC_HAS_HVDSC1) +/*! + * brief Configures the high-voltage detect setting. + * + * This function configures the high-voltage detect setting, including the trip + * point voltage setting, enabling or disabling the interrupt, enabling or disabling the system reset. + * + * param base PMC peripheral base address. + * param config High-voltage detect configuration structure. + */ +void PMC_ConfigureHighVoltDetect(PMC_Type *base, const pmc_high_volt_detect_config_t *config) +{ + base->HVDSC1 = (((uint32_t)config->voltSelect << PMC_HVDSC1_HVDV_SHIFT) | + ((uint32_t)config->enableInt << PMC_HVDSC1_HVDIE_SHIFT) | + ((uint32_t)config->enableReset << PMC_HVDSC1_HVDRE_SHIFT) + /* Clear the High Voltage Detect Flag with previous power detect setting */ + | PMC_HVDSC1_HVDACK_MASK); +} +#endif /* FSL_FEATURE_PMC_HAS_HVDSC1 */ + +#if ((defined(FSL_FEATURE_PMC_HAS_BGBE) && FSL_FEATURE_PMC_HAS_BGBE) || \ + (defined(FSL_FEATURE_PMC_HAS_BGEN) && FSL_FEATURE_PMC_HAS_BGEN) || \ + (defined(FSL_FEATURE_PMC_HAS_BGBDS) && FSL_FEATURE_PMC_HAS_BGBDS)) +/*! + * brief Configures the PMC bandgap. + * + * This function configures the PMC bandgap, including the drive select and + * behavior in low-power mode. + * + * param base PMC peripheral base address. + * param config Pointer to the configuration structure + */ +void PMC_ConfigureBandgapBuffer(PMC_Type *base, const pmc_bandgap_buffer_config_t *config) +{ + base->REGSC = (uint8_t)(0U +#if (defined(FSL_FEATURE_PMC_HAS_BGBE) && FSL_FEATURE_PMC_HAS_BGBE) + | ((uint32_t)config->enable << PMC_REGSC_BGBE_SHIFT) +#endif /* FSL_FEATURE_PMC_HAS_BGBE */ +#if (defined(FSL_FEATURE_PMC_HAS_BGEN) && FSL_FEATURE_PMC_HAS_BGEN) + | (((uint32_t)config->enableInLowPowerMode << PMC_REGSC_BGEN_SHIFT)) +#endif /* FSL_FEATURE_PMC_HAS_BGEN */ +#if (defined(FSL_FEATURE_PMC_HAS_BGBDS) && FSL_FEATURE_PMC_HAS_BGBDS) + | ((uint32_t)config->drive << PMC_REGSC_BGBDS_SHIFT) +#endif /* FSL_FEATURE_PMC_HAS_BGBDS */ + ); +} +#endif diff --git a/source/hic_hal/freescale/kl27z/fsl_pmc.h b/source/hic_hal/freescale/kl27z/fsl_pmc.h new file mode 100644 index 000000000..adcee6512 --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_pmc.h @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_PMC_H_ +#define _FSL_PMC_H_ + +#include "fsl_common.h" + +/*! @addtogroup pmc */ +/*! @{ */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +/*! @brief PMC driver version */ +#define FSL_PMC_DRIVER_VERSION (MAKE_VERSION(2, 0, 1)) /*!< Version 2.0.1. */ +/*@}*/ + +#if (defined(FSL_FEATURE_PMC_HAS_LVDV) && FSL_FEATURE_PMC_HAS_LVDV) +/*! + * @brief Low-voltage Detect Voltage Select + */ +typedef enum _pmc_low_volt_detect_volt_select +{ + kPMC_LowVoltDetectLowTrip = 0U, /*!< Low-trip point selected (VLVD = VLVDL )*/ + kPMC_LowVoltDetectHighTrip = 1U /*!< High-trip point selected (VLVD = VLVDH )*/ +} pmc_low_volt_detect_volt_select_t; +#endif + +#if (defined(FSL_FEATURE_PMC_HAS_LVWV) && FSL_FEATURE_PMC_HAS_LVWV) +/*! + * @brief Low-voltage Warning Voltage Select + */ +typedef enum _pmc_low_volt_warning_volt_select +{ + kPMC_LowVoltWarningLowTrip = 0U, /*!< Low-trip point selected (VLVW = VLVW1)*/ + kPMC_LowVoltWarningMid1Trip = 1U, /*!< Mid 1 trip point selected (VLVW = VLVW2)*/ + kPMC_LowVoltWarningMid2Trip = 2U, /*!< Mid 2 trip point selected (VLVW = VLVW3)*/ + kPMC_LowVoltWarningHighTrip = 3U /*!< High-trip point selected (VLVW = VLVW4)*/ +} pmc_low_volt_warning_volt_select_t; +#endif + +#if (defined(FSL_FEATURE_PMC_HAS_HVDSC1) && FSL_FEATURE_PMC_HAS_HVDSC1) +/*! + * @brief High-voltage Detect Voltage Select + */ +typedef enum _pmc_high_volt_detect_volt_select +{ + kPMC_HighVoltDetectLowTrip = 0U, /*!< Low-trip point selected (VHVD = VHVDL )*/ + kPMC_HighVoltDetectHighTrip = 1U /*!< High-trip point selected (VHVD = VHVDH )*/ +} pmc_high_volt_detect_volt_select_t; +#endif /* FSL_FEATURE_PMC_HAS_HVDSC1 */ + +#if (defined(FSL_FEATURE_PMC_HAS_BGBDS) && FSL_FEATURE_PMC_HAS_BGBDS) +/*! + * @brief Bandgap Buffer Drive Select. + */ +typedef enum _pmc_bandgap_buffer_drive_select +{ + kPMC_BandgapBufferDriveLow = 0U, /*!< Low-drive. */ + kPMC_BandgapBufferDriveHigh = 1U /*!< High-drive. */ +} pmc_bandgap_buffer_drive_select_t; +#endif /* FSL_FEATURE_PMC_HAS_BGBDS */ + +#if (defined(FSL_FEATURE_PMC_HAS_VLPO) && FSL_FEATURE_PMC_HAS_VLPO) +/*! + * @brief VLPx Option + */ +typedef enum _pmc_vlp_freq_option +{ + kPMC_FreqRestrict = 0U, /*!< Frequency is restricted in VLPx mode. */ + kPMC_FreqUnrestrict = 1U /*!< Frequency is unrestricted in VLPx mode. */ +} pmc_vlp_freq_mode_t; +#endif /* FSL_FEATURE_PMC_HAS_VLPO */ + +#if (defined(FSL_FEATURE_PMC_HAS_VERID) && FSL_FEATURE_PMC_HAS_VERID) +/*! + @brief IP version ID definition. + */ +typedef struct _pmc_version_id +{ + uint16_t feature; /*!< Feature Specification Number. */ + uint8_t minor; /*!< Minor version number. */ + uint8_t major; /*!< Major version number. */ +} pmc_version_id_t; +#endif /* FSL_FEATURE_PMC_HAS_VERID */ + +#if (defined(FSL_FEATURE_PMC_HAS_PARAM) && FSL_FEATURE_PMC_HAS_PARAM) +/*! @brief IP parameter definition. */ +typedef struct _pmc_param +{ + bool vlpoEnable; /*!< VLPO enable. */ + bool hvdEnable; /*!< HVD enable. */ +} pmc_param_t; +#endif /* FSL_FEATURE_PMC_HAS_PARAM */ + +/*! + * @brief Low-voltage Detect Configuration Structure + */ +typedef struct _pmc_low_volt_detect_config +{ + bool enableInt; /*!< Enable interrupt when Low-voltage detect*/ + bool enableReset; /*!< Enable system reset when Low-voltage detect*/ +#if (defined(FSL_FEATURE_PMC_HAS_LVDV) && FSL_FEATURE_PMC_HAS_LVDV) + pmc_low_volt_detect_volt_select_t voltSelect; /*!< Low-voltage detect trip point voltage selection*/ +#endif +} pmc_low_volt_detect_config_t; + +/*! + * @brief Low-voltage Warning Configuration Structure + */ +typedef struct _pmc_low_volt_warning_config +{ + bool enableInt; /*!< Enable interrupt when low-voltage warning*/ +#if (defined(FSL_FEATURE_PMC_HAS_LVWV) && FSL_FEATURE_PMC_HAS_LVWV) + pmc_low_volt_warning_volt_select_t voltSelect; /*!< Low-voltage warning trip point voltage selection*/ +#endif +} pmc_low_volt_warning_config_t; + +#if (defined(FSL_FEATURE_PMC_HAS_HVDSC1) && FSL_FEATURE_PMC_HAS_HVDSC1) +/*! + * @brief High-voltage Detect Configuration Structure + */ +typedef struct _pmc_high_volt_detect_config +{ + bool enableInt; /*!< Enable interrupt when high-voltage detect*/ + bool enableReset; /*!< Enable system reset when high-voltage detect*/ + pmc_high_volt_detect_volt_select_t voltSelect; /*!< High-voltage detect trip point voltage selection*/ +} pmc_high_volt_detect_config_t; +#endif /* FSL_FEATURE_PMC_HAS_HVDSC1 */ + +#if ((defined(FSL_FEATURE_PMC_HAS_BGBE) && FSL_FEATURE_PMC_HAS_BGBE) || \ + (defined(FSL_FEATURE_PMC_HAS_BGEN) && FSL_FEATURE_PMC_HAS_BGEN) || \ + (defined(FSL_FEATURE_PMC_HAS_BGBDS) && FSL_FEATURE_PMC_HAS_BGBDS)) +/*! + * @brief Bandgap Buffer configuration. + */ +typedef struct _pmc_bandgap_buffer_config +{ +#if (defined(FSL_FEATURE_PMC_HAS_BGBE) && FSL_FEATURE_PMC_HAS_BGBE) + bool enable; /*!< Enable bandgap buffer. */ +#endif +#if (defined(FSL_FEATURE_PMC_HAS_BGEN) && FSL_FEATURE_PMC_HAS_BGEN) + bool enableInLowPowerMode; /*!< Enable bandgap buffer in low-power mode. */ +#endif /* FSL_FEATURE_PMC_HAS_BGEN */ +#if (defined(FSL_FEATURE_PMC_HAS_BGBDS) && FSL_FEATURE_PMC_HAS_BGBDS) + pmc_bandgap_buffer_drive_select_t drive; /*!< Bandgap buffer drive select. */ +#endif /* FSL_FEATURE_PMC_HAS_BGBDS */ +} pmc_bandgap_buffer_config_t; +#endif + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! @name Power Management Controller Control APIs*/ +/*@{*/ + +#if (defined(FSL_FEATURE_PMC_HAS_VERID) && FSL_FEATURE_PMC_HAS_VERID) +/*! + * @brief Gets the PMC version ID. + * + * This function gets the PMC version ID, including major version number, + * minor version number, and a feature specification number. + * + * @param base PMC peripheral base address. + * @param versionId Pointer to version ID structure. + */ +static inline void PMC_GetVersionId(PMC_Type *base, pmc_version_id_t *versionId) +{ + *((uint32_t *)versionId) = base->VERID; +} +#endif /* FSL_FEATURE_PMC_HAS_VERID */ + +#if (defined(FSL_FEATURE_PMC_HAS_PARAM) && FSL_FEATURE_PMC_HAS_PARAM) +/*! + * @brief Gets the PMC parameter. + * + * This function gets the PMC parameter including the VLPO enable and the HVD enable. + * + * @param base PMC peripheral base address. + * @param param Pointer to PMC param structure. + */ +void PMC_GetParam(PMC_Type *base, pmc_param_t *param); +#endif + +/*! + * @brief Configures the low-voltage detect setting. + * + * This function configures the low-voltage detect setting, including the trip + * point voltage setting, enables or disables the interrupt, enables or disables the system reset. + * + * @param base PMC peripheral base address. + * @param config Low-voltage detect configuration structure. + */ +void PMC_ConfigureLowVoltDetect(PMC_Type *base, const pmc_low_volt_detect_config_t *config); + +/*! + * @brief Gets the Low-voltage Detect Flag status. + * + * This function reads the current LVDF status. If it returns 1, a low-voltage event is detected. + * + * @param base PMC peripheral base address. + * @return Current low-voltage detect flag + * - true: Low-voltage detected + * - false: Low-voltage not detected + */ +static inline bool PMC_GetLowVoltDetectFlag(PMC_Type *base) +{ + if (0U != (base->LVDSC1 & PMC_LVDSC1_LVDF_MASK)) + { + return true; + } + else + { + return false; + } +} + +/*! + * @brief Acknowledges clearing the Low-voltage Detect flag. + * + * This function acknowledges the low-voltage detection errors (write 1 to + * clear LVDF). + * + * @param base PMC peripheral base address. + */ +static inline void PMC_ClearLowVoltDetectFlag(PMC_Type *base) +{ + base->LVDSC1 |= PMC_LVDSC1_LVDACK_MASK; +} + +/*! + * @brief Configures the low-voltage warning setting. + * + * This function configures the low-voltage warning setting, including the trip + * point voltage setting and enabling or disabling the interrupt. + * + * @param base PMC peripheral base address. + * @param config Low-voltage warning configuration structure. + */ +void PMC_ConfigureLowVoltWarning(PMC_Type *base, const pmc_low_volt_warning_config_t *config); + +/*! + * @brief Gets the Low-voltage Warning Flag status. + * + * This function polls the current LVWF status. When 1 is returned, it + * indicates a low-voltage warning event. LVWF is set when V Supply transitions + * below the trip point or after reset and V Supply is already below the V LVW. + * + * @param base PMC peripheral base address. + * @return Current LVWF status + * - true: Low-voltage Warning Flag is set. + * - false: the Low-voltage Warning does not happen. + */ +static inline bool PMC_GetLowVoltWarningFlag(PMC_Type *base) +{ + if (0U != (base->LVDSC2 & PMC_LVDSC2_LVWF_MASK)) + { + return true; + } + else + { + return false; + } +} + +/*! + * @brief Acknowledges the Low-voltage Warning flag. + * + * This function acknowledges the low voltage warning errors (write 1 to + * clear LVWF). + * + * @param base PMC peripheral base address. + */ +static inline void PMC_ClearLowVoltWarningFlag(PMC_Type *base) +{ + base->LVDSC2 |= PMC_LVDSC2_LVWACK_MASK; +} + +#if (defined(FSL_FEATURE_PMC_HAS_HVDSC1) && FSL_FEATURE_PMC_HAS_HVDSC1) +/*! + * @brief Configures the high-voltage detect setting. + * + * This function configures the high-voltage detect setting, including the trip + * point voltage setting, enabling or disabling the interrupt, enabling or disabling the system reset. + * + * @param base PMC peripheral base address. + * @param config High-voltage detect configuration structure. + */ +void PMC_ConfigureHighVoltDetect(PMC_Type *base, const pmc_high_volt_detect_config_t *config); + +/*! + * @brief Gets the High-voltage Detect Flag status. + * + * This function reads the current HVDF status. If it returns 1, a low + * voltage event is detected. + * + * @param base PMC peripheral base address. + * @return Current high-voltage detect flag + * - true: High-voltage detected + * - false: High-voltage not detected + */ +static inline bool PMC_GetHighVoltDetectFlag(PMC_Type *base) +{ + return (bool)(base->HVDSC1 & PMC_HVDSC1_HVDF_MASK); +} + +/*! + * @brief Acknowledges clearing the High-voltage Detect flag. + * + * This function acknowledges the high-voltage detection errors (write 1 to + * clear HVDF). + * + * @param base PMC peripheral base address. + */ +static inline void PMC_ClearHighVoltDetectFlag(PMC_Type *base) +{ + base->HVDSC1 |= PMC_HVDSC1_HVDACK_MASK; +} +#endif /* FSL_FEATURE_PMC_HAS_HVDSC1 */ + +#if ((defined(FSL_FEATURE_PMC_HAS_BGBE) && FSL_FEATURE_PMC_HAS_BGBE) || \ + (defined(FSL_FEATURE_PMC_HAS_BGEN) && FSL_FEATURE_PMC_HAS_BGEN) || \ + (defined(FSL_FEATURE_PMC_HAS_BGBDS) && FSL_FEATURE_PMC_HAS_BGBDS)) +/*! + * @brief Configures the PMC bandgap. + * + * This function configures the PMC bandgap, including the drive select and + * behavior in low-power mode. + * + * @param base PMC peripheral base address. + * @param config Pointer to the configuration structure + */ +void PMC_ConfigureBandgapBuffer(PMC_Type *base, const pmc_bandgap_buffer_config_t *config); +#endif + +#if (defined(FSL_FEATURE_PMC_HAS_ACKISO) && FSL_FEATURE_PMC_HAS_ACKISO) +/*! + * @brief Gets the acknowledge Peripherals and I/O pads isolation flag. + * + * This function reads the Acknowledge Isolation setting that indicates + * whether certain peripherals and the I/O pads are in a latched state as + * a result of having been in the VLLS mode. + * + * @param base PMC peripheral base address. + * @param base Base address for current PMC instance. + * @return ACK isolation + * 0 - Peripherals and I/O pads are in a normal run state. + * 1 - Certain peripherals and I/O pads are in an isolated and + * latched state. + */ +static inline bool PMC_GetPeriphIOIsolationFlag(PMC_Type *base) +{ + return (0U != (base->REGSC & PMC_REGSC_ACKISO_MASK)) ? true : false; +} + +/*! + * @brief Acknowledges the isolation flag to Peripherals and I/O pads. + * + * This function clears the ACK Isolation flag. Writing one to this setting + * when it is set releases the I/O pads and certain peripherals to their normal + * run mode state. + * + * @param base PMC peripheral base address. + */ +static inline void PMC_ClearPeriphIOIsolationFlag(PMC_Type *base) +{ + base->REGSC |= PMC_REGSC_ACKISO_MASK; +} +#endif /* FSL_FEATURE_PMC_HAS_ACKISO */ + +#if (defined(FSL_FEATURE_PMC_HAS_REGONS) && FSL_FEATURE_PMC_HAS_REGONS) +/*! + * @brief Gets the regulator regulation status. + * + * This function returns the regulator to run a regulation status. It provides + * the current status of the internal voltage regulator. + * + * @param base PMC peripheral base address. + * @param base Base address for current PMC instance. + * @return Regulation status + * 0 - Regulator is in a stop regulation or in transition to/from the regulation. + * 1 - Regulator is in a run regulation. + * + */ +static inline bool PMC_IsRegulatorInRunRegulation(PMC_Type *base) +{ + if (0U != (base->REGSC & PMC_REGSC_REGONS_MASK)) + { + return true; + } + else + { + return false; + } +} +#endif /* FSL_FEATURE_PMC_HAS_REGONS */ + +/*@}*/ + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/*! @}*/ + +#endif /* _FSL_PMC_H_*/ diff --git a/source/hic_hal/freescale/kl27z/fsl_port.h b/source/hic_hal/freescale/kl27z/fsl_port.h new file mode 100644 index 000000000..128047bd2 --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_port.h @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_PORT_H_ +#define _FSL_PORT_H_ + +#include "fsl_common.h" + +/*! + * @addtogroup port + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.port" +#endif + +/*! @name Driver version */ +/*@{*/ +/*! Version 2.1.0. */ +#define FSL_PORT_DRIVER_VERSION (MAKE_VERSION(2, 1, 0)) +/*@}*/ + +#if defined(FSL_FEATURE_PORT_HAS_PULL_ENABLE) && FSL_FEATURE_PORT_HAS_PULL_ENABLE +/*! @brief Internal resistor pull feature selection */ +enum _port_pull +{ + kPORT_PullDisable = 0U, /*!< Internal pull-up/down resistor is disabled. */ + kPORT_PullDown = 2U, /*!< Internal pull-down resistor is enabled. */ + kPORT_PullUp = 3U, /*!< Internal pull-up resistor is enabled. */ +}; +#endif /* FSL_FEATURE_PORT_HAS_PULL_ENABLE */ + +#if defined(FSL_FEATURE_PORT_HAS_SLEW_RATE) && FSL_FEATURE_PORT_HAS_SLEW_RATE +/*! @brief Slew rate selection */ +enum _port_slew_rate +{ + kPORT_FastSlewRate = 0U, /*!< Fast slew rate is configured. */ + kPORT_SlowSlewRate = 1U, /*!< Slow slew rate is configured. */ +}; +#endif /* FSL_FEATURE_PORT_HAS_SLEW_RATE */ + +#if defined(FSL_FEATURE_PORT_HAS_OPEN_DRAIN) && FSL_FEATURE_PORT_HAS_OPEN_DRAIN +/*! @brief Open Drain feature enable/disable */ +enum _port_open_drain_enable +{ + kPORT_OpenDrainDisable = 0U, /*!< Open drain output is disabled. */ + kPORT_OpenDrainEnable = 1U, /*!< Open drain output is enabled. */ +}; +#endif /* FSL_FEATURE_PORT_HAS_OPEN_DRAIN */ + +#if defined(FSL_FEATURE_PORT_HAS_PASSIVE_FILTER) && FSL_FEATURE_PORT_HAS_PASSIVE_FILTER +/*! @brief Passive filter feature enable/disable */ +enum _port_passive_filter_enable +{ + kPORT_PassiveFilterDisable = 0U, /*!< Passive input filter is disabled. */ + kPORT_PassiveFilterEnable = 1U, /*!< Passive input filter is enabled. */ +}; +#endif + +#if defined(FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH) && FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH +/*! @brief Configures the drive strength. */ +enum _port_drive_strength +{ + kPORT_LowDriveStrength = 0U, /*!< Low-drive strength is configured. */ + kPORT_HighDriveStrength = 1U, /*!< High-drive strength is configured. */ +}; +#endif /* FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH */ + +#if defined(FSL_FEATURE_PORT_HAS_PIN_CONTROL_LOCK) && FSL_FEATURE_PORT_HAS_PIN_CONTROL_LOCK +/*! @brief Unlock/lock the pin control register field[15:0] */ +enum _port_lock_register +{ + kPORT_UnlockRegister = 0U, /*!< Pin Control Register fields [15:0] are not locked. */ + kPORT_LockRegister = 1U, /*!< Pin Control Register fields [15:0] are locked. */ +}; +#endif /* FSL_FEATURE_PORT_HAS_PIN_CONTROL_LOCK */ + +#if defined(FSL_FEATURE_PORT_PCR_MUX_WIDTH) && FSL_FEATURE_PORT_PCR_MUX_WIDTH +/*! @brief Pin mux selection */ +typedef enum _port_mux +{ + kPORT_PinDisabledOrAnalog = 0U, /*!< Corresponding pin is disabled, but is used as an analog pin. */ + kPORT_MuxAsGpio = 1U, /*!< Corresponding pin is configured as GPIO. */ + kPORT_MuxAlt2 = 2U, /*!< Chip-specific */ + kPORT_MuxAlt3 = 3U, /*!< Chip-specific */ + kPORT_MuxAlt4 = 4U, /*!< Chip-specific */ + kPORT_MuxAlt5 = 5U, /*!< Chip-specific */ + kPORT_MuxAlt6 = 6U, /*!< Chip-specific */ + kPORT_MuxAlt7 = 7U, /*!< Chip-specific */ + kPORT_MuxAlt8 = 8U, /*!< Chip-specific */ + kPORT_MuxAlt9 = 9U, /*!< Chip-specific */ + kPORT_MuxAlt10 = 10U, /*!< Chip-specific */ + kPORT_MuxAlt11 = 11U, /*!< Chip-specific */ + kPORT_MuxAlt12 = 12U, /*!< Chip-specific */ + kPORT_MuxAlt13 = 13U, /*!< Chip-specific */ + kPORT_MuxAlt14 = 14U, /*!< Chip-specific */ + kPORT_MuxAlt15 = 15U, /*!< Chip-specific */ +} port_mux_t; +#endif /* FSL_FEATURE_PORT_PCR_MUX_WIDTH */ + +#if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) +/*! @brief Configures the interrupt generation condition. */ +typedef enum _port_interrupt +{ + kPORT_InterruptOrDMADisabled = 0x0U, /*!< Interrupt/DMA request is disabled. */ +#if defined(FSL_FEATURE_PORT_HAS_DMA_REQUEST) && FSL_FEATURE_PORT_HAS_DMA_REQUEST + kPORT_DMARisingEdge = 0x1U, /*!< DMA request on rising edge. */ + kPORT_DMAFallingEdge = 0x2U, /*!< DMA request on falling edge. */ + kPORT_DMAEitherEdge = 0x3U, /*!< DMA request on either edge. */ +#endif +#if defined(FSL_FEATURE_PORT_HAS_IRQC_FLAG) && FSL_FEATURE_PORT_HAS_IRQC_FLAG + kPORT_FlagRisingEdge = 0x05U, /*!< Flag sets on rising edge. */ + kPORT_FlagFallingEdge = 0x06U, /*!< Flag sets on falling edge. */ + kPORT_FlagEitherEdge = 0x07U, /*!< Flag sets on either edge. */ +#endif + kPORT_InterruptLogicZero = 0x8U, /*!< Interrupt when logic zero. */ + kPORT_InterruptRisingEdge = 0x9U, /*!< Interrupt on rising edge. */ + kPORT_InterruptFallingEdge = 0xAU, /*!< Interrupt on falling edge. */ + kPORT_InterruptEitherEdge = 0xBU, /*!< Interrupt on either edge. */ + kPORT_InterruptLogicOne = 0xCU, /*!< Interrupt when logic one. */ +#if defined(FSL_FEATURE_PORT_HAS_IRQC_TRIGGER) && FSL_FEATURE_PORT_HAS_IRQC_TRIGGER + kPORT_ActiveHighTriggerOutputEnable = 0xDU, /*!< Enable active high-trigger output. */ + kPORT_ActiveLowTriggerOutputEnable = 0xEU, /*!< Enable active low-trigger output. */ +#endif +} port_interrupt_t; +#endif + +#if defined(FSL_FEATURE_PORT_HAS_DIGITAL_FILTER) && FSL_FEATURE_PORT_HAS_DIGITAL_FILTER +/*! @brief Digital filter clock source selection */ +typedef enum _port_digital_filter_clock_source +{ + kPORT_BusClock = 0U, /*!< Digital filters are clocked by the bus clock. */ + kPORT_LpoClock = 1U, /*!< Digital filters are clocked by the 1 kHz LPO clock. */ +} port_digital_filter_clock_source_t; + +/*! @brief PORT digital filter feature configuration definition */ +typedef struct _port_digital_filter_config +{ + uint32_t digitalFilterWidth; /*!< Set digital filter width */ + port_digital_filter_clock_source_t clockSource; /*!< Set digital filter clockSource */ +} port_digital_filter_config_t; +#endif /* FSL_FEATURE_PORT_HAS_DIGITAL_FILTER */ + +#if defined(FSL_FEATURE_PORT_PCR_MUX_WIDTH) && FSL_FEATURE_PORT_PCR_MUX_WIDTH +/*! @brief PORT pin configuration structure */ +typedef struct _port_pin_config +{ +#if defined(FSL_FEATURE_PORT_HAS_PULL_ENABLE) && FSL_FEATURE_PORT_HAS_PULL_ENABLE + uint16_t pullSelect : 2; /*!< No-pull/pull-down/pull-up select */ +#else + uint16_t : 2; +#endif /* FSL_FEATURE_PORT_HAS_PULL_ENABLE */ + +#if defined(FSL_FEATURE_PORT_HAS_SLEW_RATE) && FSL_FEATURE_PORT_HAS_SLEW_RATE + uint16_t slewRate : 1; /*!< Fast/slow slew rate Configure */ +#else + uint16_t : 1; +#endif /* FSL_FEATURE_PORT_HAS_SLEW_RATE */ + + uint16_t : 1; + +#if defined(FSL_FEATURE_PORT_HAS_PASSIVE_FILTER) && FSL_FEATURE_PORT_HAS_PASSIVE_FILTER + uint16_t passiveFilterEnable : 1; /*!< Passive filter enable/disable */ +#else + uint16_t : 1; +#endif /* FSL_FEATURE_PORT_HAS_PASSIVE_FILTER */ + +#if defined(FSL_FEATURE_PORT_HAS_OPEN_DRAIN) && FSL_FEATURE_PORT_HAS_OPEN_DRAIN + uint16_t openDrainEnable : 1; /*!< Open drain enable/disable */ +#else + uint16_t : 1; +#endif /* FSL_FEATURE_PORT_HAS_OPEN_DRAIN */ + +#if defined(FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH) && FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH + uint16_t driveStrength : 1; /*!< Fast/slow drive strength configure */ +#else + uint16_t : 1; +#endif + + uint16_t : 1; + +#if defined(FSL_FEATURE_PORT_PCR_MUX_WIDTH) && (FSL_FEATURE_PORT_PCR_MUX_WIDTH == 3) + uint16_t mux : 3; /*!< Pin mux Configure */ + uint16_t : 4; +#elif defined(FSL_FEATURE_PORT_PCR_MUX_WIDTH) && (FSL_FEATURE_PORT_PCR_MUX_WIDTH == 4) + uint16_t mux : 4; /*!< Pin mux Configure */ + uint16_t : 3; +#else + uint16_t : 7, +#endif + +#if defined(FSL_FEATURE_PORT_HAS_PIN_CONTROL_LOCK) && FSL_FEATURE_PORT_HAS_PIN_CONTROL_LOCK + uint16_t lockRegister : 1; /*!< Lock/unlock the PCR field[15:0] */ +#else + uint16_t : 1; +#endif /* FSL_FEATURE_PORT_HAS_PIN_CONTROL_LOCK */ +} port_pin_config_t; +#endif /* FSL_FEATURE_PORT_PCR_MUX_WIDTH */ + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(FSL_FEATURE_PORT_PCR_MUX_WIDTH) && FSL_FEATURE_PORT_PCR_MUX_WIDTH +/*! @name Configuration */ +/*@{*/ + +/*! + * @brief Sets the port PCR register. + * + * This is an example to define an input pin or output pin PCR configuration. + * @code + * // Define a digital input pin PCR configuration + * port_pin_config_t config = { + * kPORT_PullUp, + * kPORT_FastSlewRate, + * kPORT_PassiveFilterDisable, + * kPORT_OpenDrainDisable, + * kPORT_LowDriveStrength, + * kPORT_MuxAsGpio, + * kPORT_UnLockRegister, + * }; + * @endcode + * + * @param base PORT peripheral base pointer. + * @param pin PORT pin number. + * @param config PORT PCR register configuration structure. + */ +static inline void PORT_SetPinConfig(PORT_Type *base, uint32_t pin, const port_pin_config_t *config) +{ + assert(config); + uint32_t addr = (uint32_t)&base->PCR[pin]; + *(volatile uint16_t *)(addr) = *((const uint16_t *)config); +} + +/*! + * @brief Sets the port PCR register for multiple pins. + * + * This is an example to define input pins or output pins PCR configuration. + * @code + * // Define a digital input pin PCR configuration + * port_pin_config_t config = { + * kPORT_PullUp , + * kPORT_PullEnable, + * kPORT_FastSlewRate, + * kPORT_PassiveFilterDisable, + * kPORT_OpenDrainDisable, + * kPORT_LowDriveStrength, + * kPORT_MuxAsGpio, + * kPORT_UnlockRegister, + * }; + * @endcode + * + * @param base PORT peripheral base pointer. + * @param mask PORT pin number macro. + * @param config PORT PCR register configuration structure. + */ +static inline void PORT_SetMultiplePinsConfig(PORT_Type *base, uint32_t mask, const port_pin_config_t *config) +{ + assert(config); + + uint16_t pcrl = *((const uint16_t *)config); + + if (mask & 0xffffU) + { + base->GPCLR = ((mask & 0xffffU) << 16) | pcrl; + } + if (mask >> 16) + { + base->GPCHR = (mask & 0xffff0000U) | pcrl; + } +} + +#if defined(FSL_FEATURE_PORT_HAS_MULTIPLE_IRQ_CONFIG) && FSL_FEATURE_PORT_HAS_MULTIPLE_IRQ_CONFIG +/*! + * @brief Sets the port interrupt configuration in PCR register for multiple pins. + * + * @param base PORT peripheral base pointer. + * @param mask PORT pin number macro. + * @param config PORT pin interrupt configuration. + * - #kPORT_InterruptOrDMADisabled: Interrupt/DMA request disabled. + * - #kPORT_DMARisingEdge : DMA request on rising edge(if the DMA requests exit). + * - #kPORT_DMAFallingEdge: DMA request on falling edge(if the DMA requests exit). + * - #kPORT_DMAEitherEdge : DMA request on either edge(if the DMA requests exit). + * - #kPORT_FlagRisingEdge : Flag sets on rising edge(if the Flag states exit). + * - #kPORT_FlagFallingEdge : Flag sets on falling edge(if the Flag states exit). + * - #kPORT_FlagEitherEdge : Flag sets on either edge(if the Flag states exit). + * - #kPORT_InterruptLogicZero : Interrupt when logic zero. + * - #kPORT_InterruptRisingEdge : Interrupt on rising edge. + * - #kPORT_InterruptFallingEdge: Interrupt on falling edge. + * - #kPORT_InterruptEitherEdge : Interrupt on either edge. + * - #kPORT_InterruptLogicOne : Interrupt when logic one. + * - #kPORT_ActiveHighTriggerOutputEnable : Enable active high-trigger output (if the trigger states exit). + * - #kPORT_ActiveLowTriggerOutputEnable : Enable active low-trigger output (if the trigger states exit).. + */ +static inline void PORT_SetMultipleInterruptPinsConfig(PORT_Type *base, uint32_t mask, port_interrupt_t config) +{ + assert(config); + + if (mask & 0xffffU) + { + base->GICLR = (config << 16) | (mask & 0xffffU); + } + mask = mask >> 16; + if (mask) + { + base->GICHR = (config << 16) | (mask & 0xffffU); + } +} +#endif + +/*! + * @brief Configures the pin muxing. + * + * @param base PORT peripheral base pointer. + * @param pin PORT pin number. + * @param mux pin muxing slot selection. + * - #kPORT_PinDisabledOrAnalog: Pin disabled or work in analog function. + * - #kPORT_MuxAsGpio : Set as GPIO. + * - #kPORT_MuxAlt2 : chip-specific. + * - #kPORT_MuxAlt3 : chip-specific. + * - #kPORT_MuxAlt4 : chip-specific. + * - #kPORT_MuxAlt5 : chip-specific. + * - #kPORT_MuxAlt6 : chip-specific. + * - #kPORT_MuxAlt7 : chip-specific. + * @Note : This function is NOT recommended to use together with the PORT_SetPinsConfig, because + * the PORT_SetPinsConfig need to configure the pin mux anyway (Otherwise the pin mux is + * reset to zero : kPORT_PinDisabledOrAnalog). + * This function is recommended to use to reset the pin mux + * + */ +static inline void PORT_SetPinMux(PORT_Type *base, uint32_t pin, port_mux_t mux) +{ + base->PCR[pin] = (base->PCR[pin] & ~PORT_PCR_MUX_MASK) | PORT_PCR_MUX(mux); +} +#endif /* FSL_FEATURE_PORT_PCR_MUX_WIDTH */ + +#if defined(FSL_FEATURE_PORT_HAS_DIGITAL_FILTER) && FSL_FEATURE_PORT_HAS_DIGITAL_FILTER + +/*! + * @brief Enables the digital filter in one port, each bit of the 32-bit register represents one pin. + * + * @param base PORT peripheral base pointer. + * @param mask PORT pin number macro. + */ +static inline void PORT_EnablePinsDigitalFilter(PORT_Type *base, uint32_t mask, bool enable) +{ + if (enable == true) + { + base->DFER |= mask; + } + else + { + base->DFER &= ~mask; + } +} + +/*! + * @brief Sets the digital filter in one port, each bit of the 32-bit register represents one pin. + * + * @param base PORT peripheral base pointer. + * @param config PORT digital filter configuration structure. + */ +static inline void PORT_SetDigitalFilterConfig(PORT_Type *base, const port_digital_filter_config_t *config) +{ + assert(config); + + base->DFCR = PORT_DFCR_CS(config->clockSource); + base->DFWR = PORT_DFWR_FILT(config->digitalFilterWidth); +} + +#endif /* FSL_FEATURE_PORT_HAS_DIGITAL_FILTER */ + +/*@}*/ + +/*! @name Interrupt */ +/*@{*/ + +#if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) +/*! + * @brief Configures the port pin interrupt/DMA request. + * + * @param base PORT peripheral base pointer. + * @param pin PORT pin number. + * @param config PORT pin interrupt configuration. + * - #kPORT_InterruptOrDMADisabled: Interrupt/DMA request disabled. + * - #kPORT_DMARisingEdge : DMA request on rising edge(if the DMA requests exit). + * - #kPORT_DMAFallingEdge: DMA request on falling edge(if the DMA requests exit). + * - #kPORT_DMAEitherEdge : DMA request on either edge(if the DMA requests exit). + * - #kPORT_FlagRisingEdge : Flag sets on rising edge(if the Flag states exit). + * - #kPORT_FlagFallingEdge : Flag sets on falling edge(if the Flag states exit). + * - #kPORT_FlagEitherEdge : Flag sets on either edge(if the Flag states exit). + * - #kPORT_InterruptLogicZero : Interrupt when logic zero. + * - #kPORT_InterruptRisingEdge : Interrupt on rising edge. + * - #kPORT_InterruptFallingEdge: Interrupt on falling edge. + * - #kPORT_InterruptEitherEdge : Interrupt on either edge. + * - #kPORT_InterruptLogicOne : Interrupt when logic one. + * - #kPORT_ActiveHighTriggerOutputEnable : Enable active high-trigger output (if the trigger states exit). + * - #kPORT_ActiveLowTriggerOutputEnable : Enable active low-trigger output (if the trigger states exit). + */ +static inline void PORT_SetPinInterruptConfig(PORT_Type *base, uint32_t pin, port_interrupt_t config) +{ + base->PCR[pin] = (base->PCR[pin] & ~PORT_PCR_IRQC_MASK) | PORT_PCR_IRQC(config); +} +#endif + +#if defined(FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH) && FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH +/*! + * @brief Configures the port pin drive strength. + * + * @param base PORT peripheral base pointer. + * @param pin PORT pin number. + * @param config PORT pin drive strength + * - #kPORT_LowDriveStrength = 0U - Low-drive strength is configured. + * - #kPORT_HighDriveStrength = 1U - High-drive strength is configured. + */ +static inline void PORT_SetPinDriveStrength(PORT_Type *base, uint32_t pin, uint8_t strength) +{ + base->PCR[pin] = (base->PCR[pin] & ~PORT_PCR_DSE_MASK) | PORT_PCR_DSE(strength); +} +#endif + +#if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) +/*! + * @brief Reads the whole port status flag. + * + * If a pin is configured to generate the DMA request, the corresponding flag + * is cleared automatically at the completion of the requested DMA transfer. + * Otherwise, the flag remains set until a logic one is written to that flag. + * If configured for a level sensitive interrupt that remains asserted, the flag + * is set again immediately. + * + * @param base PORT peripheral base pointer. + * @return Current port interrupt status flags, for example, 0x00010001 means the + * pin 0 and 16 have the interrupt. + */ +static inline uint32_t PORT_GetPinsInterruptFlags(PORT_Type *base) +{ + return base->ISFR; +} + +/*! + * @brief Clears the multiple pin interrupt status flag. + * + * @param base PORT peripheral base pointer. + * @param mask PORT pin number macro. + */ +static inline void PORT_ClearPinsInterruptFlags(PORT_Type *base, uint32_t mask) +{ + base->ISFR = mask; +} +#endif + +/*@}*/ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_PORT_H_ */ diff --git a/source/hic_hal/freescale/kl27z/fsl_rcm.c b/source/hic_hal/freescale/kl27z/fsl_rcm.c new file mode 100644 index 000000000..475f47938 --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_rcm.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_rcm.h" + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.rcm" +#endif + +/*! + * brief Configures the reset pin filter. + * + * This function sets the reset pin filter including the filter source, filter + * width, and so on. + * + * param base RCM peripheral base address. + * param config Pointer to the configuration structure. + */ +void RCM_ConfigureResetPinFilter(RCM_Type *base, const rcm_reset_pin_filter_config_t *config) +{ + assert(NULL != config); + +#if (defined(FSL_FEATURE_RCM_REG_WIDTH) && (FSL_FEATURE_RCM_REG_WIDTH == 32)) + uint32_t reg; + + reg = (((uint32_t)config->enableFilterInStop << RCM_RPC_RSTFLTSS_SHIFT) | (uint32_t)config->filterInRunWait); + if (config->filterInRunWait == kRCM_FilterBusClock) + { + reg |= ((uint32_t)config->busClockFilterCount << RCM_RPC_RSTFLTSEL_SHIFT); + } + base->RPC = reg; +#else + base->RPFC = (((uint8_t)config->enableFilterInStop << RCM_RPFC_RSTFLTSS_SHIFT) | (uint8_t)config->filterInRunWait); + if (config->filterInRunWait == kRCM_FilterBusClock) + { + base->RPFW = config->busClockFilterCount; + } +#endif /* FSL_FEATURE_RCM_REG_WIDTH */ +} + +#if (defined(FSL_FEATURE_RCM_HAS_BOOTROM) && FSL_FEATURE_RCM_HAS_BOOTROM) +/*! + * brief Forces the boot from ROM. + * + * This function forces booting from ROM during all subsequent system resets. + * + * param base RCM peripheral base address. + * param config Boot configuration. + */ +void RCM_SetForceBootRomSource(RCM_Type *base, rcm_boot_rom_config_t config) +{ + uint32_t reg; + + reg = base->FM; + reg &= ~RCM_FM_FORCEROM_MASK; + reg |= ((uint32_t)config << RCM_FM_FORCEROM_SHIFT); + base->FM = reg; +} +#endif /* #if FSL_FEATURE_RCM_HAS_BOOTROM */ diff --git a/source/hic_hal/freescale/kl27z/fsl_rcm.h b/source/hic_hal/freescale/kl27z/fsl_rcm.h new file mode 100644 index 000000000..28d6692c3 --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_rcm.h @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_RCM_H_ +#define _FSL_RCM_H_ + +#include "fsl_common.h" + +/*! @addtogroup rcm */ +/*! @{*/ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +/*! @brief RCM driver version 2.0.2. */ +#define FSL_RCM_DRIVER_VERSION (MAKE_VERSION(2, 0, 2)) +/*@}*/ + +/*! + * @brief System Reset Source Name definitions + */ +typedef enum _rcm_reset_source +{ +#if (defined(FSL_FEATURE_RCM_REG_WIDTH) && (FSL_FEATURE_RCM_REG_WIDTH == 32)) +/* RCM register bit width is 32. */ +#if (defined(FSL_FEATURE_RCM_HAS_WAKEUP) && FSL_FEATURE_RCM_HAS_WAKEUP) + kRCM_SourceWakeup = RCM_SRS_WAKEUP_MASK, /*!< Low-leakage wakeup reset */ +#endif + kRCM_SourceLvd = RCM_SRS_LVD_MASK, /*!< Low-voltage detect reset */ +#if (defined(FSL_FEATURE_RCM_HAS_LOC) && FSL_FEATURE_RCM_HAS_LOC) + kRCM_SourceLoc = RCM_SRS_LOC_MASK, /*!< Loss of clock reset */ +#endif /* FSL_FEATURE_RCM_HAS_LOC */ +#if (defined(FSL_FEATURE_RCM_HAS_LOL) && FSL_FEATURE_RCM_HAS_LOL) + kRCM_SourceLol = RCM_SRS_LOL_MASK, /*!< Loss of lock reset */ +#endif /* FSL_FEATURE_RCM_HAS_LOL */ + kRCM_SourceWdog = RCM_SRS_WDOG_MASK, /*!< Watchdog reset */ + kRCM_SourcePin = RCM_SRS_PIN_MASK, /*!< External pin reset */ + kRCM_SourcePor = RCM_SRS_POR_MASK, /*!< Power on reset */ +#if (defined(FSL_FEATURE_RCM_HAS_JTAG) && FSL_FEATURE_RCM_HAS_JTAG) + kRCM_SourceJtag = RCM_SRS_JTAG_MASK, /*!< JTAG generated reset */ +#endif /* FSL_FEATURE_RCM_HAS_JTAG */ + kRCM_SourceLockup = RCM_SRS_LOCKUP_MASK, /*!< Core lock up reset */ + kRCM_SourceSw = RCM_SRS_SW_MASK, /*!< Software reset */ +#if (defined(FSL_FEATURE_RCM_HAS_MDM_AP) && FSL_FEATURE_RCM_HAS_MDM_AP) + kRCM_SourceMdmap = RCM_SRS_MDM_AP_MASK, /*!< MDM-AP system reset */ +#endif /* FSL_FEATURE_RCM_HAS_MDM_AP */ +#if (defined(FSL_FEATURE_RCM_HAS_EZPORT) && FSL_FEATURE_RCM_HAS_EZPORT) + kRCM_SourceEzpt = RCM_SRS_EZPT_MASK, /*!< EzPort reset */ +#endif /* FSL_FEATURE_RCM_HAS_EZPORT */ + kRCM_SourceSackerr = RCM_SRS_SACKERR_MASK, /*!< Parameter could get all reset flags */ + +#else /* (FSL_FEATURE_RCM_REG_WIDTH == 32) */ +/* RCM register bit width is 8. */ +#if (defined(FSL_FEATURE_RCM_HAS_WAKEUP) && FSL_FEATURE_RCM_HAS_WAKEUP) + kRCM_SourceWakeup = RCM_SRS0_WAKEUP_MASK, /*!< Low-leakage wakeup reset */ +#endif + kRCM_SourceLvd = RCM_SRS0_LVD_MASK, /*!< Low-voltage detect reset */ +#if (defined(FSL_FEATURE_RCM_HAS_LOC) && FSL_FEATURE_RCM_HAS_LOC) + kRCM_SourceLoc = RCM_SRS0_LOC_MASK, /*!< Loss of clock reset */ +#endif /* FSL_FEATURE_RCM_HAS_LOC */ +#if (defined(FSL_FEATURE_RCM_HAS_LOL) && FSL_FEATURE_RCM_HAS_LOL) + kRCM_SourceLol = RCM_SRS0_LOL_MASK, /*!< Loss of lock reset */ +#endif /* FSL_FEATURE_RCM_HAS_LOL */ + kRCM_SourceWdog = RCM_SRS0_WDOG_MASK, /*!< Watchdog reset */ + kRCM_SourcePin = RCM_SRS0_PIN_MASK, /*!< External pin reset */ + kRCM_SourcePor = RCM_SRS0_POR_MASK, /*!< Power on reset */ +#if (defined(FSL_FEATURE_RCM_HAS_JTAG) && FSL_FEATURE_RCM_HAS_JTAG) + kRCM_SourceJtag = RCM_SRS1_JTAG_MASK << 8U, /*!< JTAG generated reset */ +#endif /* FSL_FEATURE_RCM_HAS_JTAG */ + kRCM_SourceLockup = RCM_SRS1_LOCKUP_MASK << 8U, /*!< Core lock up reset */ + kRCM_SourceSw = RCM_SRS1_SW_MASK << 8U, /*!< Software reset */ +#if (defined(FSL_FEATURE_RCM_HAS_MDM_AP) && FSL_FEATURE_RCM_HAS_MDM_AP) + kRCM_SourceMdmap = RCM_SRS1_MDM_AP_MASK << 8U, /*!< MDM-AP system reset */ +#endif /* FSL_FEATURE_RCM_HAS_MDM_AP */ +#if (defined(FSL_FEATURE_RCM_HAS_EZPORT) && FSL_FEATURE_RCM_HAS_EZPORT) + kRCM_SourceEzpt = RCM_SRS1_EZPT_MASK << 8U, /*!< EzPort reset */ +#endif /* FSL_FEATURE_RCM_HAS_EZPORT */ + kRCM_SourceSackerr = RCM_SRS1_SACKERR_MASK << 8U, /*!< Parameter could get all reset flags */ +#endif /* (FSL_FEATURE_RCM_REG_WIDTH == 32) */ + kRCM_SourceAll = (int)0xffffffffU, +} rcm_reset_source_t; + +/*! + * @brief Reset pin filter select in Run and Wait modes. + */ +typedef enum _rcm_run_wait_filter_mode +{ + kRCM_FilterDisable = 0U, /*!< All filtering disabled */ + kRCM_FilterBusClock = 1U, /*!< Bus clock filter enabled */ + kRCM_FilterLpoClock = 2U /*!< LPO clock filter enabled */ +} rcm_run_wait_filter_mode_t; + +#if (defined(FSL_FEATURE_RCM_HAS_BOOTROM) && FSL_FEATURE_RCM_HAS_BOOTROM) +/*! + * @brief Boot from ROM configuration. + */ +typedef enum _rcm_boot_rom_config +{ + kRCM_BootFlash = 0U, /*!< Boot from flash */ + kRCM_BootRomCfg0 = 1U, /*!< Boot from boot ROM due to BOOTCFG0 */ + kRCM_BootRomFopt = 2U, /*!< Boot from boot ROM due to FOPT[7] */ + kRCM_BootRomBoth = 3U /*!< Boot from boot ROM due to both BOOTCFG0 and FOPT[7] */ +} rcm_boot_rom_config_t; +#endif /* FSL_FEATURE_RCM_HAS_BOOTROM */ + +#if (defined(FSL_FEATURE_RCM_HAS_SRIE) && FSL_FEATURE_RCM_HAS_SRIE) +/*! + * @brief Maximum delay time from interrupt asserts to system reset. + */ +typedef enum _rcm_reset_delay +{ + kRCM_ResetDelay8Lpo = 0U, /*!< Delay 8 LPO cycles. */ + kRCM_ResetDelay32Lpo = 1U, /*!< Delay 32 LPO cycles. */ + kRCM_ResetDelay128Lpo = 2U, /*!< Delay 128 LPO cycles. */ + kRCM_ResetDelay512Lpo = 3U /*!< Delay 512 LPO cycles. */ +} rcm_reset_delay_t; + +/*! + * @brief System reset interrupt enable bit definitions. + */ +typedef enum _rcm_interrupt_enable +{ + kRCM_IntNone = 0U, /*!< No interrupt enabled. */ + kRCM_IntLossOfClk = RCM_SRIE_LOC_MASK, /*!< Loss of clock interrupt. */ + kRCM_IntLossOfLock = RCM_SRIE_LOL_MASK, /*!< Loss of lock interrupt. */ + kRCM_IntWatchDog = RCM_SRIE_WDOG_MASK, /*!< Watch dog interrupt. */ + kRCM_IntExternalPin = RCM_SRIE_PIN_MASK, /*!< External pin interrupt. */ + kRCM_IntGlobal = RCM_SRIE_GIE_MASK, /*!< Global interrupts. */ + kRCM_IntCoreLockup = RCM_SRIE_LOCKUP_MASK, /*!< Core lock up interrupt */ + kRCM_IntSoftware = RCM_SRIE_SW_MASK, /*!< software interrupt */ + kRCM_IntStopModeAckErr = RCM_SRIE_SACKERR_MASK, /*!< Stop mode ACK error interrupt. */ +#if (defined(FSL_FEATURE_RCM_HAS_CORE1) && FSL_FEATURE_RCM_HAS_CORE1) + kRCM_IntCore1 = RCM_SRIE_CORE1_MASK, /*!< Core 1 interrupt. */ +#endif + kRCM_IntAll = RCM_SRIE_LOC_MASK /*!< Enable all interrupts. */ + | RCM_SRIE_LOL_MASK | RCM_SRIE_WDOG_MASK | RCM_SRIE_PIN_MASK | RCM_SRIE_GIE_MASK | + RCM_SRIE_LOCKUP_MASK | RCM_SRIE_SW_MASK | RCM_SRIE_SACKERR_MASK +#if (defined(FSL_FEATURE_RCM_HAS_CORE1) && FSL_FEATURE_RCM_HAS_CORE1) + | RCM_SRIE_CORE1_MASK +#endif +} rcm_interrupt_enable_t; +#endif /* FSL_FEATURE_RCM_HAS_SRIE */ + +#if (defined(FSL_FEATURE_RCM_HAS_VERID) && FSL_FEATURE_RCM_HAS_VERID) +/*! + * @brief IP version ID definition. + */ +typedef struct _rcm_version_id +{ + uint16_t feature; /*!< Feature Specification Number. */ + uint8_t minor; /*!< Minor version number. */ + uint8_t major; /*!< Major version number. */ +} rcm_version_id_t; +#endif + +/*! + * @brief Reset pin filter configuration. + */ +typedef struct _rcm_reset_pin_filter_config +{ + bool enableFilterInStop; /*!< Reset pin filter select in stop mode. */ + rcm_run_wait_filter_mode_t filterInRunWait; /*!< Reset pin filter in run/wait mode. */ + uint8_t busClockFilterCount; /*!< Reset pin bus clock filter width. */ +} rcm_reset_pin_filter_config_t; + +/******************************************************************************* + * API + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! @name Reset Control Module APIs*/ +/*@{*/ + +#if (defined(FSL_FEATURE_RCM_HAS_VERID) && FSL_FEATURE_RCM_HAS_VERID) +/*! + * @brief Gets the RCM version ID. + * + * This function gets the RCM version ID including the major version number, + * the minor version number, and the feature specification number. + * + * @param base RCM peripheral base address. + * @param versionId Pointer to the version ID structure. + */ +static inline void RCM_GetVersionId(RCM_Type *base, rcm_version_id_t *versionId) +{ + *((uint32_t *)versionId) = base->VERID; +} +#endif + +#if (defined(FSL_FEATURE_RCM_HAS_PARAM) && FSL_FEATURE_RCM_HAS_PARAM) +/*! + * @brief Gets the reset source implemented status. + * + * This function gets the RCM parameter that indicates whether the corresponding reset source is implemented. + * Use source masks defined in the rcm_reset_source_t to get the desired source status. + * + * This is an example. + * @code + * uint32_t status; + * + * To test whether the MCU is reset using Watchdog. + * status = RCM_GetResetSourceImplementedStatus(RCM) & (kRCM_SourceWdog | kRCM_SourcePin); + * @endcode + * + * @param base RCM peripheral base address. + * @return All reset source implemented status bit map. + */ +static inline uint32_t RCM_GetResetSourceImplementedStatus(RCM_Type *base) +{ + return base->PARAM; +} +#endif /* FSL_FEATURE_RCM_HAS_PARAM */ + +/*! + * @brief Gets the reset source status which caused a previous reset. + * + * This function gets the current reset source status. Use source masks + * defined in the rcm_reset_source_t to get the desired source status. + * + * This is an example. + * @code + * uint32_t resetStatus; + * + * To get all reset source statuses. + * resetStatus = RCM_GetPreviousResetSources(RCM) & kRCM_SourceAll; + * + * To test whether the MCU is reset using Watchdog. + * resetStatus = RCM_GetPreviousResetSources(RCM) & kRCM_SourceWdog; + * + * To test multiple reset sources. + * resetStatus = RCM_GetPreviousResetSources(RCM) & (kRCM_SourceWdog | kRCM_SourcePin); + * @endcode + * + * @param base RCM peripheral base address. + * @return All reset source status bit map. + */ +static inline uint32_t RCM_GetPreviousResetSources(RCM_Type *base) +{ +#if (defined(FSL_FEATURE_RCM_REG_WIDTH) && (FSL_FEATURE_RCM_REG_WIDTH == 32)) + return base->SRS; +#else + uint8_t tmpSrs0 = base->SRS0; + uint8_t tmpSrs1 = base->SRS1; + return (uint32_t)((uint32_t)tmpSrs0 | ((uint32_t)tmpSrs1 << 8U)); +#endif /* (FSL_FEATURE_RCM_REG_WIDTH == 32) */ +} + +#if (defined(FSL_FEATURE_RCM_HAS_SSRS) && FSL_FEATURE_RCM_HAS_SSRS) +/*! + * @brief Gets the sticky reset source status. + * + * This function gets the current reset source status that has not been cleared + * by software for a specific source. + * + * This is an example. + * @code + * uint32_t resetStatus; + * + * To get all reset source statuses. + * resetStatus = RCM_GetStickyResetSources(RCM) & kRCM_SourceAll; + * + * To test whether the MCU is reset using Watchdog. + * resetStatus = RCM_GetStickyResetSources(RCM) & kRCM_SourceWdog; + * + * To test multiple reset sources. + * resetStatus = RCM_GetStickyResetSources(RCM) & (kRCM_SourceWdog | kRCM_SourcePin); + * @endcode + * + * @param base RCM peripheral base address. + * @return All reset source status bit map. + */ +static inline uint32_t RCM_GetStickyResetSources(RCM_Type *base) +{ +#if (defined(FSL_FEATURE_RCM_REG_WIDTH) && (FSL_FEATURE_RCM_REG_WIDTH == 32)) + return base->SSRS; +#else + return (base->SSRS0 | ((uint32_t)base->SSRS1 << 8U)); +#endif /* (FSL_FEATURE_RCM_REG_WIDTH == 32) */ +} + +/*! + * @brief Clears the sticky reset source status. + * + * This function clears the sticky system reset flags indicated by source masks. + * + * This is an example. + * @code + * Clears multiple reset sources. + * RCM_ClearStickyResetSources(kRCM_SourceWdog | kRCM_SourcePin); + * @endcode + * + * @param base RCM peripheral base address. + * @param sourceMasks reset source status bit map + */ +static inline void RCM_ClearStickyResetSources(RCM_Type *base, uint32_t sourceMasks) +{ +#if (defined(FSL_FEATURE_RCM_REG_WIDTH) && (FSL_FEATURE_RCM_REG_WIDTH == 32)) + base->SSRS = sourceMasks; +#else + base->SSRS0 = (sourceMasks & 0xffU); + base->SSRS1 = ((sourceMasks >> 8U) & 0xffU); +#endif /* (FSL_FEATURE_RCM_REG_WIDTH == 32) */ +} +#endif /* FSL_FEATURE_RCM_HAS_SSRS */ + +/*! + * @brief Configures the reset pin filter. + * + * This function sets the reset pin filter including the filter source, filter + * width, and so on. + * + * @param base RCM peripheral base address. + * @param config Pointer to the configuration structure. + */ +void RCM_ConfigureResetPinFilter(RCM_Type *base, const rcm_reset_pin_filter_config_t *config); + +#if (defined(FSL_FEATURE_RCM_HAS_EZPMS) && FSL_FEATURE_RCM_HAS_EZPMS) +/*! + * @brief Gets the EZP_MS_B pin assert status. + * + * This function gets the easy port mode status (EZP_MS_B) pin assert status. + * + * @param base RCM peripheral base address. + * @return status true - asserted, false - reasserted + */ +static inline bool RCM_GetEasyPortModePinStatus(RCM_Type *base) +{ + return (bool)(base->MR & RCM_MR_EZP_MS_MASK); +} +#endif /* FSL_FEATURE_RCM_HAS_EZPMS */ + +#if (defined(FSL_FEATURE_RCM_HAS_BOOTROM) && FSL_FEATURE_RCM_HAS_BOOTROM) +/*! + * @brief Gets the ROM boot source. + * + * This function gets the ROM boot source during the last chip reset. + * + * @param base RCM peripheral base address. + * @return The ROM boot source. + */ +static inline rcm_boot_rom_config_t RCM_GetBootRomSource(RCM_Type *base) +{ + return (rcm_boot_rom_config_t)((base->MR & RCM_MR_BOOTROM_MASK) >> RCM_MR_BOOTROM_SHIFT); +} + +/*! + * @brief Clears the ROM boot source flag. + * + * This function clears the ROM boot source flag. + * + * @param base Register base address of RCM + */ +static inline void RCM_ClearBootRomSource(RCM_Type *base) +{ + base->MR |= RCM_MR_BOOTROM_MASK; +} + +/*! + * @brief Forces the boot from ROM. + * + * This function forces booting from ROM during all subsequent system resets. + * + * @param base RCM peripheral base address. + * @param config Boot configuration. + */ +void RCM_SetForceBootRomSource(RCM_Type *base, rcm_boot_rom_config_t config); +#endif /* FSL_FEATURE_RCM_HAS_BOOTROM */ + +#if (defined(FSL_FEATURE_RCM_HAS_SRIE) && FSL_FEATURE_RCM_HAS_SRIE) +/*! + * @brief Sets the system reset interrupt configuration. + * + * For a graceful shut down, the RCM supports delaying the assertion of the system + * reset for a period of time when the reset interrupt is generated. This function + * can be used to enable the interrupt and the delay period. The interrupts + * are passed in as bit mask. See rcm_int_t for details. For example, to + * delay a reset for 512 LPO cycles after the WDOG timeout or loss-of-clock occurs, + * configure as follows: + * RCM_SetSystemResetInterruptConfig(kRCM_IntWatchDog | kRCM_IntLossOfClk, kRCM_ResetDelay512Lpo); + * + * @param base RCM peripheral base address. + * @param intMask Bit mask of the system reset interrupts to enable. See + * rcm_interrupt_enable_t for details. + * @param Delay Bit mask of the system reset interrupts to enable. + */ +static inline void RCM_SetSystemResetInterruptConfig(RCM_Type *base, uint32_t intMask, rcm_reset_delay_t delay) +{ + base->SRIE = (intMask | delay); +} +#endif /* FSL_FEATURE_RCM_HAS_SRIE */ +/*@}*/ + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/*! @}*/ + +#endif /* _FSL_RCM_H_ */ diff --git a/source/hic_hal/freescale/kl27z/fsl_smc.c b/source/hic_hal/freescale/kl27z/fsl_smc.c new file mode 100644 index 000000000..b3998d037 --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_smc.c @@ -0,0 +1,511 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_smc.h" +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.smc" +#endif + +typedef void (*smc_stop_ram_func_t)(void); + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +static void SMC_EnterStopRamFunc(void); + +/******************************************************************************* + * Variables + ******************************************************************************/ +static uint32_t g_savedPrimask; + +/* + * The ram function code is: + * + * uint32_t i; + * for (i=0; i<0x8; i++) + * { + * __NOP(); + * } + * __DSB(); + * __WFI(); + * __ISB(); + * + * When entring the stop modes, the flash prefetch might be interrupted, thus + * the prefetched code or data might be broken. To make sure the flash is idle + * when entring the stop modes, the code is moved to ram. And delay for a while + * before WFI to make sure previous flash prefetch is finished. + * + * Only need to do like this when code is in flash, if code is in rom or ram, + * this is not necessary. + */ +static uint16_t s_stopRamFuncArray[] = { + 0x2000, /* MOVS R0, #0 */ + 0x2808, /* CMP R0, #8 */ + 0xD202, /* BCS.N */ + 0xBF00, /* NOP */ + 0x1C40, /* ADDS R0, R0, #1 */ + 0xE7FA, /* B.N */ + 0xF3BF, 0x8F4F, /* DSB */ + 0xBF30, /* WFI */ + 0xF3BF, 0x8F6F, /* ISB */ + 0x4770, /* BX LR */ +}; + +/******************************************************************************* + * Code + ******************************************************************************/ +static void SMC_EnterStopRamFunc(void) +{ + uint32_t ramFuncEntry = ((uint32_t)(s_stopRamFuncArray)) + 1U; + smc_stop_ram_func_t stopRamFunc = (smc_stop_ram_func_t)ramFuncEntry; + stopRamFunc(); +} + +#if (defined(FSL_FEATURE_SMC_HAS_PARAM) && FSL_FEATURE_SMC_HAS_PARAM) +/*! + * brief Gets the SMC parameter. + * + * This function gets the SMC parameter including the enabled power mdoes. + * + * param base SMC peripheral base address. + * param param Pointer to the SMC param structure. + */ +void SMC_GetParam(SMC_Type *base, smc_param_t *param) +{ + uint32_t reg = base->PARAM; + param->hsrunEnable = (bool)(reg & SMC_PARAM_EHSRUN_MASK); + param->llsEnable = (bool)(reg & SMC_PARAM_ELLS_MASK); + param->lls2Enable = (bool)(reg & SMC_PARAM_ELLS2_MASK); + param->vlls0Enable = (bool)(reg & SMC_PARAM_EVLLS0_MASK); +} +#endif /* FSL_FEATURE_SMC_HAS_PARAM */ + +/*! + * brief Prepares to enter stop modes. + * + * This function should be called before entering STOP/VLPS/LLS/VLLS modes. + */ +void SMC_PreEnterStopModes(void) +{ + g_savedPrimask = DisableGlobalIRQ(); + __ISB(); +} + +/*! + * brief Recovers after wake up from stop modes. + * + * This function should be called after wake up from STOP/VLPS/LLS/VLLS modes. + * It is used with ref SMC_PreEnterStopModes. + */ +void SMC_PostExitStopModes(void) +{ + EnableGlobalIRQ(g_savedPrimask); + __ISB(); +} + +/*! + * brief Prepares to enter wait modes. + * + * This function should be called before entering WAIT/VLPW modes. + */ +void SMC_PreEnterWaitModes(void) +{ + g_savedPrimask = DisableGlobalIRQ(); + __ISB(); +} + +/*! + * brief Recovers after wake up from stop modes. + * + * This function should be called after wake up from WAIT/VLPW modes. + * It is used with ref SMC_PreEnterWaitModes. + */ +void SMC_PostExitWaitModes(void) +{ + EnableGlobalIRQ(g_savedPrimask); + __ISB(); +} + +/*! + * brief Configures the system to RUN power mode. + * + * param base SMC peripheral base address. + * return SMC configuration error code. + */ +status_t SMC_SetPowerModeRun(SMC_Type *base) +{ + uint8_t reg; + + reg = base->PMCTRL; + /* configure Normal RUN mode */ + reg &= ~(uint8_t)SMC_PMCTRL_RUNM_MASK; + reg |= ((uint8_t)kSMC_RunNormal << SMC_PMCTRL_RUNM_SHIFT); + base->PMCTRL = reg; + + return kStatus_Success; +} + +#if (defined(FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE) && FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE) +/*! + * brief Configures the system to HSRUN power mode. + * + * param base SMC peripheral base address. + * return SMC configuration error code. + */ +status_t SMC_SetPowerModeHsrun(SMC_Type *base) +{ + uint8_t reg; + + reg = base->PMCTRL; + /* configure High Speed RUN mode */ + reg &= ~SMC_PMCTRL_RUNM_MASK; + reg |= ((uint8_t)kSMC_Hsrun << SMC_PMCTRL_RUNM_SHIFT); + base->PMCTRL = reg; + + return kStatus_Success; +} +#endif /* FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE */ + +/*! + * brief Configures the system to WAIT power mode. + * + * param base SMC peripheral base address. + * return SMC configuration error code. + */ +status_t SMC_SetPowerModeWait(SMC_Type *base) +{ + /* configure Normal Wait mode */ + SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; + __DSB(); + __WFI(); + __ISB(); + + return kStatus_Success; +} + +/*! + * brief Configures the system to Stop power mode. + * + * param base SMC peripheral base address. + * param option Partial Stop mode option. + * return SMC configuration error code. + */ +status_t SMC_SetPowerModeStop(SMC_Type *base, smc_partial_stop_option_t option) +{ + uint8_t reg; + +#if (defined(FSL_FEATURE_SMC_HAS_PSTOPO) && FSL_FEATURE_SMC_HAS_PSTOPO) + /* configure the Partial Stop mode in Normal Stop mode */ + reg = base->STOPCTRL; + reg &= ~(uint8_t)SMC_STOPCTRL_PSTOPO_MASK; + reg |= ((uint8_t)option << SMC_STOPCTRL_PSTOPO_SHIFT); + base->STOPCTRL = reg; +#endif + + /* configure Normal Stop mode */ + reg = base->PMCTRL; + reg &= ~(uint8_t)SMC_PMCTRL_STOPM_MASK; + reg |= ((uint8_t)kSMC_StopNormal << SMC_PMCTRL_STOPM_SHIFT); + base->PMCTRL = reg; + + /* Set the SLEEPDEEP bit to enable deep sleep mode (stop mode) */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + + /* read back to make sure the configuration valid before enter stop mode */ + (void)base->PMCTRL; + SMC_EnterStopRamFunc(); + + /* check whether the power mode enter Stop mode succeed */ + if (0U != (base->PMCTRL & SMC_PMCTRL_STOPA_MASK)) + { + return kStatus_SMC_StopAbort; + } + else + { + return kStatus_Success; + } +} + +/*! + * brief Configures the system to VLPR power mode. + * + * param base SMC peripheral base address. + * return SMC configuration error code. + */ +status_t SMC_SetPowerModeVlpr(SMC_Type *base +#if (defined(FSL_FEATURE_SMC_HAS_LPWUI) && FSL_FEATURE_SMC_HAS_LPWUI) + , + bool wakeupMode +#endif +) +{ + uint8_t reg; + + reg = base->PMCTRL; +#if (defined(FSL_FEATURE_SMC_HAS_LPWUI) && FSL_FEATURE_SMC_HAS_LPWUI) + /* configure whether the system remains in VLP mode on an interrupt */ + if (wakeupMode) + { + /* exits to RUN mode on an interrupt */ + reg |= SMC_PMCTRL_LPWUI_MASK; + } + else + { + /* remains in VLP mode on an interrupt */ + reg &= ~(uint8_t)SMC_PMCTRL_LPWUI_MASK; + } +#endif /* FSL_FEATURE_SMC_HAS_LPWUI */ + + /* configure VLPR mode */ + reg &= ~(uint8_t)SMC_PMCTRL_RUNM_MASK; + reg |= ((uint8_t)kSMC_RunVlpr << SMC_PMCTRL_RUNM_SHIFT); + base->PMCTRL = reg; + + return kStatus_Success; +} + +/*! + * brief Configures the system to VLPW power mode. + * + * param base SMC peripheral base address. + * return SMC configuration error code. + */ +status_t SMC_SetPowerModeVlpw(SMC_Type *base) +{ + /* configure VLPW mode */ + /* Set the SLEEPDEEP bit to enable deep sleep mode */ + SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; + __DSB(); + __WFI(); + __ISB(); + + return kStatus_Success; +} + +/*! + * brief Configures the system to VLPS power mode. + * + * param base SMC peripheral base address. + * return SMC configuration error code. + */ +status_t SMC_SetPowerModeVlps(SMC_Type *base) +{ + uint8_t reg; + + /* configure VLPS mode */ + reg = base->PMCTRL; + reg &= ~(uint8_t)SMC_PMCTRL_STOPM_MASK; + reg |= ((uint8_t)kSMC_StopVlps << SMC_PMCTRL_STOPM_SHIFT); + base->PMCTRL = reg; + + /* Set the SLEEPDEEP bit to enable deep sleep mode */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + + /* read back to make sure the configuration valid before enter stop mode */ + (void)base->PMCTRL; + SMC_EnterStopRamFunc(); + + /* check whether the power mode enter VLPS mode succeed */ + if (0U != (base->PMCTRL & SMC_PMCTRL_STOPA_MASK)) + { + return kStatus_SMC_StopAbort; + } + else + { + return kStatus_Success; + } +} + +#if (defined(FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE) +/*! + * brief Configures the system to LLS power mode. + * + * param base SMC peripheral base address. + * return SMC configuration error code. + */ +status_t SMC_SetPowerModeLls(SMC_Type *base +#if ((defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE) || \ + (defined(FSL_FEATURE_SMC_HAS_LPOPO) && FSL_FEATURE_SMC_HAS_LPOPO)) + , + const smc_power_mode_lls_config_t *config +#endif +) +{ + uint8_t reg; + + /* configure to LLS mode */ + reg = base->PMCTRL; + reg &= ~(uint8_t)SMC_PMCTRL_STOPM_MASK; + reg |= ((uint8_t)kSMC_StopLls << SMC_PMCTRL_STOPM_SHIFT); + base->PMCTRL = reg; + +/* configure LLS sub-mode*/ +#if (defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE) + reg = base->STOPCTRL; + reg &= ~(uint8_t)SMC_STOPCTRL_LLSM_MASK; + reg |= ((uint8_t)config->subMode << SMC_STOPCTRL_LLSM_SHIFT); + base->STOPCTRL = reg; +#endif /* FSL_FEATURE_SMC_HAS_LLS_SUBMODE */ + +#if (defined(FSL_FEATURE_SMC_HAS_LPOPO) && FSL_FEATURE_SMC_HAS_LPOPO) + if (config->enableLpoClock) + { + base->STOPCTRL &= ~SMC_STOPCTRL_LPOPO_MASK; + } + else + { + base->STOPCTRL |= SMC_STOPCTRL_LPOPO_MASK; + } +#endif /* FSL_FEATURE_SMC_HAS_LPOPO */ + + /* Set the SLEEPDEEP bit to enable deep sleep mode */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + + /* read back to make sure the configuration valid before enter stop mode */ + (void)base->PMCTRL; + SMC_EnterStopRamFunc(); + + /* check whether the power mode enter LLS mode succeed */ + if (0U != (base->PMCTRL & SMC_PMCTRL_STOPA_MASK)) + { + return kStatus_SMC_StopAbort; + } + else + { + return kStatus_Success; + } +} +#endif /* FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE */ + +#if (defined(FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE) +/*! + * brief Configures the system to VLLS power mode. + * + * param base SMC peripheral base address. + * param config The VLLS power mode configuration structure. + * return SMC configuration error code. + */ +status_t SMC_SetPowerModeVlls(SMC_Type *base, const smc_power_mode_vlls_config_t *config) +{ + uint8_t reg; + +#if (defined(FSL_FEATURE_SMC_HAS_PORPO) && FSL_FEATURE_SMC_HAS_PORPO) +#if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG) || \ + (defined(FSL_FEATURE_SMC_USE_STOPCTRL_VLLSM) && FSL_FEATURE_SMC_USE_STOPCTRL_VLLSM) || \ + (defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE) + if (config->subMode == kSMC_StopSub0) +#endif + { + /* configure whether the Por Detect work in Vlls0 mode */ + if (true == config->enablePorDetectInVlls0) + { +#if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG) + base->VLLSCTRL &= ~SMC_VLLSCTRL_PORPO_MASK; +#else + base->STOPCTRL &= ~(uint8_t)SMC_STOPCTRL_PORPO_MASK; +#endif + } + else + { +#if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG) + base->VLLSCTRL |= SMC_VLLSCTRL_PORPO_MASK; +#else + base->STOPCTRL |= SMC_STOPCTRL_PORPO_MASK; +#endif + } + } +#endif /* FSL_FEATURE_SMC_HAS_PORPO */ + +#if (defined(FSL_FEATURE_SMC_HAS_RAM2_POWER_OPTION) && FSL_FEATURE_SMC_HAS_RAM2_POWER_OPTION) + else if (config->subMode == kSMC_StopSub2) + { + /* configure whether the Por Detect work in Vlls0 mode */ + if (true == config->enableRam2InVlls2) + { +#if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG) + base->VLLSCTRL |= SMC_VLLSCTRL_RAM2PO_MASK; +#else + base->STOPCTRL |= SMC_STOPCTRL_RAM2PO_MASK; +#endif + } + else + { +#if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG) + base->VLLSCTRL &= ~SMC_VLLSCTRL_RAM2PO_MASK; +#else + base->STOPCTRL &= ~(uint8_t)SMC_STOPCTRL_RAM2PO_MASK; +#endif + } + } + else + { + /* Add this to fix MISRA C2012 rule15.7 issue: Empty else without comment. */ + } +#endif /* FSL_FEATURE_SMC_HAS_RAM2_POWER_OPTION */ + + /* configure to VLLS mode */ + reg = base->PMCTRL; + reg &= ~(uint8_t)SMC_PMCTRL_STOPM_MASK; + reg |= ((uint8_t)kSMC_StopVlls << SMC_PMCTRL_STOPM_SHIFT); + base->PMCTRL = reg; + +/* configure the VLLS sub-mode */ +#if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG) + reg = base->VLLSCTRL; + reg &= ~SMC_VLLSCTRL_VLLSM_MASK; + reg |= ((uint8_t)config->subMode << SMC_VLLSCTRL_VLLSM_SHIFT); + base->VLLSCTRL = reg; +#else +#if (defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE) + reg = base->STOPCTRL; + reg &= ~(uint8_t)SMC_STOPCTRL_LLSM_MASK; + reg |= ((uint8_t)config->subMode << SMC_STOPCTRL_LLSM_SHIFT); + base->STOPCTRL = reg; +#else + reg = base->STOPCTRL; + reg &= ~SMC_STOPCTRL_VLLSM_MASK; + reg |= ((uint8_t)config->subMode << SMC_STOPCTRL_VLLSM_SHIFT); + base->STOPCTRL = reg; +#endif /* FSL_FEATURE_SMC_HAS_LLS_SUBMODE */ +#endif + +#if (defined(FSL_FEATURE_SMC_HAS_LPOPO) && FSL_FEATURE_SMC_HAS_LPOPO) + if (config->enableLpoClock) + { + base->STOPCTRL &= ~SMC_STOPCTRL_LPOPO_MASK; + } + else + { + base->STOPCTRL |= SMC_STOPCTRL_LPOPO_MASK; + } +#endif /* FSL_FEATURE_SMC_HAS_LPOPO */ + + /* Set the SLEEPDEEP bit to enable deep sleep mode */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + + /* read back to make sure the configuration valid before enter stop mode */ + (void)base->PMCTRL; + SMC_EnterStopRamFunc(); + + /* check whether the power mode enter LLS mode succeed */ + if (0U != (base->PMCTRL & SMC_PMCTRL_STOPA_MASK)) + { + return kStatus_SMC_StopAbort; + } + else + { + return kStatus_Success; + } +} +#endif /* FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE */ diff --git a/source/hic_hal/freescale/kl27z/fsl_smc.h b/source/hic_hal/freescale/kl27z/fsl_smc.h new file mode 100644 index 000000000..e5c318e1a --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_smc.h @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_SMC_H_ +#define _FSL_SMC_H_ + +#include "fsl_common.h" + +/*! @addtogroup smc */ +/*! @{ */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +/*! @brief SMC driver version 2.0.5. */ +#define FSL_SMC_DRIVER_VERSION (MAKE_VERSION(2, 0, 5)) +/*@}*/ + +/*! + * @brief Power Modes Protection + */ +typedef enum _smc_power_mode_protection +{ +#if (defined(FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE) + kSMC_AllowPowerModeVlls = SMC_PMPROT_AVLLS_MASK, /*!< Allow Very-low-leakage Stop Mode. */ +#endif +#if (defined(FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE) + kSMC_AllowPowerModeLls = SMC_PMPROT_ALLS_MASK, /*!< Allow Low-leakage Stop Mode. */ +#endif /* FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE */ + kSMC_AllowPowerModeVlp = SMC_PMPROT_AVLP_MASK, /*!< Allow Very-Low-power Mode. */ +#if (defined(FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE) && FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE) + kSMC_AllowPowerModeHsrun = SMC_PMPROT_AHSRUN_MASK, /*!< Allow High-speed Run mode. */ +#endif /* FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE */ + kSMC_AllowPowerModeAll = (0U +#if (defined(FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE) + | SMC_PMPROT_AVLLS_MASK +#endif +#if (defined(FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE) + | SMC_PMPROT_ALLS_MASK +#endif /* FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE */ + | SMC_PMPROT_AVLP_MASK +#if (defined(FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE) && FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE) + | kSMC_AllowPowerModeHsrun +#endif /* FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE */ + ) /*!< Allow all power mode. */ +} smc_power_mode_protection_t; + +/*! + * @brief Power Modes in PMSTAT + */ +typedef enum _smc_power_state +{ + kSMC_PowerStateRun = 0x01U << 0U, /*!< 0000_0001 - Current power mode is RUN */ + kSMC_PowerStateStop = 0x01U << 1U, /*!< 0000_0010 - Current power mode is STOP */ + kSMC_PowerStateVlpr = 0x01U << 2U, /*!< 0000_0100 - Current power mode is VLPR */ + kSMC_PowerStateVlpw = 0x01U << 3U, /*!< 0000_1000 - Current power mode is VLPW */ + kSMC_PowerStateVlps = 0x01U << 4U, /*!< 0001_0000 - Current power mode is VLPS */ +#if (defined(FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE) + kSMC_PowerStateLls = 0x01U << 5U, /*!< 0010_0000 - Current power mode is LLS */ +#endif /* FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE */ +#if (defined(FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE) + kSMC_PowerStateVlls = 0x01U << 6U, /*!< 0100_0000 - Current power mode is VLLS */ +#endif +#if (defined(FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE) && FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE) + kSMC_PowerStateHsrun = 0x01U << 7U /*!< 1000_0000 - Current power mode is HSRUN */ +#endif /* FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE */ +} smc_power_state_t; + +/*! + * @brief Run mode definition + */ +typedef enum _smc_run_mode +{ + kSMC_RunNormal = 0U, /*!< Normal RUN mode. */ + kSMC_RunVlpr = 2U, /*!< Very-low-power RUN mode. */ +#if (defined(FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE) && FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE) + kSMC_Hsrun = 3U /*!< High-speed Run mode (HSRUN). */ +#endif /* FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE */ +} smc_run_mode_t; + +/*! + * @brief Stop mode definition + */ +typedef enum _smc_stop_mode +{ + kSMC_StopNormal = 0U, /*!< Normal STOP mode. */ + kSMC_StopVlps = 2U, /*!< Very-low-power STOP mode. */ +#if (defined(FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE) + kSMC_StopLls = 3U, /*!< Low-leakage Stop mode. */ +#endif /* FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE */ +#if (defined(FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE) + kSMC_StopVlls = 4U /*!< Very-low-leakage Stop mode. */ +#endif +} smc_stop_mode_t; + +#if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG) || \ + (defined(FSL_FEATURE_SMC_USE_STOPCTRL_VLLSM) && FSL_FEATURE_SMC_USE_STOPCTRL_VLLSM) || \ + (defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE) +/*! + * @brief VLLS/LLS stop sub mode definition + */ +typedef enum _smc_stop_submode +{ + kSMC_StopSub0 = 0U, /*!< Stop submode 0, for VLLS0/LLS0. */ + kSMC_StopSub1 = 1U, /*!< Stop submode 1, for VLLS1/LLS1. */ + kSMC_StopSub2 = 2U, /*!< Stop submode 2, for VLLS2/LLS2. */ + kSMC_StopSub3 = 3U /*!< Stop submode 3, for VLLS3/LLS3. */ +} smc_stop_submode_t; +#endif + +/*! + * @brief Partial STOP option + */ +typedef enum _smc_partial_stop_mode +{ + kSMC_PartialStop = 0U, /*!< STOP - Normal Stop mode*/ + kSMC_PartialStop1 = 1U, /*!< Partial Stop with both system and bus clocks disabled*/ + kSMC_PartialStop2 = 2U, /*!< Partial Stop with system clock disabled and bus clock enabled*/ +} smc_partial_stop_option_t; + +/*! + * @brief SMC configuration status. + */ +enum _smc_status +{ + kStatus_SMC_StopAbort = MAKE_STATUS(kStatusGroup_POWER, 0) /*!< Entering Stop mode is abort*/ +}; + +#if (defined(FSL_FEATURE_SMC_HAS_VERID) && FSL_FEATURE_SMC_HAS_VERID) +/*! + * @brief IP version ID definition. + */ +typedef struct _smc_version_id +{ + uint16_t feature; /*!< Feature Specification Number. */ + uint8_t minor; /*!< Minor version number. */ + uint8_t major; /*!< Major version number. */ +} smc_version_id_t; +#endif /* FSL_FEATURE_SMC_HAS_VERID */ + +#if (defined(FSL_FEATURE_SMC_HAS_PARAM) && FSL_FEATURE_SMC_HAS_PARAM) +/*! + * @brief IP parameter definition. + */ +typedef struct _smc_param +{ + bool hsrunEnable; /*!< HSRUN mode enable. */ + bool llsEnable; /*!< LLS mode enable. */ + bool lls2Enable; /*!< LLS2 mode enable. */ + bool vlls0Enable; /*!< VLLS0 mode enable. */ +} smc_param_t; +#endif /* FSL_FEATURE_SMC_HAS_PARAM */ + +#if (defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE) || \ + (defined(FSL_FEATURE_SMC_HAS_LPOPO) && FSL_FEATURE_SMC_HAS_LPOPO) +/*! + * @brief SMC Low-Leakage Stop power mode configuration. + */ +typedef struct _smc_power_mode_lls_config +{ +#if (defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE) + smc_stop_submode_t subMode; /*!< Low-leakage Stop sub-mode */ +#endif +#if (defined(FSL_FEATURE_SMC_HAS_LPOPO) && FSL_FEATURE_SMC_HAS_LPOPO) + bool enableLpoClock; /*!< Enable LPO clock in LLS mode */ +#endif +} smc_power_mode_lls_config_t; +#endif /* (FSL_FEATURE_SMC_HAS_LLS_SUBMODE || FSL_FEATURE_SMC_HAS_LPOPO) */ + +#if (defined(FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE) +/*! + * @brief SMC Very Low-Leakage Stop power mode configuration. + */ +typedef struct _smc_power_mode_vlls_config +{ +#if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG) || \ + (defined(FSL_FEATURE_SMC_USE_STOPCTRL_VLLSM) && FSL_FEATURE_SMC_USE_STOPCTRL_VLLSM) || \ + (defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE) + smc_stop_submode_t subMode; /*!< Very Low-leakage Stop sub-mode */ +#endif +#if (defined(FSL_FEATURE_SMC_HAS_PORPO) && FSL_FEATURE_SMC_HAS_PORPO) + bool enablePorDetectInVlls0; /*!< Enable Power on reset detect in VLLS mode */ +#endif +#if (defined(FSL_FEATURE_SMC_HAS_RAM2_POWER_OPTION) && FSL_FEATURE_SMC_HAS_RAM2_POWER_OPTION) + bool enableRam2InVlls2; /*!< Enable RAM2 power in VLLS2 */ +#endif +#if (defined(FSL_FEATURE_SMC_HAS_LPOPO) && FSL_FEATURE_SMC_HAS_LPOPO) + bool enableLpoClock; /*!< Enable LPO clock in VLLS mode */ +#endif +} smc_power_mode_vlls_config_t; +#endif + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +/*! @name System mode controller APIs*/ +/*@{*/ + +#if (defined(FSL_FEATURE_SMC_HAS_VERID) && FSL_FEATURE_SMC_HAS_VERID) +/*! + * @brief Gets the SMC version ID. + * + * This function gets the SMC version ID, including major version number, + * minor version number, and feature specification number. + * + * @param base SMC peripheral base address. + * @param versionId Pointer to the version ID structure. + */ +static inline void SMC_GetVersionId(SMC_Type *base, smc_version_id_t *versionId) +{ + *((uint32_t *)versionId) = base->VERID; +} +#endif /* FSL_FEATURE_SMC_HAS_VERID */ + +#if (defined(FSL_FEATURE_SMC_HAS_PARAM) && FSL_FEATURE_SMC_HAS_PARAM) +/*! + * @brief Gets the SMC parameter. + * + * This function gets the SMC parameter including the enabled power mdoes. + * + * @param base SMC peripheral base address. + * @param param Pointer to the SMC param structure. + */ +void SMC_GetParam(SMC_Type *base, smc_param_t *param); +#endif + +/*! + * @brief Configures all power mode protection settings. + * + * This function configures the power mode protection settings for + * supported power modes in the specified chip family. The available power modes + * are defined in the smc_power_mode_protection_t. This should be done at an early + * system level initialization stage. See the reference manual for details. + * This register can only write once after the power reset. + * + * The allowed modes are passed as bit map. For example, to allow LLS and VLLS, + * use SMC_SetPowerModeProtection(kSMC_AllowPowerModeVlls | kSMC_AllowPowerModeVlps). + * To allow all modes, use SMC_SetPowerModeProtection(kSMC_AllowPowerModeAll). + * + * @param base SMC peripheral base address. + * @param allowedModes Bitmap of the allowed power modes. + */ +static inline void SMC_SetPowerModeProtection(SMC_Type *base, uint8_t allowedModes) +{ + base->PMPROT = allowedModes; +} + +/*! + * @brief Gets the current power mode status. + * + * This function returns the current power mode status. After the application + * switches the power mode, it should always check the status to check whether it + * runs into the specified mode or not. The application should check + * this mode before switching to a different mode. The system requires that + * only certain modes can switch to other specific modes. See the + * reference manual for details and the smc_power_state_t for information about + * the power status. + * + * @param base SMC peripheral base address. + * @return Current power mode status. + */ +static inline smc_power_state_t SMC_GetPowerModeState(SMC_Type *base) +{ + return (smc_power_state_t)base->PMSTAT; +} + +/*! + * @brief Prepares to enter stop modes. + * + * This function should be called before entering STOP/VLPS/LLS/VLLS modes. + */ +void SMC_PreEnterStopModes(void); + +/*! + * @brief Recovers after wake up from stop modes. + * + * This function should be called after wake up from STOP/VLPS/LLS/VLLS modes. + * It is used with @ref SMC_PreEnterStopModes. + */ +void SMC_PostExitStopModes(void); + +/*! + * @brief Prepares to enter wait modes. + * + * This function should be called before entering WAIT/VLPW modes. + */ +void SMC_PreEnterWaitModes(void); + +/*! + * @brief Recovers after wake up from stop modes. + * + * This function should be called after wake up from WAIT/VLPW modes. + * It is used with @ref SMC_PreEnterWaitModes. + */ +void SMC_PostExitWaitModes(void); + +/*! + * @brief Configures the system to RUN power mode. + * + * @param base SMC peripheral base address. + * @return SMC configuration error code. + */ +status_t SMC_SetPowerModeRun(SMC_Type *base); + +#if (defined(FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE) && FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE) +/*! + * @brief Configures the system to HSRUN power mode. + * + * @param base SMC peripheral base address. + * @return SMC configuration error code. + */ +status_t SMC_SetPowerModeHsrun(SMC_Type *base); +#endif /* FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE */ + +/*! + * @brief Configures the system to WAIT power mode. + * + * @param base SMC peripheral base address. + * @return SMC configuration error code. + */ +status_t SMC_SetPowerModeWait(SMC_Type *base); + +/*! + * @brief Configures the system to Stop power mode. + * + * @param base SMC peripheral base address. + * @param option Partial Stop mode option. + * @return SMC configuration error code. + */ +status_t SMC_SetPowerModeStop(SMC_Type *base, smc_partial_stop_option_t option); + +#if (defined(FSL_FEATURE_SMC_HAS_LPWUI) && FSL_FEATURE_SMC_HAS_LPWUI) +/*! + * @brief Configures the system to VLPR power mode. + * + * @param base SMC peripheral base address. + * @param wakeupMode Enter Normal Run mode if true, else stay in VLPR mode. + * @return SMC configuration error code. + */ +status_t SMC_SetPowerModeVlpr(SMC_Type *base, bool wakeupMode); +#else +/*! + * @brief Configures the system to VLPR power mode. + * + * @param base SMC peripheral base address. + * @return SMC configuration error code. + */ +status_t SMC_SetPowerModeVlpr(SMC_Type *base); +#endif /* FSL_FEATURE_SMC_HAS_LPWUI */ + +/*! + * @brief Configures the system to VLPW power mode. + * + * @param base SMC peripheral base address. + * @return SMC configuration error code. + */ +status_t SMC_SetPowerModeVlpw(SMC_Type *base); + +/*! + * @brief Configures the system to VLPS power mode. + * + * @param base SMC peripheral base address. + * @return SMC configuration error code. + */ +status_t SMC_SetPowerModeVlps(SMC_Type *base); + +#if (defined(FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE) +#if ((defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE) || \ + (defined(FSL_FEATURE_SMC_HAS_LPOPO) && FSL_FEATURE_SMC_HAS_LPOPO)) +/*! + * @brief Configures the system to LLS power mode. + * + * @param base SMC peripheral base address. + * @param config The LLS power mode configuration structure + * @return SMC configuration error code. + */ +status_t SMC_SetPowerModeLls(SMC_Type *base, const smc_power_mode_lls_config_t *config); +#else +/*! + * @brief Configures the system to LLS power mode. + * + * @param base SMC peripheral base address. + * @return SMC configuration error code. + */ +status_t SMC_SetPowerModeLls(SMC_Type *base); +#endif +#endif /* FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE */ + +#if (defined(FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE) +/*! + * @brief Configures the system to VLLS power mode. + * + * @param base SMC peripheral base address. + * @param config The VLLS power mode configuration structure. + * @return SMC configuration error code. + */ +status_t SMC_SetPowerModeVlls(SMC_Type *base, const smc_power_mode_vlls_config_t *config); +#endif /* FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE */ + +/*@}*/ + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +/*! @}*/ + +#endif /* _FSL_SMC_H_ */ diff --git a/source/hic_hal/freescale/kl27z/fsl_tpm.c b/source/hic_hal/freescale/kl27z/fsl_tpm.c new file mode 100644 index 000000000..9a390a2be --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_tpm.c @@ -0,0 +1,766 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fsl_tpm.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TPM_COMBINE_SHIFT (8U) + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief Gets the instance from the base address + * + * @param base TPM peripheral base address + * + * @return The TPM instance + */ +static uint32_t TPM_GetInstance(TPM_Type *base); + +/******************************************************************************* + * Variables + ******************************************************************************/ +/*! @brief Pointers to TPM bases for each instance. */ +static TPM_Type *const s_tpmBases[] = TPM_BASE_PTRS; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Pointers to TPM clocks for each instance. */ +static const clock_ip_name_t s_tpmClocks[] = TPM_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/******************************************************************************* + * Code + ******************************************************************************/ +static uint32_t TPM_GetInstance(TPM_Type *base) +{ + uint32_t instance; + uint32_t tpmArrayCount = (sizeof(s_tpmBases) / sizeof(s_tpmBases[0])); + + /* Find the instance index from base address mappings. */ + for (instance = 0; instance < tpmArrayCount; instance++) + { + if (s_tpmBases[instance] == base) + { + break; + } + } + + assert(instance < tpmArrayCount); + + return instance; +} + +void TPM_Init(TPM_Type *base, const tpm_config_t *config) +{ + assert(config); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Enable the module clock */ + CLOCK_EnableClock(s_tpmClocks[TPM_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +#if defined(FSL_FEATURE_TPM_HAS_GLOBAL) && FSL_FEATURE_TPM_HAS_GLOBAL + /* TPM reset is available on certain SoC's */ + TPM_Reset(base); +#endif + + /* Set the clock prescale factor */ + base->SC = TPM_SC_PS(config->prescale); + + /* Setup the counter operation */ + base->CONF = TPM_CONF_DOZEEN(config->enableDoze) | TPM_CONF_GTBEEN(config->useGlobalTimeBase) | + TPM_CONF_CROT(config->enableReloadOnTrigger) | TPM_CONF_CSOT(config->enableStartOnTrigger) | + TPM_CONF_CSOO(config->enableStopOnOverflow) | +#if defined(FSL_FEATURE_TPM_HAS_PAUSE_COUNTER_ON_TRIGGER) && FSL_FEATURE_TPM_HAS_PAUSE_COUNTER_ON_TRIGGER + TPM_CONF_CPOT(config->enablePauseOnTrigger) | +#endif +#if defined(FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION) && FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION + TPM_CONF_TRGSRC(config->triggerSource) | +#endif + TPM_CONF_TRGSEL(config->triggerSelect); + if (config->enableDebugMode) + { + base->CONF |= TPM_CONF_DBGMODE_MASK; + } + else + { + base->CONF &= ~TPM_CONF_DBGMODE_MASK; + } +} + +void TPM_Deinit(TPM_Type *base) +{ + /* Stop the counter */ + base->SC &= ~TPM_SC_CMOD_MASK; +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Gate the TPM clock */ + CLOCK_DisableClock(s_tpmClocks[TPM_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +void TPM_GetDefaultConfig(tpm_config_t *config) +{ + assert(config); + + /* TPM clock divide by 1 */ + config->prescale = kTPM_Prescale_Divide_1; + /* Use internal TPM counter as timebase */ + config->useGlobalTimeBase = false; + /* TPM counter continues in doze mode */ + config->enableDoze = false; + /* TPM counter pauses when in debug mode */ + config->enableDebugMode = false; + /* TPM counter will not be reloaded on input trigger */ + config->enableReloadOnTrigger = false; + /* TPM counter continues running after overflow */ + config->enableStopOnOverflow = false; + /* TPM counter starts immediately once it is enabled */ + config->enableStartOnTrigger = false; +#if defined(FSL_FEATURE_TPM_HAS_PAUSE_COUNTER_ON_TRIGGER) && FSL_FEATURE_TPM_HAS_PAUSE_COUNTER_ON_TRIGGER + config->enablePauseOnTrigger = false; +#endif + /* Choose trigger select 0 as input trigger for controlling counter operation */ + config->triggerSelect = kTPM_Trigger_Select_0; +#if defined(FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION) && FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION + /* Choose external trigger source to control counter operation */ + config->triggerSource = kTPM_TriggerSource_External; +#endif +} + +status_t TPM_SetupPwm(TPM_Type *base, + const tpm_chnl_pwm_signal_param_t *chnlParams, + uint8_t numOfChnls, + tpm_pwm_mode_t mode, + uint32_t pwmFreq_Hz, + uint32_t srcClock_Hz) +{ + assert(chnlParams); + assert(pwmFreq_Hz); + assert(numOfChnls); + assert(srcClock_Hz); +#if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE + if(mode == kTPM_CombinedPwm) + { + assert(FSL_FEATURE_TPM_COMBINE_HAS_EFFECTn(base)); + } +#endif + + uint32_t mod; + uint32_t tpmClock = (srcClock_Hz / (1U << (base->SC & TPM_SC_PS_MASK))); + uint16_t cnv; + uint8_t i; + +#if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL + /* The TPM's QDCTRL register required to be effective */ + if( FSL_FEATURE_TPM_QDCTRL_HAS_EFFECTn(base) ) + { + /* Clear quadrature Decoder mode because in quadrature Decoder mode PWM doesn't operate*/ + base->QDCTRL &= ~TPM_QDCTRL_QUADEN_MASK; + } +#endif + + switch (mode) + { + case kTPM_EdgeAlignedPwm: +#if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE + case kTPM_CombinedPwm: +#endif + base->SC &= ~TPM_SC_CPWMS_MASK; + mod = (tpmClock / pwmFreq_Hz) - 1; + break; + case kTPM_CenterAlignedPwm: + base->SC |= TPM_SC_CPWMS_MASK; + mod = tpmClock / (pwmFreq_Hz * 2); + break; + default: + return kStatus_Fail; + } + + /* Return an error in case we overflow the registers, probably would require changing + * clock source to get the desired frequency */ + if (mod > 65535U) + { + return kStatus_Fail; + } + /* Set the PWM period */ + base->MOD = mod; + + /* Setup each TPM channel */ + for (i = 0; i < numOfChnls; i++) + { + /* Return error if requested dutycycle is greater than the max allowed */ + if (chnlParams->dutyCyclePercent > 100) + { + return kStatus_Fail; + } +#if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE + if (mode == kTPM_CombinedPwm) + { + uint16_t cnvFirstEdge; + + /* This check is added for combined mode as the channel number should be the pair number */ + if (chnlParams->chnlNumber >= (FSL_FEATURE_TPM_CHANNEL_COUNTn(base) / 2)) + { + return kStatus_Fail; + } + + /* Return error if requested value is greater than the max allowed */ + if (chnlParams->firstEdgeDelayPercent > 100) + { + return kStatus_Fail; + } + /* Configure delay of the first edge */ + if (chnlParams->firstEdgeDelayPercent == 0) + { + /* No delay for the first edge */ + cnvFirstEdge = 0; + } + else + { + cnvFirstEdge = (mod * chnlParams->firstEdgeDelayPercent) / 100; + } + /* Configure dutycycle */ + if (chnlParams->dutyCyclePercent == 0) + { + /* Signal stays low */ + cnv = 0; + cnvFirstEdge = 0; + } + else + { + cnv = (mod * chnlParams->dutyCyclePercent) / 100; + /* For 100% duty cycle */ + if (cnv >= mod) + { + cnv = mod + 1; + } + } + + /* Set the combine bit for the channel pair */ + base->COMBINE |= (1U << (TPM_COMBINE_COMBINE0_SHIFT + (TPM_COMBINE_SHIFT * chnlParams->chnlNumber))); + + /* When switching mode, disable channel n first */ + base->CONTROLS[chnlParams->chnlNumber * 2].CnSC &= + ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); + + /* Wait till mode change to disable channel is acknowledged */ + while ((base->CONTROLS[chnlParams->chnlNumber * 2].CnSC & + (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } + + /* Set the requested PWM mode for channel n, PWM output requires mode select to be set to 2 */ + base->CONTROLS[chnlParams->chnlNumber * 2].CnSC |= + ((chnlParams->level << TPM_CnSC_ELSA_SHIFT) | (2U << TPM_CnSC_MSA_SHIFT)); + + /* Wait till mode change is acknowledged */ + while (!(base->CONTROLS[chnlParams->chnlNumber * 2].CnSC & + (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } + /* Set the channel pair values */ + base->CONTROLS[chnlParams->chnlNumber * 2].CnV = cnvFirstEdge; + + /* When switching mode, disable channel n + 1 first */ + base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC &= + ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); + + /* Wait till mode change to disable channel is acknowledged */ + while ((base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC & + (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } + + /* Set the requested PWM mode for channel n + 1, PWM output requires mode select to be set to 2 */ + base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC |= + ((chnlParams->level << TPM_CnSC_ELSA_SHIFT) | (2U << TPM_CnSC_MSA_SHIFT)); + + /* Wait till mode change is acknowledged */ + while (!(base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC & + (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } + /* Set the channel pair values */ + base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnV = cnvFirstEdge + cnv; + } + else + { +#endif + if (chnlParams->dutyCyclePercent == 0) + { + /* Signal stays low */ + cnv = 0; + } + else + { + cnv = (mod * chnlParams->dutyCyclePercent) / 100; + /* For 100% duty cycle */ + if (cnv >= mod) + { + cnv = mod + 1; + } + } + + /* When switching mode, disable channel first */ + base->CONTROLS[chnlParams->chnlNumber].CnSC &= + ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); + + /* Wait till mode change to disable channel is acknowledged */ + while ((base->CONTROLS[chnlParams->chnlNumber].CnSC & + (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } + + /* Set the requested PWM mode, PWM output requires mode select to be set to 2 */ + base->CONTROLS[chnlParams->chnlNumber].CnSC |= + ((chnlParams->level << TPM_CnSC_ELSA_SHIFT) | (2U << TPM_CnSC_MSA_SHIFT)); + + /* Wait till mode change is acknowledged */ + while (!(base->CONTROLS[chnlParams->chnlNumber].CnSC & + (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } + base->CONTROLS[chnlParams->chnlNumber].CnV = cnv; +#if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE + } +#endif + + chnlParams++; + } + + return kStatus_Success; +} + +void TPM_UpdatePwmDutycycle(TPM_Type *base, + tpm_chnl_t chnlNumber, + tpm_pwm_mode_t currentPwmMode, + uint8_t dutyCyclePercent) +{ + assert(chnlNumber < FSL_FEATURE_TPM_CHANNEL_COUNTn(base)); +#if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE + if(currentPwmMode == kTPM_CombinedPwm) + { + assert(FSL_FEATURE_TPM_COMBINE_HAS_EFFECTn(base)); + } +#endif + + uint16_t cnv, mod; + + mod = base->MOD; +#if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE + if (currentPwmMode == kTPM_CombinedPwm) + { + uint16_t cnvFirstEdge; + + /* This check is added for combined mode as the channel number should be the pair number */ + if (chnlNumber >= (FSL_FEATURE_TPM_CHANNEL_COUNTn(base) / 2)) + { + return; + } + cnv = (mod * dutyCyclePercent) / 100; + cnvFirstEdge = base->CONTROLS[chnlNumber * 2].CnV; + /* For 100% duty cycle */ + if (cnv >= mod) + { + cnv = mod + 1; + } + base->CONTROLS[(chnlNumber * 2) + 1].CnV = cnvFirstEdge + cnv; + } + else + { +#endif + cnv = (mod * dutyCyclePercent) / 100; + /* For 100% duty cycle */ + if (cnv >= mod) + { + cnv = mod + 1; + } + base->CONTROLS[chnlNumber].CnV = cnv; +#if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE + } +#endif +} + +void TPM_UpdateChnlEdgeLevelSelect(TPM_Type *base, tpm_chnl_t chnlNumber, uint8_t level) +{ + assert(chnlNumber < FSL_FEATURE_TPM_CHANNEL_COUNTn(base)); + + uint32_t reg = base->CONTROLS[chnlNumber].CnSC & ~(TPM_CnSC_CHF_MASK); + + /* When switching mode, disable channel first */ + base->CONTROLS[chnlNumber].CnSC &= + ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); + + /* Wait till mode change to disable channel is acknowledged */ + while ((base->CONTROLS[chnlNumber].CnSC & + (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } + + /* Clear the field and write the new level value */ + reg &= ~(TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); + reg |= ((uint32_t)level << TPM_CnSC_ELSA_SHIFT) & (TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); + + base->CONTROLS[chnlNumber].CnSC = reg; + + /* Wait till mode change is acknowledged */ + reg &= (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); + while (reg != (base->CONTROLS[chnlNumber].CnSC & + (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } +} + +void TPM_SetupInputCapture(TPM_Type *base, tpm_chnl_t chnlNumber, tpm_input_capture_edge_t captureMode) +{ + assert(chnlNumber < FSL_FEATURE_TPM_CHANNEL_COUNTn(base)); + +#if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL + /* The TPM's QDCTRL register required to be effective */ + if( FSL_FEATURE_TPM_QDCTRL_HAS_EFFECTn(base) ) + { + /* Clear quadrature Decoder mode for channel 0 or 1*/ + if ((chnlNumber == 0) || (chnlNumber == 1)) + { + base->QDCTRL &= ~TPM_QDCTRL_QUADEN_MASK; + } + } +#endif + +#if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE + /* The TPM's COMBINE register required to be effective */ + if( FSL_FEATURE_TPM_COMBINE_HAS_EFFECTn(base) ) + { + /* Clear the combine bit for chnlNumber */ + base->COMBINE &= ~(1U << TPM_COMBINE_SHIFT * (chnlNumber / 2)); + } +#endif + + /* When switching mode, disable channel first */ + base->CONTROLS[chnlNumber].CnSC &= + ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); + + /* Wait till mode change to disable channel is acknowledged */ + while ((base->CONTROLS[chnlNumber].CnSC & + (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } + + /* Set the requested input capture mode */ + base->CONTROLS[chnlNumber].CnSC |= captureMode; + + /* Wait till mode change is acknowledged */ + while (!(base->CONTROLS[chnlNumber].CnSC & + (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } +} + +void TPM_SetupOutputCompare(TPM_Type *base, + tpm_chnl_t chnlNumber, + tpm_output_compare_mode_t compareMode, + uint32_t compareValue) +{ + assert(chnlNumber < FSL_FEATURE_TPM_CHANNEL_COUNTn(base)); + +#if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL + /* The TPM's QDCTRL register required to be effective */ + if( FSL_FEATURE_TPM_QDCTRL_HAS_EFFECTn(base) ) + { + /* Clear quadrature Decoder mode for channel 0 or 1 */ + if ((chnlNumber == 0) || (chnlNumber == 1)) + { + base->QDCTRL &= ~TPM_QDCTRL_QUADEN_MASK; + } + } +#endif + + /* When switching mode, disable channel first */ + base->CONTROLS[chnlNumber].CnSC &= + ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); + + /* Wait till mode change to disable channel is acknowledged */ + while ((base->CONTROLS[chnlNumber].CnSC & + (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } + + /* Setup the channel output behaviour when a match occurs with the compare value */ + base->CONTROLS[chnlNumber].CnSC |= compareMode; + + /* Setup the compare value */ + base->CONTROLS[chnlNumber].CnV = compareValue; + + /* Wait till mode change is acknowledged */ + while (!(base->CONTROLS[chnlNumber].CnSC & + (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } +} + +#if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE +void TPM_SetupDualEdgeCapture(TPM_Type *base, + tpm_chnl_t chnlPairNumber, + const tpm_dual_edge_capture_param_t *edgeParam, + uint32_t filterValue) +{ + assert(edgeParam); + assert(chnlPairNumber < FSL_FEATURE_TPM_CHANNEL_COUNTn(base) / 2); + assert(FSL_FEATURE_TPM_COMBINE_HAS_EFFECTn(base)); + + uint32_t reg; + +#if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL + /* The TPM's QDCTRL register required to be effective */ + if( FSL_FEATURE_TPM_QDCTRL_HAS_EFFECTn(base) ) + { + /* Clear quadrature Decoder mode for channel 0 or 1*/ + if (chnlPairNumber == 0) + { + base->QDCTRL &= ~TPM_QDCTRL_QUADEN_MASK; + } + } +#endif + + /* Unlock: When switching mode, disable channel first */ + base->CONTROLS[chnlPairNumber * 2].CnSC &= + ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); + + /* Wait till mode change to disable channel is acknowledged */ + while ((base->CONTROLS[chnlPairNumber * 2].CnSC & + (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } + + base->CONTROLS[chnlPairNumber * 2 + 1].CnSC &= + ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); + + /* Wait till mode change to disable channel is acknowledged */ + while ((base->CONTROLS[chnlPairNumber * 2 + 1].CnSC & + (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } + + /* Now, the registers for input mode can be operated. */ + if (edgeParam->enableSwap) + { + /* Set the combine and swap bits for the channel pair */ + base->COMBINE |= (TPM_COMBINE_COMBINE0_MASK | TPM_COMBINE_COMSWAP0_MASK) + << (TPM_COMBINE_SHIFT * chnlPairNumber); + + /* Input filter setup for channel n+1 input */ + reg = base->FILTER; + reg &= ~(TPM_FILTER_CH0FVAL_MASK << (TPM_FILTER_CH1FVAL_SHIFT * (chnlPairNumber + 1))); + reg |= (filterValue << (TPM_FILTER_CH1FVAL_SHIFT * (chnlPairNumber + 1))); + base->FILTER = reg; + } + else + { + reg = base->COMBINE; + /* Clear the swap bit for the channel pair */ + reg &= ~(TPM_COMBINE_COMSWAP0_MASK << (TPM_COMBINE_COMSWAP0_SHIFT * chnlPairNumber)); + + /* Set the combine bit for the channel pair */ + reg |= TPM_COMBINE_COMBINE0_MASK << (TPM_COMBINE_SHIFT * chnlPairNumber); + base->COMBINE = reg; + + /* Input filter setup for channel n input */ + reg = base->FILTER; + reg &= ~(TPM_FILTER_CH0FVAL_MASK << (TPM_FILTER_CH1FVAL_SHIFT * chnlPairNumber)); + reg |= (filterValue << (TPM_FILTER_CH1FVAL_SHIFT * chnlPairNumber)); + base->FILTER = reg; + } + + /* Setup the edge detection from channel n */ + base->CONTROLS[chnlPairNumber * 2].CnSC |= edgeParam->currChanEdgeMode; + + /* Wait till mode change is acknowledged */ + while (!(base->CONTROLS[chnlPairNumber * 2].CnSC & + (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } + + /* Setup the edge detection from channel n+1 */ + base->CONTROLS[(chnlPairNumber * 2) + 1].CnSC |= edgeParam->nextChanEdgeMode; + + /* Wait till mode change is acknowledged */ + while (!(base->CONTROLS[(chnlPairNumber * 2) + 1].CnSC & + (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } +} +#endif + +#if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL +void TPM_SetupQuadDecode(TPM_Type *base, + const tpm_phase_params_t *phaseAParams, + const tpm_phase_params_t *phaseBParams, + tpm_quad_decode_mode_t quadMode) +{ + assert(phaseAParams); + assert(phaseBParams); + assert(FSL_FEATURE_TPM_QDCTRL_HAS_EFFECTn(base)); + + base->CONTROLS[0].CnSC &= ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); + + /* Wait till mode change to disable channel is acknowledged */ + while ((base->CONTROLS[0].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } + uint32_t reg; + + /* Set Phase A filter value */ + reg = base->FILTER; + reg &= ~(TPM_FILTER_CH0FVAL_MASK); + reg |= TPM_FILTER_CH0FVAL(phaseAParams->phaseFilterVal); + base->FILTER = reg; + +#if defined(FSL_FEATURE_TPM_HAS_POL) && FSL_FEATURE_TPM_HAS_POL + /* Set Phase A polarity */ + if (phaseAParams->phasePolarity) + { + base->POL |= TPM_POL_POL0_MASK; + } + else + { + base->POL &= ~TPM_POL_POL0_MASK; + } +#endif + + base->CONTROLS[1].CnSC &= ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); + + /* Wait till mode change to disable channel is acknowledged */ + while ((base->CONTROLS[1].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) + { + } + /* Set Phase B filter value */ + reg = base->FILTER; + reg &= ~(TPM_FILTER_CH1FVAL_MASK); + reg |= TPM_FILTER_CH1FVAL(phaseBParams->phaseFilterVal); + base->FILTER = reg; +#if defined(FSL_FEATURE_TPM_HAS_POL) && FSL_FEATURE_TPM_HAS_POL + /* Set Phase B polarity */ + if (phaseBParams->phasePolarity) + { + base->POL |= TPM_POL_POL1_MASK; + } + else + { + base->POL &= ~TPM_POL_POL1_MASK; + } +#endif + + /* Set Quadrature mode */ + reg = base->QDCTRL; + reg &= ~(TPM_QDCTRL_QUADMODE_MASK); + reg |= TPM_QDCTRL_QUADMODE(quadMode); + base->QDCTRL = reg; + + /* Enable Quad decode */ + base->QDCTRL |= TPM_QDCTRL_QUADEN_MASK; +} + +#endif + +void TPM_EnableInterrupts(TPM_Type *base, uint32_t mask) +{ + uint32_t chnlInterrupts = (mask & 0xFF); + uint8_t chnlNumber = 0; + + /* Enable the timer overflow interrupt */ + if (mask & kTPM_TimeOverflowInterruptEnable) + { + base->SC |= TPM_SC_TOIE_MASK; + } + + /* Enable the channel interrupts */ + while (chnlInterrupts) + { + if (chnlInterrupts & 0x1) + { + base->CONTROLS[chnlNumber].CnSC |= TPM_CnSC_CHIE_MASK; + } + chnlNumber++; + chnlInterrupts = chnlInterrupts >> 1U; + } +} + +void TPM_DisableInterrupts(TPM_Type *base, uint32_t mask) +{ + uint32_t chnlInterrupts = (mask & 0xFF); + uint8_t chnlNumber = 0; + + /* Disable the timer overflow interrupt */ + if (mask & kTPM_TimeOverflowInterruptEnable) + { + base->SC &= ~TPM_SC_TOIE_MASK; + } + + /* Disable the channel interrupts */ + while (chnlInterrupts) + { + if (chnlInterrupts & 0x1) + { + base->CONTROLS[chnlNumber].CnSC &= ~TPM_CnSC_CHIE_MASK; + } + chnlNumber++; + chnlInterrupts = chnlInterrupts >> 1U; + } +} + +uint32_t TPM_GetEnabledInterrupts(TPM_Type *base) +{ + uint32_t enabledInterrupts = 0; + int8_t chnlCount = FSL_FEATURE_TPM_CHANNEL_COUNTn(base); + + /* The CHANNEL_COUNT macro returns -1 if it cannot match the TPM instance */ + assert(chnlCount != -1); + + /* Check if timer overflow interrupt is enabled */ + if (base->SC & TPM_SC_TOIE_MASK) + { + enabledInterrupts |= kTPM_TimeOverflowInterruptEnable; + } + + /* Check if the channel interrupts are enabled */ + while (chnlCount > 0) + { + chnlCount--; + if (base->CONTROLS[chnlCount].CnSC & TPM_CnSC_CHIE_MASK) + { + enabledInterrupts |= (1U << chnlCount); + } + } + + return enabledInterrupts; +} diff --git a/source/hic_hal/freescale/kl27z/fsl_tpm.h b/source/hic_hal/freescale/kl27z/fsl_tpm.h new file mode 100644 index 000000000..5722a2bf3 --- /dev/null +++ b/source/hic_hal/freescale/kl27z/fsl_tpm.h @@ -0,0 +1,630 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _FSL_TPM_H_ +#define _FSL_TPM_H_ + +#include "fsl_common.h" +#include "fsl_clock.h" + +/*! + * @addtogroup tpm + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +#define FSL_TPM_DRIVER_VERSION (MAKE_VERSION(2, 0, 2)) /*!< Version 2.0.2 */ +/*@}*/ + +/*! + * @brief List of TPM channels. + * @note Actual number of available channels is SoC dependent + */ +typedef enum _tpm_chnl +{ + kTPM_Chnl_0 = 0U, /*!< TPM channel number 0*/ + kTPM_Chnl_1, /*!< TPM channel number 1 */ + kTPM_Chnl_2, /*!< TPM channel number 2 */ + kTPM_Chnl_3, /*!< TPM channel number 3 */ + kTPM_Chnl_4, /*!< TPM channel number 4 */ + kTPM_Chnl_5, /*!< TPM channel number 5 */ + kTPM_Chnl_6, /*!< TPM channel number 6 */ + kTPM_Chnl_7 /*!< TPM channel number 7 */ +} tpm_chnl_t; + +/*! @brief TPM PWM operation modes */ +typedef enum _tpm_pwm_mode +{ + kTPM_EdgeAlignedPwm = 0U, /*!< Edge aligned PWM */ + kTPM_CenterAlignedPwm, /*!< Center aligned PWM */ +#if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE + kTPM_CombinedPwm /*!< Combined PWM */ +#endif +} tpm_pwm_mode_t; + +/*! @brief TPM PWM output pulse mode: high-true, low-true or no output */ +typedef enum _tpm_pwm_level_select +{ + kTPM_NoPwmSignal = 0U, /*!< No PWM output on pin */ + kTPM_LowTrue, /*!< Low true pulses */ + kTPM_HighTrue /*!< High true pulses */ +} tpm_pwm_level_select_t; + +/*! @brief Options to configure a TPM channel's PWM signal */ +typedef struct _tpm_chnl_pwm_signal_param +{ + tpm_chnl_t chnlNumber; /*!< TPM channel to configure. + In combined mode (available in some SoC's, this represents the + channel pair number */ + tpm_pwm_level_select_t level; /*!< PWM output active level select */ + uint8_t dutyCyclePercent; /*!< PWM pulse width, value should be between 0 to 100 + 0=inactive signal(0% duty cycle)... + 100=always active signal (100% duty cycle)*/ +#if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE + uint8_t firstEdgeDelayPercent; /*!< Used only in combined PWM mode to generate asymmetrical PWM. + Specifies the delay to the first edge in a PWM period. + If unsure, leave as 0; Should be specified as + percentage of the PWM period */ +#endif +} tpm_chnl_pwm_signal_param_t; + +/*! + * @brief Trigger options available. + * + * This is used for both internal & external trigger sources (external option available in certain SoC's) + * + * @note The actual trigger options available is SoC-specific. + */ +typedef enum _tpm_trigger_select +{ + kTPM_Trigger_Select_0 = 0U, + kTPM_Trigger_Select_1, + kTPM_Trigger_Select_2, + kTPM_Trigger_Select_3, + kTPM_Trigger_Select_4, + kTPM_Trigger_Select_5, + kTPM_Trigger_Select_6, + kTPM_Trigger_Select_7, + kTPM_Trigger_Select_8, + kTPM_Trigger_Select_9, + kTPM_Trigger_Select_10, + kTPM_Trigger_Select_11, + kTPM_Trigger_Select_12, + kTPM_Trigger_Select_13, + kTPM_Trigger_Select_14, + kTPM_Trigger_Select_15 +} tpm_trigger_select_t; + +#if defined(FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION) && FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION +/*! + * @brief Trigger source options available + * + * @note This selection is available only on some SoC's. For SoC's without this selection, the only + * trigger source available is internal triger. + */ +typedef enum _tpm_trigger_source +{ + kTPM_TriggerSource_External = 0U, /*!< Use external trigger input */ + kTPM_TriggerSource_Internal /*!< Use internal trigger */ +} tpm_trigger_source_t; +#endif + +/*! @brief TPM output compare modes */ +typedef enum _tpm_output_compare_mode +{ + kTPM_NoOutputSignal = (1U << TPM_CnSC_MSA_SHIFT), /*!< No channel output when counter reaches CnV */ + kTPM_ToggleOnMatch = ((1U << TPM_CnSC_MSA_SHIFT) | (1U << TPM_CnSC_ELSA_SHIFT)), /*!< Toggle output */ + kTPM_ClearOnMatch = ((1U << TPM_CnSC_MSA_SHIFT) | (2U << TPM_CnSC_ELSA_SHIFT)), /*!< Clear output */ + kTPM_SetOnMatch = ((1U << TPM_CnSC_MSA_SHIFT) | (3U << TPM_CnSC_ELSA_SHIFT)), /*!< Set output */ + kTPM_HighPulseOutput = ((3U << TPM_CnSC_MSA_SHIFT) | (1U << TPM_CnSC_ELSA_SHIFT)), /*!< Pulse output high */ + kTPM_LowPulseOutput = ((3U << TPM_CnSC_MSA_SHIFT) | (2U << TPM_CnSC_ELSA_SHIFT)) /*!< Pulse output low */ +} tpm_output_compare_mode_t; + +/*! @brief TPM input capture edge */ +typedef enum _tpm_input_capture_edge +{ + kTPM_RisingEdge = (1U << TPM_CnSC_ELSA_SHIFT), /*!< Capture on rising edge only */ + kTPM_FallingEdge = (2U << TPM_CnSC_ELSA_SHIFT), /*!< Capture on falling edge only */ + kTPM_RiseAndFallEdge = (3U << TPM_CnSC_ELSA_SHIFT) /*!< Capture on rising or falling edge */ +} tpm_input_capture_edge_t; + +#if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE +/*! + * @brief TPM dual edge capture parameters + * + * @note This mode is available only on some SoC's. + */ +typedef struct _tpm_dual_edge_capture_param +{ + bool enableSwap; /*!< true: Use channel n+1 input, channel n input is ignored; + false: Use channel n input, channel n+1 input is ignored */ + tpm_input_capture_edge_t currChanEdgeMode; /*!< Input capture edge select for channel n */ + tpm_input_capture_edge_t nextChanEdgeMode; /*!< Input capture edge select for channel n+1 */ +} tpm_dual_edge_capture_param_t; +#endif + +#if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL +/*! + * @brief TPM quadrature decode modes + * + * @note This mode is available only on some SoC's. + */ +typedef enum _tpm_quad_decode_mode +{ + kTPM_QuadPhaseEncode = 0U, /*!< Phase A and Phase B encoding mode */ + kTPM_QuadCountAndDir /*!< Count and direction encoding mode */ +} tpm_quad_decode_mode_t; + +/*! @brief TPM quadrature phase polarities */ +typedef enum _tpm_phase_polarity +{ + kTPM_QuadPhaseNormal = 0U, /*!< Phase input signal is not inverted */ + kTPM_QuadPhaseInvert /*!< Phase input signal is inverted */ +} tpm_phase_polarity_t; + +/*! @brief TPM quadrature decode phase parameters */ +typedef struct _tpm_phase_param +{ + uint32_t phaseFilterVal; /*!< Filter value, filter is disabled when the value is zero */ + tpm_phase_polarity_t phasePolarity; /*!< Phase polarity */ +} tpm_phase_params_t; +#endif + +/*! @brief TPM clock source selection*/ +typedef enum _tpm_clock_source +{ + kTPM_SystemClock = 1U, /*!< System clock */ + kTPM_ExternalClock /*!< External clock */ +} tpm_clock_source_t; + +/*! @brief TPM prescale value selection for the clock source*/ +typedef enum _tpm_clock_prescale +{ + kTPM_Prescale_Divide_1 = 0U, /*!< Divide by 1 */ + kTPM_Prescale_Divide_2, /*!< Divide by 2 */ + kTPM_Prescale_Divide_4, /*!< Divide by 4 */ + kTPM_Prescale_Divide_8, /*!< Divide by 8 */ + kTPM_Prescale_Divide_16, /*!< Divide by 16 */ + kTPM_Prescale_Divide_32, /*!< Divide by 32 */ + kTPM_Prescale_Divide_64, /*!< Divide by 64 */ + kTPM_Prescale_Divide_128 /*!< Divide by 128 */ +} tpm_clock_prescale_t; + +/*! + * @brief TPM config structure + * + * This structure holds the configuration settings for the TPM peripheral. To initialize this + * structure to reasonable defaults, call the TPM_GetDefaultConfig() function and pass a + * pointer to your config structure instance. + * + * The config struct can be made const so it resides in flash + */ +typedef struct _tpm_config +{ + tpm_clock_prescale_t prescale; /*!< Select TPM clock prescale value */ + bool useGlobalTimeBase; /*!< true: Use of an external global time base is enabled; + false: disabled */ + tpm_trigger_select_t triggerSelect; /*!< Input trigger to use for controlling the counter operation */ +#if defined(FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION) && FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION + tpm_trigger_source_t triggerSource; /*!< Decides if we use external or internal trigger. */ +#endif + bool enableDoze; /*!< true: TPM counter is paused in doze mode; + false: TPM counter continues in doze mode */ + bool enableDebugMode; /*!< true: TPM counter continues in debug mode; + false: TPM counter is paused in debug mode */ + bool enableReloadOnTrigger; /*!< true: TPM counter is reloaded on trigger; + false: TPM counter not reloaded */ + bool enableStopOnOverflow; /*!< true: TPM counter stops after overflow; + false: TPM counter continues running after overflow */ + bool enableStartOnTrigger; /*!< true: TPM counter only starts when a trigger is detected; + false: TPM counter starts immediately */ +#if defined(FSL_FEATURE_TPM_HAS_PAUSE_COUNTER_ON_TRIGGER) && FSL_FEATURE_TPM_HAS_PAUSE_COUNTER_ON_TRIGGER + bool enablePauseOnTrigger; /*!< true: TPM counter will pause while trigger remains asserted; + false: TPM counter continues running */ +#endif +} tpm_config_t; + +/*! @brief List of TPM interrupts */ +typedef enum _tpm_interrupt_enable +{ + kTPM_Chnl0InterruptEnable = (1U << 0), /*!< Channel 0 interrupt.*/ + kTPM_Chnl1InterruptEnable = (1U << 1), /*!< Channel 1 interrupt.*/ + kTPM_Chnl2InterruptEnable = (1U << 2), /*!< Channel 2 interrupt.*/ + kTPM_Chnl3InterruptEnable = (1U << 3), /*!< Channel 3 interrupt.*/ + kTPM_Chnl4InterruptEnable = (1U << 4), /*!< Channel 4 interrupt.*/ + kTPM_Chnl5InterruptEnable = (1U << 5), /*!< Channel 5 interrupt.*/ + kTPM_Chnl6InterruptEnable = (1U << 6), /*!< Channel 6 interrupt.*/ + kTPM_Chnl7InterruptEnable = (1U << 7), /*!< Channel 7 interrupt.*/ + kTPM_TimeOverflowInterruptEnable = (1U << 8) /*!< Time overflow interrupt.*/ +} tpm_interrupt_enable_t; + +/*! @brief List of TPM flags */ +typedef enum _tpm_status_flags +{ + kTPM_Chnl0Flag = (1U << 0), /*!< Channel 0 flag */ + kTPM_Chnl1Flag = (1U << 1), /*!< Channel 1 flag */ + kTPM_Chnl2Flag = (1U << 2), /*!< Channel 2 flag */ + kTPM_Chnl3Flag = (1U << 3), /*!< Channel 3 flag */ + kTPM_Chnl4Flag = (1U << 4), /*!< Channel 4 flag */ + kTPM_Chnl5Flag = (1U << 5), /*!< Channel 5 flag */ + kTPM_Chnl6Flag = (1U << 6), /*!< Channel 6 flag */ + kTPM_Chnl7Flag = (1U << 7), /*!< Channel 7 flag */ + kTPM_TimeOverflowFlag = (1U << 8) /*!< Time overflow flag */ +} tpm_status_flags_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name Initialization and deinitialization + * @{ + */ + +/*! + * @brief Ungates the TPM clock and configures the peripheral for basic operation. + * + * @note This API should be called at the beginning of the application using the TPM driver. + * + * @param base TPM peripheral base address + * @param config Pointer to user's TPM config structure. + */ +void TPM_Init(TPM_Type *base, const tpm_config_t *config); + +/*! + * @brief Stops the counter and gates the TPM clock + * + * @param base TPM peripheral base address + */ +void TPM_Deinit(TPM_Type *base); + +/*! + * @brief Fill in the TPM config struct with the default settings + * + * The default values are: + * @code + * config->prescale = kTPM_Prescale_Divide_1; + * config->useGlobalTimeBase = false; + * config->dozeEnable = false; + * config->dbgMode = false; + * config->enableReloadOnTrigger = false; + * config->enableStopOnOverflow = false; + * config->enableStartOnTrigger = false; + *#if FSL_FEATURE_TPM_HAS_PAUSE_COUNTER_ON_TRIGGER + * config->enablePauseOnTrigger = false; + *#endif + * config->triggerSelect = kTPM_Trigger_Select_0; + *#if FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION + * config->triggerSource = kTPM_TriggerSource_External; + *#endif + * @endcode + * @param config Pointer to user's TPM config structure. + */ +void TPM_GetDefaultConfig(tpm_config_t *config); + +/*! @}*/ + +/*! + * @name Channel mode operations + * @{ + */ + +/*! + * @brief Configures the PWM signal parameters + * + * User calls this function to configure the PWM signals period, mode, dutycycle and edge. Use this + * function to configure all the TPM channels that will be used to output a PWM signal + * + * @param base TPM peripheral base address + * @param chnlParams Array of PWM channel parameters to configure the channel(s) + * @param numOfChnls Number of channels to configure, this should be the size of the array passed in + * @param mode PWM operation mode, options available in enumeration ::tpm_pwm_mode_t + * @param pwmFreq_Hz PWM signal frequency in Hz + * @param srcClock_Hz TPM counter clock in Hz + * + * @return kStatus_Success if the PWM setup was successful, + * kStatus_Error on failure + */ +status_t TPM_SetupPwm(TPM_Type *base, + const tpm_chnl_pwm_signal_param_t *chnlParams, + uint8_t numOfChnls, + tpm_pwm_mode_t mode, + uint32_t pwmFreq_Hz, + uint32_t srcClock_Hz); + +/*! + * @brief Update the duty cycle of an active PWM signal + * + * @param base TPM peripheral base address + * @param chnlNumber The channel number. In combined mode, this represents + * the channel pair number + * @param currentPwmMode The current PWM mode set during PWM setup + * @param dutyCyclePercent New PWM pulse width, value should be between 0 to 100 + * 0=inactive signal(0% duty cycle)... + * 100=active signal (100% duty cycle) + */ +void TPM_UpdatePwmDutycycle(TPM_Type *base, + tpm_chnl_t chnlNumber, + tpm_pwm_mode_t currentPwmMode, + uint8_t dutyCyclePercent); + +/*! + * @brief Update the edge level selection for a channel + * + * @param base TPM peripheral base address + * @param chnlNumber The channel number + * @param level The level to be set to the ELSnB:ELSnA field; valid values are 00, 01, 10, 11. + * See the appropriate SoC reference manual for details about this field. + */ +void TPM_UpdateChnlEdgeLevelSelect(TPM_Type *base, tpm_chnl_t chnlNumber, uint8_t level); + +/*! + * @brief Enables capturing an input signal on the channel using the function parameters. + * + * When the edge specified in the captureMode argument occurs on the channel, the TPM counter is captured into + * the CnV register. The user has to read the CnV register separately to get this value. + * + * @param base TPM peripheral base address + * @param chnlNumber The channel number + * @param captureMode Specifies which edge to capture + */ +void TPM_SetupInputCapture(TPM_Type *base, tpm_chnl_t chnlNumber, tpm_input_capture_edge_t captureMode); + +/*! + * @brief Configures the TPM to generate timed pulses. + * + * When the TPM counter matches the value of compareVal argument (this is written into CnV reg), the channel + * output is changed based on what is specified in the compareMode argument. + * + * @param base TPM peripheral base address + * @param chnlNumber The channel number + * @param compareMode Action to take on the channel output when the compare condition is met + * @param compareValue Value to be programmed in the CnV register. + */ +void TPM_SetupOutputCompare(TPM_Type *base, + tpm_chnl_t chnlNumber, + tpm_output_compare_mode_t compareMode, + uint32_t compareValue); + +#if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE +/*! + * @brief Configures the dual edge capture mode of the TPM. + * + * This function allows to measure a pulse width of the signal on the input of channel of a + * channel pair. The filter function is disabled if the filterVal argument passed is zero. + * + * @param base TPM peripheral base address + * @param chnlPairNumber The TPM channel pair number; options are 0, 1, 2, 3 + * @param edgeParam Sets up the dual edge capture function + * @param filterValue Filter value, specify 0 to disable filter. + */ +void TPM_SetupDualEdgeCapture(TPM_Type *base, + tpm_chnl_t chnlPairNumber, + const tpm_dual_edge_capture_param_t *edgeParam, + uint32_t filterValue); +#endif + +#if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL +/*! + * @brief Configures the parameters and activates the quadrature decode mode. + * + * @param base TPM peripheral base address + * @param phaseAParams Phase A configuration parameters + * @param phaseBParams Phase B configuration parameters + * @param quadMode Selects encoding mode used in quadrature decoder mode + */ +void TPM_SetupQuadDecode(TPM_Type *base, + const tpm_phase_params_t *phaseAParams, + const tpm_phase_params_t *phaseBParams, + tpm_quad_decode_mode_t quadMode); +#endif + +/*! @}*/ + +/*! + * @name Interrupt Interface + * @{ + */ + +/*! + * @brief Enables the selected TPM interrupts. + * + * @param base TPM peripheral base address + * @param mask The interrupts to enable. This is a logical OR of members of the + * enumeration ::tpm_interrupt_enable_t + */ +void TPM_EnableInterrupts(TPM_Type *base, uint32_t mask); + +/*! + * @brief Disables the selected TPM interrupts. + * + * @param base TPM peripheral base address + * @param mask The interrupts to disable. This is a logical OR of members of the + * enumeration ::tpm_interrupt_enable_t + */ +void TPM_DisableInterrupts(TPM_Type *base, uint32_t mask); + +/*! + * @brief Gets the enabled TPM interrupts. + * + * @param base TPM peripheral base address + * + * @return The enabled interrupts. This is the logical OR of members of the + * enumeration ::tpm_interrupt_enable_t + */ +uint32_t TPM_GetEnabledInterrupts(TPM_Type *base); + +/*! @}*/ + +/*! + * @name Status Interface + * @{ + */ + +/*! + * @brief Gets the TPM status flags + * + * @param base TPM peripheral base address + * + * @return The status flags. This is the logical OR of members of the + * enumeration ::tpm_status_flags_t + */ +static inline uint32_t TPM_GetStatusFlags(TPM_Type *base) +{ + return base->STATUS; +} + +/*! + * @brief Clears the TPM status flags + * + * @param base TPM peripheral base address + * @param mask The status flags to clear. This is a logical OR of members of the + * enumeration ::tpm_status_flags_t + */ +static inline void TPM_ClearStatusFlags(TPM_Type *base, uint32_t mask) +{ + /* Clear the status flags */ + base->STATUS = mask; +} + +/*! @}*/ + +/*! + * @name Read and write the timer period + * @{ + */ + +/*! + * @brief Sets the timer period in units of ticks. + * + * Timers counts from 0 until it equals the count value set here. The count value is written to + * the MOD register. + * + * @note + * 1. This API allows the user to use the TPM module as a timer. Do not mix usage + * of this API with TPM's PWM setup API's. + * 2. Call the utility macros provided in the fsl_common.h to convert usec or msec to ticks. + * + * @param base TPM peripheral base address + * @param ticks A timer period in units of ticks, which should be equal or greater than 1. + */ +static inline void TPM_SetTimerPeriod(TPM_Type *base, uint32_t ticks) +{ + base->MOD = ticks; +} + +/*! + * @brief Reads the current timer counting value. + * + * This function returns the real-time timer counting value in a range from 0 to a + * timer period. + * + * @note Call the utility macros provided in the fsl_common.h to convert ticks to usec or msec. + * + * @param base TPM peripheral base address + * + * @return The current counter value in ticks + */ +static inline uint32_t TPM_GetCurrentTimerCount(TPM_Type *base) +{ + return (uint32_t)((base->CNT & TPM_CNT_COUNT_MASK) >> TPM_CNT_COUNT_SHIFT); +} + +/*! + * @name Timer Start and Stop + * @{ + */ + +/*! + * @brief Starts the TPM counter. + * + * + * @param base TPM peripheral base address + * @param clockSource TPM clock source; once clock source is set the counter will start running + */ +static inline void TPM_StartTimer(TPM_Type *base, tpm_clock_source_t clockSource) +{ + uint32_t reg = base->SC; + + reg &= ~(TPM_SC_CMOD_MASK); + reg |= TPM_SC_CMOD(clockSource); + base->SC = reg; +} + +/*! + * @brief Stops the TPM counter. + * + * @param base TPM peripheral base address + */ +static inline void TPM_StopTimer(TPM_Type *base) +{ + /* Set clock source to none to disable counter */ + base->SC &= ~(TPM_SC_CMOD_MASK); + + /* Wait till this reads as zero acknowledging the counter is disabled */ + while (base->SC & TPM_SC_CMOD_MASK) + { + } +} + +/*! @}*/ + +#if defined(FSL_FEATURE_TPM_HAS_GLOBAL) && FSL_FEATURE_TPM_HAS_GLOBAL +/*! + * @brief Performs a software reset on the TPM module. + * + * Reset all internal logic and registers, except the Global Register. Remains set until cleared by software.. + * + * @note TPM software reset is available on certain SoC's only + * + * @param base TPM peripheral base address + */ +static inline void TPM_Reset(TPM_Type *base) +{ + base->GLOBAL |= TPM_GLOBAL_RST_MASK; + base->GLOBAL &= ~TPM_GLOBAL_RST_MASK; +} +#endif + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_TPM_H_ */ diff --git a/source/hic_hal/freescale/kl27z/gcc/startup_MKL27Z4.S b/source/hic_hal/freescale/kl27z/gcc/startup_MKL27Z4.S index b22302ae6..b3c1af858 100644 --- a/source/hic_hal/freescale/kl27z/gcc/startup_MKL27Z4.S +++ b/source/hic_hal/freescale/kl27z/gcc/startup_MKL27Z4.S @@ -76,12 +76,23 @@ __isr_vector: .size __isr_vector, . - __isr_vector +#if defined(DAPLINK_BL) + /* TODO: Bootloader Configuration Area (BCA) used by Kinetis ROM Bootloader */ +#endif + /* Flash Configuration */ .section .FlashConfig, "a" +#if defined(MICROBIT_LOCK_BOOTLOADER) + .long 0x5243494D + .long 0x5449424F + .long 0xFFFFFFF0 + .long 0xFFFF39FE +#else .long 0xFFFFFFFF .long 0xFFFFFFFF .long 0xFFFFFFFF .long 0xFFFF3FFE +#endif .text .thumb diff --git a/source/hic_hal/freescale/kl27z/uart.c b/source/hic_hal/freescale/kl27z/uart.c index a57ee653b..da531e5ad 100644 --- a/source/hic_hal/freescale/kl27z/uart.c +++ b/source/hic_hal/freescale/kl27z/uart.c @@ -86,12 +86,14 @@ int32_t uart_initialize(void) clear_buffers(); // alternate setting - UART_PORT->PCR[PIN_UART_RX_BIT] = PORT_PCR_MUX(PIN_UART_RX_MUX_ALT) | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK; + UART_PORT->PCR[PIN_UART_RX_BIT] = PORT_PCR_MUX(PIN_UART_RX_MUX_ALT); UART_PORT->PCR[PIN_UART_TX_BIT] = PORT_PCR_MUX(PIN_UART_TX_MUX_ALT); // transmitter and receiver enabled UART->CTRL |= LPUART_CTRL_RE_MASK | LPUART_CTRL_TE_MASK; // Enable receiver interrupt and RX Overrun interrupt UART->CTRL |= LPUART_CTRL_RIE_MASK | LPUART_CTRL_ORIE_MASK; + + NVIC_SetPriority(UART_RX_TX_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); NVIC_ClearPendingIRQ(UART_RX_TX_IRQn); NVIC_EnableIRQ(UART_RX_TX_IRQn); return 1; diff --git a/source/hic_hal/freescale/kl27z/usb_config.c b/source/hic_hal/freescale/kl27z/usb_config.c index 123957820..7bd4a8225 100644 --- a/source/hic_hal/freescale/kl27z/usb_config.c +++ b/source/hic_hal/freescale/kl27z/usb_config.c @@ -68,7 +68,12 @@ // when the device is fully operational (bMaxPower) // #define USBD_CFGDESC_BMATTRIBUTES 0x80 + +#if !defined(BOARD_USB_BMAXPOWER) #define USBD_CFGDESC_BMAXPOWER 0xFA +#else +#define USBD_CFGDESC_BMAXPOWER BOARD_USB_BMAXPOWER +#endif // String Settings // These settings affect String Descriptor diff --git a/source/hic_hal/freescale/usbd_kinetis.c b/source/hic_hal/freescale/usbd_kinetis.c index 4f06f63fd..61a0bf436 100644 --- a/source/hic_hal/freescale/usbd_kinetis.c +++ b/source/hic_hal/freescale/usbd_kinetis.c @@ -227,6 +227,7 @@ void USBD_Reset(void) USB0->ERREN = 0xFF; /* enable error interrupt sources */ USB0->ADDR = 0x00; /* set default address */ + NVIC_SetPriority(USB0_IRQn, 0x01); /* set second highest priority */ NVIC_EnableIRQ(USB0_IRQn); } diff --git a/source/hic_hal/maxim/max32620/usb_config.c b/source/hic_hal/maxim/max32620/usb_config.c index ca50523e1..21abdbaf3 100644 --- a/source/hic_hal/maxim/max32620/usb_config.c +++ b/source/hic_hal/maxim/max32620/usb_config.c @@ -68,7 +68,11 @@ // when the device is fully operational (bMaxPower) // #define USBD_CFGDESC_BMATTRIBUTES 0x80 +#if !defined(BOARD_USB_BMAXPOWER) #define USBD_CFGDESC_BMAXPOWER 0xFA +#else +#define USBD_CFGDESC_BMAXPOWER BOARD_USB_BMAXPOWER +#endif // String Settings // These settings affect String Descriptor diff --git a/source/hic_hal/maxim/max32625/usb_config.c b/source/hic_hal/maxim/max32625/usb_config.c index ca50523e1..21abdbaf3 100755 --- a/source/hic_hal/maxim/max32625/usb_config.c +++ b/source/hic_hal/maxim/max32625/usb_config.c @@ -68,7 +68,11 @@ // when the device is fully operational (bMaxPower) // #define USBD_CFGDESC_BMATTRIBUTES 0x80 +#if !defined(BOARD_USB_BMAXPOWER) #define USBD_CFGDESC_BMAXPOWER 0xFA +#else +#define USBD_CFGDESC_BMAXPOWER BOARD_USB_BMAXPOWER +#endif // String Settings // These settings affect String Descriptor diff --git a/source/hic_hal/nuvoton/m48ssidae/usb_config.c b/source/hic_hal/nuvoton/m48ssidae/usb_config.c index 053f59fed..79ae70d77 100644 --- a/source/hic_hal/nuvoton/m48ssidae/usb_config.c +++ b/source/hic_hal/nuvoton/m48ssidae/usb_config.c @@ -68,7 +68,11 @@ // when the device is fully operational (bMaxPower) // #define USBD_CFGDESC_BMATTRIBUTES 0x80 +#if !defined(BOARD_USB_BMAXPOWER) #define USBD_CFGDESC_BMAXPOWER 0xFA +#else +#define USBD_CFGDESC_BMAXPOWER BOARD_USB_BMAXPOWER +#endif // String Settings // These settings affect String Descriptor diff --git a/source/hic_hal/nxp/lpc11u35/usb_config.c b/source/hic_hal/nxp/lpc11u35/usb_config.c index 9e6233b6c..56a3ef7de 100644 --- a/source/hic_hal/nxp/lpc11u35/usb_config.c +++ b/source/hic_hal/nxp/lpc11u35/usb_config.c @@ -68,7 +68,11 @@ // when the device is fully operational (bMaxPower) // #define USBD_CFGDESC_BMATTRIBUTES 0x80 +#if !defined(BOARD_USB_BMAXPOWER) #define USBD_CFGDESC_BMAXPOWER 0xFA +#else +#define USBD_CFGDESC_BMAXPOWER BOARD_USB_BMAXPOWER +#endif // String Settings // These settings affect String Descriptor diff --git a/source/hic_hal/nxp/lpc4322/usb_config.c b/source/hic_hal/nxp/lpc4322/usb_config.c index f816f800c..9b8dde6c1 100644 --- a/source/hic_hal/nxp/lpc4322/usb_config.c +++ b/source/hic_hal/nxp/lpc4322/usb_config.c @@ -77,7 +77,11 @@ // when the device is fully operational (bMaxPower) // #define USBD_CFGDESC_BMATTRIBUTES 0x80 +#if !defined(BOARD_USB_BMAXPOWER) #define USBD_CFGDESC_BMAXPOWER 0xFA +#else +#define USBD_CFGDESC_BMAXPOWER BOARD_USB_BMAXPOWER +#endif // String Settings // These settings affect String Descriptor diff --git a/source/hic_hal/stm32/stm32f103xb/usb_config.c b/source/hic_hal/stm32/stm32f103xb/usb_config.c index 0e70ae95d..354b57ae0 100644 --- a/source/hic_hal/stm32/stm32f103xb/usb_config.c +++ b/source/hic_hal/stm32/stm32f103xb/usb_config.c @@ -68,7 +68,11 @@ // when the device is fully operational (bMaxPower) // #define USBD_CFGDESC_BMATTRIBUTES 0x80 +#if !defined(BOARD_USB_BMAXPOWER) #define USBD_CFGDESC_BMAXPOWER 0xFA +#else +#define USBD_CFGDESC_BMAXPOWER BOARD_USB_BMAXPOWER +#endif // String Settings // These settings affect String Descriptor diff --git a/source/usb/usb_lib.c b/source/usb/usb_lib.c index cbf06ff96..fef24c524 100644 --- a/source/usb/usb_lib.c +++ b/source/usb/usb_lib.c @@ -1068,6 +1068,8 @@ __WEAK void USBD_Reset_Event(void) #endif #endif /* ((USBD_CDC_ACM_ENABLE)) */ +__WEAK void board_usb_sof_event(void) {} + #if ((USBD_HID_ENABLE) || (USBD_ADC_ENABLE) || (USBD_CDC_ACM_ENABLE) || (USBD_CLS_ENABLE)) #ifndef __RTX __WEAK void USBD_SOF_Event(void) @@ -1084,6 +1086,7 @@ __WEAK void USBD_SOF_Event(void) #if (USBD_CLS_ENABLE) USBD_CLS_SOF_Event(); #endif + board_usb_sof_event(); } #endif #endif /* ((USBD_HID_ENABLE) || (USBD_ADC_ENABLE) || (USBD_CDC_ACM_ENABLE) || (USBD_CLS_ENABLE)) */ diff --git a/tools/generate_config.py b/tools/generate_config.py index e13424192..d36c03844 100755 --- a/tools/generate_config.py +++ b/tools/generate_config.py @@ -23,24 +23,25 @@ CFG_KEY = 0x6b766c64 # Must stay in sync with the structure cfg_setting -# in the header file config_settings.h: +# in the source file settings_rom.c: # 32 - key # 16 - offset_of_end # 8 - auto_rst # 8 - automation_allowed # 8 - overflow_detect +# 8 - detect_incompatible_target # 0 - 'end' member omitted -FORMAT = '