diff --git a/.travis.yml b/.travis.yml index 5dd08769..99852c97 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,7 +48,7 @@ env: # Various protocol combinations - CONFIG_BOARD_VERSION=v3.4-24V CONFIG_USB_PROTOCOL=native-stream CONFIG_UART_PROTOCOL=native - - CONFIG_BOARD_VERSION=v3.4-24V CONFIG_USB_PROTOCOL=stdout CONFIG_UART_PROTOCOL=ascii + - CONFIG_BOARD_VERSION=v3.4-24V CONFIG_USB_PROTOCOL=stdout CONFIG_UART_PROTOCOL=stdout - CONFIG_BOARD_VERSION=v3.4-24V CONFIG_USB_PROTOCOL=none CONFIG_UART_PROTOCOL=none script: diff --git a/ArduinoI2C/ArduinoI2C.ino b/ArduinoI2C/ArduinoI2C.ino new file mode 100644 index 00000000..b443642c --- /dev/null +++ b/ArduinoI2C/ArduinoI2C.ino @@ -0,0 +1,197 @@ + +#include +#include "odrive.h" + + +// See odrive.h for a description +bool I2C_transaction(uint8_t slave_addr, const uint8_t * tx_buffer, size_t tx_length, uint8_t * rx_buffer, size_t rx_length) { + // transmit + if (tx_buffer) { + Wire.beginTransmission(slave_addr); + if (Wire.write(tx_buffer, tx_length) != tx_length) + return false; + bool should_stop = !rx_buffer; + if (Wire.endTransmission(should_stop) != 0) + return false; + } + + // receive + if (rx_buffer) { + while(Wire.available()) Wire.read(); // flush input buffer + if (Wire.requestFrom(slave_addr, (uint8_t)rx_length, (uint8_t)true /* stop after receiving */) != rx_length) + return false; + for (size_t i = 0; i < rx_length; ++i) + rx_buffer[i] = Wire.read(); + } + + return true; +} + + +int set_and_save_configuration(uint8_t odrive_num, uint8_t axis_num) { + bool success; + success = odrive::clear_errors(odrive_num, axis_num); + if (!success) + return __LINE__; + + // select hall effect mode + bool user_config_loaded = false; + success = odrive::read_property(odrive_num, &user_config_loaded); + if (!success) + return __LINE__; + if (user_config_loaded) { + Serial.println("ODrive already configured"); + return 0; + } + + // select hall effect mode + success = odrive::write_axis_property(odrive_num, axis_num, 1); + if (!success) + return __LINE__; + + // configure encoder counts per revolution (6 hall effect states * 12 pole pairs) + success = odrive::write_axis_property(odrive_num, axis_num, 72); + if (!success) + return __LINE__; + + // disable velocity integrator + success = odrive::write_axis_property(odrive_num, axis_num, 0); + if (!success) + return __LINE__; + + // select velocity control + success = odrive::write_axis_property(odrive_num, axis_num, 2); + if (!success) + return __LINE__; + + // set velocity controller P-gain + success = odrive::write_axis_property(odrive_num, axis_num, 0.005f); + if (!success) + return __LINE__; + + // request state: motor calibration + success = odrive::write_axis_property(odrive_num, axis_num, 4); + if (!success) + return __LINE__; + + delay(6000); + + // check if the axis is in idle and no errors occurred + if (!odrive::check_axis_state(odrive_num, axis_num, 1)) + return __LINE__; + + // ensure that the motor calibration is considered valid after power cycle + success = odrive::write_axis_property(odrive_num, axis_num, true); + if (!success) + return __LINE__; + + // request state: encoder calibration + success = odrive::write_axis_property(odrive_num, axis_num, 7); + if (!success) + return __LINE__; + + delay(12000); + + // check if the axis is in idle and no errors occurred + if (!odrive::check_axis_state(odrive_num, axis_num, 1)) + return __LINE__; + + // ensure that the encoder calibration is considered valid after power cycle + success = odrive::write_axis_property(odrive_num, axis_num, true); + if (!success) + return __LINE__; + + // store the configuration to NVM + // Caution: this operation is usually instantaneous but after every couple of hundred calls it will + // take around 1 second (because a flash page needs to be erased). + success = odrive::trigger(odrive_num); + if (!success) + return __LINE__; + return 0; +} + + +byte odrive_num = 7; +byte axis_num = 0; +bool do_setup = true; + +void setup() { + Wire.begin(); // join i2c bus (address optional for master) + Serial.begin(9600); + Serial.println("Hello World!"); + + if (do_setup) { + Serial.println("Starting ODrive setup..."); + int error_line = set_and_save_configuration(odrive_num, axis_num); + if (error_line != 0) { + Serial.print("ODrive setup failed at line "); + Serial.print(error_line); + Serial.println(); + return; + } + Serial.println("ODrive setup succeeded!"); + do_setup = false; + } +} + + +void loop() { + bool success; + delay(500); + + success = odrive::check_axis_state(odrive_num, axis_num, 8); + if (!success) { + Serial.println("not in closed loop control - entering closed loop control"); + + // clear previous error state + success = odrive::clear_errors(odrive_num, axis_num); + if (!success) { + Serial.println("could not enter closed loop control"); + return; + } + + // request velocity 0 + success = odrive::write_axis_property(odrive_num, axis_num, 0); + if (!success) { + Serial.println("could not enter closed loop control"); + return; + } + + // request state: closed loop control + success = odrive::write_axis_property(odrive_num, axis_num, 8); + if (!success) { + Serial.println("could not enter closed loop control"); + return; + } + + success = odrive::check_axis_state(odrive_num, axis_num, 8); + if (!success) { + Serial.println("could not enter closed loop control"); + return; + } + } + + success = odrive::write_axis_property(odrive_num, axis_num, 72 * 5); + if (!success) { + Serial.println("error"); + return; + } + + delay(500); + + success = odrive::write_axis_property(odrive_num, axis_num, -72 * 5); + if (!success) { + Serial.println("error"); + return; + } + + // print Vbus to show liveness + float vbus; + success = odrive::read_property(odrive_num, &vbus); + if (!success) { + Serial.println("error"); + return; + } + Serial.println(vbus); +} + diff --git a/ArduinoI2C/odrive.h b/ArduinoI2C/odrive.h new file mode 100644 index 00000000..bce435f1 --- /dev/null +++ b/ArduinoI2C/odrive.h @@ -0,0 +1,199 @@ +/* +* ODrive I2C communication library +* This file implements I2C communication with the ODrive. +* +* - Implement the C function I2C_transaction to provide low level I2C access. +* - Use read_property() to read properties from the ODrive. +* - Use write_property() to modify properties on the ODrive. +* - Use trigger() to trigger a function (such as reboot or save_configuration) +* - Use endpoint_type_t to retrieve the underlying type +* of a given property. +* - Refer to PropertyId for a list of available properties. +* +* To regenerate the interface definitions, flash an ODrive with +* the new firmware, connect it to your PC via USB and then run +* ../tools/odrivetool generate-code --output [path to odrive_endpoints.h] +* This step can be done with any ODrive, it doesn't have to be the +* one that you'll be controlling over I2C. +*/ + + +#include +#include + +#include "odrive_endpoints.h" + +#ifdef __AVR__ +// AVR-GCC doesn't ship with the STL, so we use our own little excerpt +#include "type_traits.h" +#else +#include +#endif + + +extern "C" { + +/* @brief Send and receive data to/from an I2C slave +* +* This function carries out the following sequence: +* 1. generate a START condition +* 2. if the tx_buffer is not null: +* a. send 7-bit slave address (with the LSB 0) +* b. send all bytes in the tx_buffer +* 3. if both tx_buffer and rx_buffer are not null, generate a REPEATED START condition +* 4. if the rx_buffer is not null: +* a. send 7-bit slave address (with the LSB 1) +* b. read rx_length bytes into rx_buffer +* 5. send STOP condition +* +* @param slave_addr: 7-bit slave address (the MSB is ignored) +* @return true if all data was transmitted and received as requested by the caller, false otherwise +*/ +bool I2C_transaction(uint8_t slave_addr, const uint8_t * tx_buffer, size_t tx_length, uint8_t * rx_buffer, size_t rx_length); + +} + + +namespace odrive { + static constexpr const uint8_t i2c_addr = (0xD << 3); // write: 1101xxx0, read: 1101xxx1 + + template + using bit_width = std::integral_constant; + + template + using byte_width = std::integral_constant::value + 7) / 8>; + + + template + struct unsigned_int_of_size; + + template<> struct unsigned_int_of_size<32> { typedef uint32_t type; }; + + + template + typename std::enable_if::value, T>::type + read_le(const uint8_t buffer[byte_width::value]) { + T value = 0; + for (size_t i = 0; i < byte_width::value; ++i) + value |= (static_cast(buffer[i]) << (i << 3)); + return value; + } + + template + typename std::enable_if::value, T>::type + read_le(const uint8_t buffer[]) { + using T_Int = typename unsigned_int_of_size::value>::type; + T_Int value = read_le(buffer); + return *reinterpret_cast(&value); + } + + template + typename std::enable_if::value, void>::type + write_le(uint8_t buffer[byte_width::value], T value) { + for (size_t i = 0; i < byte_width::value; ++i) + buffer[i] = (value >> (i << 3)) & 0xff; + } + + template + typename std::enable_if::value, T>::type + write_le(uint8_t buffer[byte_width::value], T value) { + using T_Int = typename unsigned_int_of_size::value>::type; + write_le(buffer, *reinterpret_cast(&value)); + } + + /* @brief Read from an endpoint on the ODrive. + * To read from an axis specific endpoint use read_axis_property() instead. + * + * Usage example: + * float val; + * success = odrive::read_property(0, &val); + * + * @param num Selects the ODrive. For instance the value 4 selects + * the ODrive that has [A2, A1, A0] connected to [VCC, GND, GND]. + * @return true if the I2C transaction succeeded, false otherwise + */ + template + bool read_property(uint8_t num, endpoint_type_t* value, uint16_t address = IPropertyId) { + uint8_t i2c_tx_buffer[4]; + write_le(i2c_tx_buffer, address); + write_le(i2c_tx_buffer + sizeof(i2c_tx_buffer) - 2, json_crc); + uint8_t i2c_rx_buffer[byte_width>::value]; + if (!I2C_transaction(i2c_addr + num, + i2c_tx_buffer, sizeof(i2c_tx_buffer), + i2c_rx_buffer, sizeof(i2c_rx_buffer))) + return false; + if (value) + *value = read_le>(i2c_rx_buffer); + return true; + } + + /* @brief Write to an endpoint on the ODrive. + * To write to an axis specific endpoint use write_axis_property() instead. + * + * Usage example: + * success = odrive::write_property(0, 42); + * + * @param num Selects the ODrive. For instance the value 4 selects + * the ODrive that has [A2, A1, A0] connected to [VCC, GND, GND]. + * @return true if the I2C transaction succeeded, false otherwise + */ + template + bool write_property(uint8_t num, endpoint_type_t value, uint16_t address = IPropertyId) { + uint8_t i2c_tx_buffer[4 + byte_width>::value]; + write_le(i2c_tx_buffer, address); + write_le>(i2c_tx_buffer + 2, value); + write_le(i2c_tx_buffer + sizeof(i2c_tx_buffer) - 2, json_crc); + return I2C_transaction(i2c_addr + num, i2c_tx_buffer, sizeof(i2c_tx_buffer), nullptr, 0); + } + + /* @brief Trigger an parameter-less function on the ODrive + * + * Usage example: + * success = odrive::trigger(0); + * + * @param num Selects the ODrive. For instance the value 4 selects + * the ODrive that has [A2, A1, A0] connected to [VCC, GND, GND]. + * @return true if the I2C transaction succeeded, false otherwise + */ + template>::value>::type> + bool trigger(uint8_t num, uint16_t address = IPropertyId) { + uint8_t i2c_tx_buffer[4]; + write_le(i2c_tx_buffer, address); + write_le(i2c_tx_buffer + sizeof(i2c_tx_buffer) - 2, json_crc); + return I2C_transaction(i2c_addr + num, i2c_tx_buffer, sizeof(i2c_tx_buffer), nullptr, 0); + } + + template + bool read_axis_property(uint8_t num, uint8_t axis, endpoint_type_t* value) { + return read_property(num, value, IPropertyId + axis * per_axis_offset); + } + + template + bool write_axis_property(uint8_t num, uint8_t axis, endpoint_type_t value) { + return write_property(num, value, IPropertyId + axis * per_axis_offset); + } + + + /* @brief Checks if the axis is in the requested state and the error register is clear */ + bool check_axis_state(uint8_t num, uint8_t axis, uint8_t state) { + endpoint_type_t observed_state = 0; + endpoint_type_t observed_error = 0; + if (!read_axis_property(num, axis, &observed_state)) + return false; + if (!read_axis_property(num, axis, &observed_error)) + return false; + return (observed_error == 0) && (observed_state == state); + } + + /* @brief Clears any error state of the specified axis */ + bool clear_errors(uint8_t num, uint8_t axis) { + if (!write_axis_property(num, axis, 0)) + return false; + if (!write_axis_property(num, axis, 0)) + return false; + if (!write_axis_property(num, axis, 0)) + return false; + return true; + } +} diff --git a/ArduinoI2C/odrive_endpoints.h b/ArduinoI2C/odrive_endpoints.h new file mode 100644 index 00000000..f82c2b6a --- /dev/null +++ b/ArduinoI2C/odrive_endpoints.h @@ -0,0 +1,299 @@ +/* +* This file was autogenerated using the "odrivetool generate-code" feature. +* +* The file matches a specific firmware version. If you add/remove/rename any +* properties exposed by the ODrive, this file needs to be regenerated, otherwise +* the ODrive will ignore all commands. +*/ + +#ifndef __ODRIVE_ENDPOINTS_HPP +#define __ODRIVE_ENDPOINTS_HPP + + +namespace odrive { + +static constexpr const uint16_t json_crc = 0xbe97; + +static constexpr const uint16_t per_axis_offset = 101; + +enum { + VBUS_VOLTAGE = 1, + SERIAL_NUMBER = 2, + HW_VERSION_MAJOR = 3, + HW_VERSION_MINOR = 4, + HW_VERSION_VARIANT = 5, + FW_VERSION_MAJOR = 6, + FW_VERSION_MINOR = 7, + FW_VERSION_REVISION = 8, + FW_VERSION_UNRELEASED = 9, + USER_CONFIG_LOADED = 10, + BRAKE_RESISTOR_ARMED = 11, + SYSTEM_STATS__UPTIME = 12, + SYSTEM_STATS__MIN_HEAP_SPACE = 13, + SYSTEM_STATS__MIN_STACK_SPACE_AXIS0 = 14, + SYSTEM_STATS__MIN_STACK_SPACE_AXIS1 = 15, + SYSTEM_STATS__MIN_STACK_SPACE_COMMS = 16, + SYSTEM_STATS__MIN_STACK_SPACE_USB = 17, + SYSTEM_STATS__MIN_STACK_SPACE_UART = 18, + SYSTEM_STATS__MIN_STACK_SPACE_USB_IRQ = 19, + SYSTEM_STATS__MIN_STACK_SPACE_STARTUP = 20, + SYSTEM_STATS__USB__RX_CNT = 21, + SYSTEM_STATS__USB__TX_CNT = 22, + SYSTEM_STATS__USB__TX_OVERRUN_CNT = 23, + SYSTEM_STATS__I2C__ADDR = 24, + SYSTEM_STATS__I2C__ADDR_MATCH_CNT = 25, + SYSTEM_STATS__I2C__RX_CNT = 26, + SYSTEM_STATS__I2C__ERROR_CNT = 27, + CONFIG__BRAKE_RESISTANCE = 28, + CONFIG__ENABLE_UART = 29, + CONFIG__ENABLE_I2C_INSTEAD_OF_CAN = 30, + CONFIG__DC_BUS_UNDERVOLTAGE_TRIP_LEVEL = 31, + CONFIG__DC_BUS_OVERVOLTAGE_TRIP_LEVEL = 32, + TEST_PROPERTY = 235, + ADC_GPIO1 = 242, + ADC_GPIO2 = 243, + SAVE_CONFIGURATION = 244, + ERASE_CONFIGURATION = 245, + REBOOT = 246, + ENTER_DFU_MODE = 247, + + // Per-Axis endpoints (to be used with read_axis_property and write_axis_property) + AXIS__ERROR = 33, + AXIS__ENABLE_STEP_DIR = 34, + AXIS__CURRENT_STATE = 35, + AXIS__REQUESTED_STATE = 36, + AXIS__LOOP_COUNTER = 37, + AXIS__CONFIG__STARTUP_MOTOR_CALIBRATION = 38, + AXIS__CONFIG__STARTUP_ENCODER_INDEX_SEARCH = 39, + AXIS__CONFIG__STARTUP_ENCODER_OFFSET_CALIBRATION = 40, + AXIS__CONFIG__STARTUP_CLOSED_LOOP_CONTROL = 41, + AXIS__CONFIG__STARTUP_SENSORLESS_CONTROL = 42, + AXIS__CONFIG__ENABLE_STEP_DIR = 43, + AXIS__CONFIG__COUNTS_PER_STEP = 44, + AXIS__CONFIG__RAMP_UP_TIME = 45, + AXIS__CONFIG__RAMP_UP_DISTANCE = 46, + AXIS__CONFIG__SPIN_UP_CURRENT = 47, + AXIS__CONFIG__SPIN_UP_ACCELERATION = 48, + AXIS__CONFIG__SPIN_UP_TARGET_VEL = 49, + AXIS__MOTOR__ERROR = 50, + AXIS__MOTOR__ARMED_STATE = 51, + AXIS__MOTOR__IS_CALIBRATED = 52, + AXIS__MOTOR__CURRENT_MEAS_PHB = 53, + AXIS__MOTOR__CURRENT_MEAS_PHC = 54, + AXIS__MOTOR__DC_CALIB_PHB = 55, + AXIS__MOTOR__DC_CALIB_PHC = 56, + AXIS__MOTOR__PHASE_CURRENT_REV_GAIN = 57, + AXIS__MOTOR__CURRENT_CONTROL__P_GAIN = 58, + AXIS__MOTOR__CURRENT_CONTROL__I_GAIN = 59, + AXIS__MOTOR__CURRENT_CONTROL__V_CURRENT_CONTROL_INTEGRAL_D = 60, + AXIS__MOTOR__CURRENT_CONTROL__V_CURRENT_CONTROL_INTEGRAL_Q = 61, + AXIS__MOTOR__CURRENT_CONTROL__IBUS = 62, + AXIS__MOTOR__CURRENT_CONTROL__FINAL_V_ALPHA = 63, + AXIS__MOTOR__CURRENT_CONTROL__FINAL_V_BETA = 64, + AXIS__MOTOR__CURRENT_CONTROL__IQ_SETPOINT = 65, + AXIS__MOTOR__CURRENT_CONTROL__IQ_MEASURED = 66, + AXIS__MOTOR__CURRENT_CONTROL__MAX_ALLOWED_CURRENT = 67, + AXIS__MOTOR__GATE_DRIVER__DRV_FAULT = 68, + AXIS__MOTOR__TIMING_LOG__TIMING_LOG_GENERAL = 69, + AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ADC_CB_I = 70, + AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ADC_CB_DC = 71, + AXIS__MOTOR__TIMING_LOG__TIMING_LOG_MEAS_R = 72, + AXIS__MOTOR__TIMING_LOG__TIMING_LOG_MEAS_L = 73, + AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ENC_CALIB = 74, + AXIS__MOTOR__TIMING_LOG__TIMING_LOG_IDX_SEARCH = 75, + AXIS__MOTOR__TIMING_LOG__TIMING_LOG_FOC_VOLTAGE = 76, + AXIS__MOTOR__TIMING_LOG__TIMING_LOG_FOC_CURRENT = 77, + AXIS__MOTOR__CONFIG__PRE_CALIBRATED = 78, + AXIS__MOTOR__CONFIG__POLE_PAIRS = 79, + AXIS__MOTOR__CONFIG__CALIBRATION_CURRENT = 80, + AXIS__MOTOR__CONFIG__RESISTANCE_CALIB_MAX_VOLTAGE = 81, + AXIS__MOTOR__CONFIG__PHASE_INDUCTANCE = 82, + AXIS__MOTOR__CONFIG__PHASE_RESISTANCE = 83, + AXIS__MOTOR__CONFIG__DIRECTION = 84, + AXIS__MOTOR__CONFIG__MOTOR_TYPE = 85, + AXIS__MOTOR__CONFIG__CURRENT_LIM = 86, + AXIS__CONTROLLER__POS_SETPOINT = 87, + AXIS__CONTROLLER__VEL_SETPOINT = 88, + AXIS__CONTROLLER__VEL_INTEGRATOR_CURRENT = 89, + AXIS__CONTROLLER__CURRENT_SETPOINT = 90, + AXIS__CONTROLLER__CONFIG__CONTROL_MODE = 91, + AXIS__CONTROLLER__CONFIG__POS_GAIN = 92, + AXIS__CONTROLLER__CONFIG__VEL_GAIN = 93, + AXIS__CONTROLLER__CONFIG__VEL_INTEGRATOR_GAIN = 94, + AXIS__CONTROLLER__CONFIG__VEL_LIMIT = 95, + AXIS__CONTROLLER__START_ANTICOGGING_CALIBRATION = 105, + AXIS__ENCODER__ERROR = 106, + AXIS__ENCODER__IS_READY = 107, + AXIS__ENCODER__INDEX_FOUND = 108, + AXIS__ENCODER__SHADOW_COUNT = 109, + AXIS__ENCODER__COUNT_IN_CPR = 110, + AXIS__ENCODER__OFFSET = 111, + AXIS__ENCODER__INTERPOLATION = 112, + AXIS__ENCODER__PHASE = 113, + AXIS__ENCODER__POS_ESTIMATE = 114, + AXIS__ENCODER__POS_CPR = 115, + AXIS__ENCODER__HALL_STATE = 116, + AXIS__ENCODER__PLL_VEL = 117, + AXIS__ENCODER__PLL_KP = 118, + AXIS__ENCODER__PLL_KI = 119, + AXIS__ENCODER__CONFIG__MODE = 120, + AXIS__ENCODER__CONFIG__USE_INDEX = 121, + AXIS__ENCODER__CONFIG__PRE_CALIBRATED = 122, + AXIS__ENCODER__CONFIG__IDX_SEARCH_SPEED = 123, + AXIS__ENCODER__CONFIG__CPR = 124, + AXIS__ENCODER__CONFIG__OFFSET = 125, + AXIS__ENCODER__CONFIG__OFFSET_FLOAT = 126, + AXIS__ENCODER__CONFIG__CALIB_RANGE = 127, + AXIS__SENSORLESS_ESTIMATOR__ERROR = 128, + AXIS__SENSORLESS_ESTIMATOR__PHASE = 129, + AXIS__SENSORLESS_ESTIMATOR__PLL_POS = 130, + AXIS__SENSORLESS_ESTIMATOR__PLL_VEL = 131, + AXIS__SENSORLESS_ESTIMATOR__PLL_KP = 132, + AXIS__SENSORLESS_ESTIMATOR__PLL_KI = 133, +}; + +template +struct endpoint_type; + +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef uint64_t type; }; +template<> struct endpoint_type { typedef uint8_t type; }; +template<> struct endpoint_type { typedef uint8_t type; }; +template<> struct endpoint_type { typedef uint8_t type; }; +template<> struct endpoint_type { typedef uint8_t type; }; +template<> struct endpoint_type { typedef uint8_t type; }; +template<> struct endpoint_type { typedef uint8_t type; }; +template<> struct endpoint_type { typedef uint8_t type; }; +template<> struct endpoint_type { typedef bool type; }; +template<> struct endpoint_type { typedef bool type; }; +template<> struct endpoint_type { typedef uint32_t type; }; +template<> struct endpoint_type { typedef uint32_t type; }; +template<> struct endpoint_type { typedef uint32_t type; }; +template<> struct endpoint_type { typedef uint32_t type; }; +template<> struct endpoint_type { typedef uint32_t type; }; +template<> struct endpoint_type { typedef uint32_t type; }; +template<> struct endpoint_type { typedef uint32_t type; }; +template<> struct endpoint_type { typedef uint32_t type; }; +template<> struct endpoint_type { typedef uint32_t type; }; +template<> struct endpoint_type { typedef uint32_t type; }; +template<> struct endpoint_type { typedef uint32_t type; }; +template<> struct endpoint_type { typedef uint32_t type; }; +template<> struct endpoint_type { typedef uint8_t type; }; +template<> struct endpoint_type { typedef uint32_t type; }; +template<> struct endpoint_type { typedef uint32_t type; }; +template<> struct endpoint_type { typedef uint32_t type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef bool type; }; +template<> struct endpoint_type { typedef bool type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef uint32_t type; }; +template<> struct endpoint_type { typedef uint16_t type; }; +template<> struct endpoint_type { typedef uint16_t type; }; +template<> struct endpoint_type { typedef void type; }; +template<> struct endpoint_type { typedef void type; }; +template<> struct endpoint_type { typedef void type; }; +template<> struct endpoint_type { typedef void type; }; + + +// Per-axis endpoints +template<> struct endpoint_type { typedef uint16_t type; }; +template<> struct endpoint_type { typedef bool type; }; +template<> struct endpoint_type { typedef uint8_t type; }; +template<> struct endpoint_type { typedef uint8_t type; }; +template<> struct endpoint_type { typedef uint32_t type; }; +template<> struct endpoint_type { typedef bool type; }; +template<> struct endpoint_type { typedef bool type; }; +template<> struct endpoint_type { typedef bool type; }; +template<> struct endpoint_type { typedef bool type; }; +template<> struct endpoint_type { typedef bool type; }; +template<> struct endpoint_type { typedef bool type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef uint16_t type; }; +template<> struct endpoint_type { typedef uint8_t type; }; +template<> struct endpoint_type { typedef bool type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef uint16_t type; }; +template<> struct endpoint_type { typedef uint16_t type; }; +template<> struct endpoint_type { typedef uint16_t type; }; +template<> struct endpoint_type { typedef uint16_t type; }; +template<> struct endpoint_type { typedef uint16_t type; }; +template<> struct endpoint_type { typedef uint16_t type; }; +template<> struct endpoint_type { typedef uint16_t type; }; +template<> struct endpoint_type { typedef uint16_t type; }; +template<> struct endpoint_type { typedef uint16_t type; }; +template<> struct endpoint_type { typedef uint16_t type; }; +template<> struct endpoint_type { typedef bool type; }; +template<> struct endpoint_type { typedef int32_t type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef int32_t type; }; +template<> struct endpoint_type { typedef uint8_t type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef uint8_t type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef void type; }; +template<> struct endpoint_type { typedef uint8_t type; }; +template<> struct endpoint_type { typedef bool type; }; +template<> struct endpoint_type { typedef bool type; }; +template<> struct endpoint_type { typedef int32_t type; }; +template<> struct endpoint_type { typedef int32_t type; }; +template<> struct endpoint_type { typedef int32_t type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef uint8_t type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef uint8_t type; }; +template<> struct endpoint_type { typedef bool type; }; +template<> struct endpoint_type { typedef bool type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef int32_t type; }; +template<> struct endpoint_type { typedef int32_t type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef uint8_t type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; +template<> struct endpoint_type { typedef float type; }; + + +template +using endpoint_type_t = typename endpoint_type::type; + +} + +#endif // __ODRIVE_ENDPOINTS_HPP \ No newline at end of file diff --git a/ArduinoI2C/type_traits.h b/ArduinoI2C/type_traits.h new file mode 100644 index 00000000..4c4b0367 --- /dev/null +++ b/ArduinoI2C/type_traits.h @@ -0,0 +1,267 @@ +/* +* This file is a very small part of the GCC STL because AVR-GCC ships +* without the STL. +*/ + +namespace std +{ + + /** + * @defgroup metaprogramming Metaprogramming + * @ingroup utilities + * + * Template utilities for compile-time introspection and modification, + * including type classification traits, type property inspection traits + * and type transformation traits. + * + * @{ + */ + + /// integral_constant + template + struct integral_constant + { + static constexpr _Tp value = __v; + typedef _Tp value_type; + typedef integral_constant<_Tp, __v> type; + constexpr operator value_type() const noexcept { return value; } +#if __cplusplus > 201103L + +#define __cpp_lib_integral_constant_callable 201304 + + constexpr value_type operator()() const noexcept { return value; } +#endif + }; + + template + constexpr _Tp integral_constant<_Tp, __v>::value; + + /// The type used as a compile-time boolean with true value. + typedef integral_constant true_type; + + /// The type used as a compile-time boolean with false value. + typedef integral_constant false_type; + + template + using __bool_constant = integral_constant; + +#if __cplusplus > 201402L +# define __cpp_lib_bool_constant 201505 + template + using bool_constant = integral_constant; +#endif + + + // Primary type categories. + + template + struct remove_cv; + + template + struct __is_void_helper + : public false_type { }; + + template<> + struct __is_void_helper + : public true_type { }; + + /// is_void + template + struct is_void + : public __is_void_helper::type>::type + { }; + + template + struct __is_integral_helper + : public false_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + +#ifdef _GLIBCXX_USE_WCHAR_T + template<> + struct __is_integral_helper + : public true_type { }; +#endif + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + // Conditionalizing on __STRICT_ANSI__ here will break any port that + // uses one of these types for size_t. +#if defined(__GLIBCXX_TYPE_INT_N_0) + template<> + struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_0> + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_1) + template<> + struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_1> + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_2) + template<> + struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_2> + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_3) + template<> + struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_3> + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; +#endif + + /// is_integral + template + struct is_integral + : public __is_integral_helper::type>::type + { }; + + template + struct __is_floating_point_helper + : public false_type { }; + + template<> + struct __is_floating_point_helper + : public true_type { }; + + template<> + struct __is_floating_point_helper + : public true_type { }; + + template<> + struct __is_floating_point_helper + : public true_type { }; + +#if !defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_FLOAT128) + template<> + struct __is_floating_point_helper<__float128> + : public true_type { }; +#endif + + /// is_floating_point + template + struct is_floating_point + : public __is_floating_point_helper::type>::type + { }; + + + + + // Const-volatile modifications. + + /// remove_const + template + struct remove_const + { typedef _Tp type; }; + + template + struct remove_const<_Tp const> + { typedef _Tp type; }; + + /// remove_volatile + template + struct remove_volatile + { typedef _Tp type; }; + + template + struct remove_volatile<_Tp volatile> + { typedef _Tp type; }; + + /// remove_cv + template + struct remove_cv + { + typedef typename + remove_const::type>::type type; + }; + + + // Primary template. + /// Define a member typedef @c type only if a boolean constant is true. + template + struct enable_if + { }; + + // Partial specialization for true. + template + struct enable_if + { typedef _Tp type; }; + + + // Type relations. + + /// is_same + template + struct is_same + : public false_type { }; + + template + struct is_same<_Tp, _Tp> + : public true_type { }; +} diff --git a/Firmware/.vscode/c_cpp_properties.json b/Firmware/.vscode/c_cpp_properties.json index 4b0ce3bf..7f70edfe 100644 --- a/Firmware/.vscode/c_cpp_properties.json +++ b/Firmware/.vscode/c_cpp_properties.json @@ -126,7 +126,9 @@ ], "limitSymbolsToIncludedHeaders": true, "databaseFilename": "" - } + }, + "cStandard": "c11", + "cppStandard": "c++17" } ], "version": 4 diff --git a/Firmware/Board/v3/0002-Add-I2C-files-and-settings.patch b/Firmware/Board/v3/0002-Add-I2C-files-and-settings.patch new file mode 100644 index 00000000..aae18bf4 --- /dev/null +++ b/Firmware/Board/v3/0002-Add-I2C-files-and-settings.patch @@ -0,0 +1,6860 @@ +From b45bdbbbfe3d084d069da99b98116991923f5eb6 Mon Sep 17 00:00:00 2001 +From: Samuel Sadok +Date: Thu, 26 Apr 2018 13:20:38 -0700 +Subject: [PATCH] Add I2C files and settings + +--- + .../Inc/stm32f4xx_hal_i2c.h | 649 ++ + .../Inc/stm32f4xx_hal_i2c_ex.h | 137 + + .../Src/stm32f4xx_hal_i2c.c | 5494 +++++++++++++++++ + .../Src/stm32f4xx_hal_i2c_ex.c | 204 + + Firmware/Board/v3/Inc/i2c.h | 91 + + Firmware/Board/v3/Inc/stm32f4xx_hal_conf.h | 2 +- + Firmware/Board/v3/Odrive.ioc | 5 + + Firmware/Board/v3/Src/i2c.c | 198 + + Firmware/Board/v3/Src/main.c | 1 - + 11 files changed, 6811 insertions(+), 2 deletions(-) + create mode 100644 Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c.h + create mode 100644 Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c_ex.h + create mode 100644 Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c + create mode 100644 Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c + create mode 100644 Firmware/Board/v3/Inc/i2c.h + create mode 100644 Firmware/Board/v3/Src/i2c.c + +diff --git a/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c.h b/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c.h +new file mode 100644 +index 0000000..5452a50 +--- /dev/null ++++ b/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c.h +@@ -0,0 +1,649 @@ ++/** ++ ****************************************************************************** ++ * @file stm32f4xx_hal_i2c.h ++ * @author MCD Application Team ++ * @brief Header file of I2C HAL module. ++ ****************************************************************************** ++ * @attention ++ * ++ *

© COPYRIGHT(c) 2017 STMicroelectronics

++ * ++ * Redistribution and use in source and binary forms, with or without modification, ++ * are permitted provided that the following conditions are met: ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions and the following disclaimer. ++ * 2. 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. ++ * 3. Neither the name of STMicroelectronics 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. ++ * ++ ****************************************************************************** ++ */ ++ ++/* Define to prevent recursive inclusion -------------------------------------*/ ++#ifndef __STM32F4xx_HAL_I2C_H ++#define __STM32F4xx_HAL_I2C_H ++ ++#ifdef __cplusplus ++ extern "C" { ++#endif ++ ++/* Includes ------------------------------------------------------------------*/ ++#include "stm32f4xx_hal_def.h" ++ ++/** @addtogroup STM32F4xx_HAL_Driver ++ * @{ ++ */ ++ ++/** @addtogroup I2C ++ * @{ ++ */ ++ ++/* Exported types ------------------------------------------------------------*/ ++/** @defgroup I2C_Exported_Types I2C Exported Types ++ * @{ ++ */ ++ ++/** ++ * @brief I2C Configuration Structure definition ++ */ ++typedef struct ++{ ++ uint32_t ClockSpeed; /*!< Specifies the clock frequency. ++ This parameter must be set to a value lower than 400kHz */ ++ ++ uint32_t DutyCycle; /*!< Specifies the I2C fast mode duty cycle. ++ This parameter can be a value of @ref I2C_duty_cycle_in_fast_mode */ ++ ++ uint32_t OwnAddress1; /*!< Specifies the first device own address. ++ This parameter can be a 7-bit or 10-bit address. */ ++ ++ uint32_t AddressingMode; /*!< Specifies if 7-bit or 10-bit addressing mode is selected. ++ This parameter can be a value of @ref I2C_addressing_mode */ ++ ++ uint32_t DualAddressMode; /*!< Specifies if dual addressing mode is selected. ++ This parameter can be a value of @ref I2C_dual_addressing_mode */ ++ ++ uint32_t OwnAddress2; /*!< Specifies the second device own address if dual addressing mode is selected ++ This parameter can be a 7-bit address. */ ++ ++ uint32_t GeneralCallMode; /*!< Specifies if general call mode is selected. ++ This parameter can be a value of @ref I2C_general_call_addressing_mode */ ++ ++ uint32_t NoStretchMode; /*!< Specifies if nostretch mode is selected. ++ This parameter can be a value of @ref I2C_nostretch_mode */ ++ ++}I2C_InitTypeDef; ++ ++/** ++ * @brief HAL State structure definition ++ * @note HAL I2C State value coding follow below described bitmap : ++ * b7-b6 Error information ++ * 00 : No Error ++ * 01 : Abort (Abort user request on going) ++ * 10 : Timeout ++ * 11 : Error ++ * b5 IP initilisation status ++ * 0 : Reset (IP not initialized) ++ * 1 : Init done (IP initialized and ready to use. HAL I2C Init function called) ++ * b4 (not used) ++ * x : Should be set to 0 ++ * b3 ++ * 0 : Ready or Busy (No Listen mode ongoing) ++ * 1 : Listen (IP in Address Listen Mode) ++ * b2 Intrinsic process state ++ * 0 : Ready ++ * 1 : Busy (IP busy with some configuration or internal operations) ++ * b1 Rx state ++ * 0 : Ready (no Rx operation ongoing) ++ * 1 : Busy (Rx operation ongoing) ++ * b0 Tx state ++ * 0 : Ready (no Tx operation ongoing) ++ * 1 : Busy (Tx operation ongoing) ++ */ ++typedef enum ++{ ++ HAL_I2C_STATE_RESET = 0x00U, /*!< Peripheral is not yet Initialized */ ++ HAL_I2C_STATE_READY = 0x20U, /*!< Peripheral Initialized and ready for use */ ++ HAL_I2C_STATE_BUSY = 0x24U, /*!< An internal process is ongoing */ ++ HAL_I2C_STATE_BUSY_TX = 0x21U, /*!< Data Transmission process is ongoing */ ++ HAL_I2C_STATE_BUSY_RX = 0x22U, /*!< Data Reception process is ongoing */ ++ HAL_I2C_STATE_LISTEN = 0x28U, /*!< Address Listen Mode is ongoing */ ++ HAL_I2C_STATE_BUSY_TX_LISTEN = 0x29U, /*!< Address Listen Mode and Data Transmission ++ process is ongoing */ ++ HAL_I2C_STATE_BUSY_RX_LISTEN = 0x2AU, /*!< Address Listen Mode and Data Reception ++ process is ongoing */ ++ HAL_I2C_STATE_ABORT = 0x60U, /*!< Abort user request ongoing */ ++ HAL_I2C_STATE_TIMEOUT = 0xA0U, /*!< Timeout state */ ++ HAL_I2C_STATE_ERROR = 0xE0U /*!< Error */ ++ ++}HAL_I2C_StateTypeDef; ++ ++/** ++ * @brief HAL Mode structure definition ++ * @note HAL I2C Mode value coding follow below described bitmap : ++ * b7 (not used) ++ * x : Should be set to 0 ++ * b6 ++ * 0 : None ++ * 1 : Memory (HAL I2C communication is in Memory Mode) ++ * b5 ++ * 0 : None ++ * 1 : Slave (HAL I2C communication is in Slave Mode) ++ * b4 ++ * 0 : None ++ * 1 : Master (HAL I2C communication is in Master Mode) ++ * b3-b2-b1-b0 (not used) ++ * xxxx : Should be set to 0000 ++ */ ++typedef enum ++{ ++ HAL_I2C_MODE_NONE = 0x00U, /*!< No I2C communication on going */ ++ HAL_I2C_MODE_MASTER = 0x10U, /*!< I2C communication is in Master Mode */ ++ HAL_I2C_MODE_SLAVE = 0x20U, /*!< I2C communication is in Slave Mode */ ++ HAL_I2C_MODE_MEM = 0x40U /*!< I2C communication is in Memory Mode */ ++ ++}HAL_I2C_ModeTypeDef; ++ ++/** ++ * @brief I2C handle Structure definition ++ */ ++typedef struct ++{ ++ I2C_TypeDef *Instance; /*!< I2C registers base address */ ++ ++ I2C_InitTypeDef Init; /*!< I2C communication parameters */ ++ ++ uint8_t *pBuffPtr; /*!< Pointer to I2C transfer buffer */ ++ ++ uint16_t XferSize; /*!< I2C transfer size */ ++ ++ __IO uint16_t XferCount; /*!< I2C transfer counter */ ++ ++ __IO uint32_t XferOptions; /*!< I2C transfer options */ ++ ++ __IO uint32_t PreviousState; /*!< I2C communication Previous state and mode ++ context for internal usage */ ++ ++ DMA_HandleTypeDef *hdmatx; /*!< I2C Tx DMA handle parameters */ ++ ++ DMA_HandleTypeDef *hdmarx; /*!< I2C Rx DMA handle parameters */ ++ ++ HAL_LockTypeDef Lock; /*!< I2C locking object */ ++ ++ __IO HAL_I2C_StateTypeDef State; /*!< I2C communication state */ ++ ++ __IO HAL_I2C_ModeTypeDef Mode; /*!< I2C communication mode */ ++ ++ __IO uint32_t ErrorCode; /*!< I2C Error code */ ++ ++ __IO uint32_t Devaddress; /*!< I2C Target device address */ ++ ++ __IO uint32_t Memaddress; /*!< I2C Target memory address */ ++ ++ __IO uint32_t MemaddSize; /*!< I2C Target memory address size */ ++ ++ __IO uint32_t EventCount; /*!< I2C Event counter */ ++ ++}I2C_HandleTypeDef; ++ ++/** ++ * @} ++ */ ++ ++/* Exported constants --------------------------------------------------------*/ ++/** @defgroup I2C_Exported_Constants I2C Exported Constants ++ * @{ ++ */ ++ ++/** @defgroup I2C_Error_Code I2C Error Code ++ * @brief I2C Error Code ++ * @{ ++ */ ++#define HAL_I2C_ERROR_NONE 0x00000000U /*!< No error */ ++#define HAL_I2C_ERROR_BERR 0x00000001U /*!< BERR error */ ++#define HAL_I2C_ERROR_ARLO 0x00000002U /*!< ARLO error */ ++#define HAL_I2C_ERROR_AF 0x00000004U /*!< AF error */ ++#define HAL_I2C_ERROR_OVR 0x00000008U /*!< OVR error */ ++#define HAL_I2C_ERROR_DMA 0x00000010U /*!< DMA transfer error */ ++#define HAL_I2C_ERROR_TIMEOUT 0x00000020U /*!< Timeout Error */ ++/** ++ * @} ++ */ ++ ++/** @defgroup I2C_duty_cycle_in_fast_mode I2C duty cycle in fast mode ++ * @{ ++ */ ++#define I2C_DUTYCYCLE_2 0x00000000U ++#define I2C_DUTYCYCLE_16_9 I2C_CCR_DUTY ++/** ++ * @} ++ */ ++ ++/** @defgroup I2C_addressing_mode I2C addressing mode ++ * @{ ++ */ ++#define I2C_ADDRESSINGMODE_7BIT 0x00004000U ++#define I2C_ADDRESSINGMODE_10BIT (I2C_OAR1_ADDMODE | 0x00004000U) ++/** ++ * @} ++ */ ++ ++/** @defgroup I2C_dual_addressing_mode I2C dual addressing mode ++ * @{ ++ */ ++#define I2C_DUALADDRESS_DISABLE 0x00000000U ++#define I2C_DUALADDRESS_ENABLE I2C_OAR2_ENDUAL ++/** ++ * @} ++ */ ++ ++/** @defgroup I2C_general_call_addressing_mode I2C general call addressing mode ++ * @{ ++ */ ++#define I2C_GENERALCALL_DISABLE 0x00000000U ++#define I2C_GENERALCALL_ENABLE I2C_CR1_ENGC ++/** ++ * @} ++ */ ++ ++/** @defgroup I2C_nostretch_mode I2C nostretch mode ++ * @{ ++ */ ++#define I2C_NOSTRETCH_DISABLE 0x00000000U ++#define I2C_NOSTRETCH_ENABLE I2C_CR1_NOSTRETCH ++/** ++ * @} ++ */ ++ ++/** @defgroup I2C_Memory_Address_Size I2C Memory Address Size ++ * @{ ++ */ ++#define I2C_MEMADD_SIZE_8BIT 0x00000001U ++#define I2C_MEMADD_SIZE_16BIT 0x00000010U ++/** ++ * @} ++ */ ++ ++/** @defgroup I2C_XferDirection_definition I2C XferDirection definition ++ * @{ ++ */ ++#define I2C_DIRECTION_RECEIVE 0x00000000U ++#define I2C_DIRECTION_TRANSMIT 0x00000001U ++/** ++ * @} ++ */ ++ ++/** @defgroup I2C_XferOptions_definition I2C XferOptions definition ++ * @{ ++ */ ++#define I2C_FIRST_FRAME 0x00000001U ++#define I2C_NEXT_FRAME 0x00000002U ++#define I2C_FIRST_AND_LAST_FRAME 0x00000004U ++#define I2C_LAST_FRAME 0x00000008U ++/** ++ * @} ++ */ ++ ++/** @defgroup I2C_Interrupt_configuration_definition I2C Interrupt configuration definition ++ * @{ ++ */ ++#define I2C_IT_BUF I2C_CR2_ITBUFEN ++#define I2C_IT_EVT I2C_CR2_ITEVTEN ++#define I2C_IT_ERR I2C_CR2_ITERREN ++/** ++ * @} ++ */ ++ ++/** @defgroup I2C_Flag_definition I2C Flag definition ++ * @{ ++ */ ++#define I2C_FLAG_SMBALERT 0x00018000U ++#define I2C_FLAG_TIMEOUT 0x00014000U ++#define I2C_FLAG_PECERR 0x00011000U ++#define I2C_FLAG_OVR 0x00010800U ++#define I2C_FLAG_AF 0x00010400U ++#define I2C_FLAG_ARLO 0x00010200U ++#define I2C_FLAG_BERR 0x00010100U ++#define I2C_FLAG_TXE 0x00010080U ++#define I2C_FLAG_RXNE 0x00010040U ++#define I2C_FLAG_STOPF 0x00010010U ++#define I2C_FLAG_ADD10 0x00010008U ++#define I2C_FLAG_BTF 0x00010004U ++#define I2C_FLAG_ADDR 0x00010002U ++#define I2C_FLAG_SB 0x00010001U ++#define I2C_FLAG_DUALF 0x00100080U ++#define I2C_FLAG_SMBHOST 0x00100040U ++#define I2C_FLAG_SMBDEFAULT 0x00100020U ++#define I2C_FLAG_GENCALL 0x00100010U ++#define I2C_FLAG_TRA 0x00100004U ++#define I2C_FLAG_BUSY 0x00100002U ++#define I2C_FLAG_MSL 0x00100001U ++/** ++ * @} ++ */ ++ ++/** ++ * @} ++ */ ++ ++/* Exported macro ------------------------------------------------------------*/ ++/** @defgroup I2C_Exported_Macros I2C Exported Macros ++ * @{ ++ */ ++ ++/** @brief Reset I2C handle state ++ * @param __HANDLE__ specifies the I2C Handle. ++ * This parameter can be I2C where x: 1, 2, or 3 to select the I2C peripheral. ++ * @retval None ++ */ ++#define __HAL_I2C_RESET_HANDLE_STATE(__HANDLE__) ((__HANDLE__)->State = HAL_I2C_STATE_RESET) ++ ++/** @brief Enable or disable the specified I2C interrupts. ++ * @param __HANDLE__ specifies the I2C Handle. ++ * This parameter can be I2C where x: 1, 2, or 3 to select the I2C peripheral. ++ * @param __INTERRUPT__ specifies the interrupt source to enable or disable. ++ * This parameter can be one of the following values: ++ * @arg I2C_IT_BUF: Buffer interrupt enable ++ * @arg I2C_IT_EVT: Event interrupt enable ++ * @arg I2C_IT_ERR: Error interrupt enable ++ * @retval None ++ */ ++#define __HAL_I2C_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->CR2 |= (__INTERRUPT__)) ++#define __HAL_I2C_DISABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->CR2 &= (~(__INTERRUPT__))) ++ ++/** @brief Checks if the specified I2C interrupt source is enabled or disabled. ++ * @param __HANDLE__ specifies the I2C Handle. ++ * This parameter can be I2C where x: 1, 2, or 3 to select the I2C peripheral. ++ * @param __INTERRUPT__ specifies the I2C interrupt source to check. ++ * This parameter can be one of the following values: ++ * @arg I2C_IT_BUF: Buffer interrupt enable ++ * @arg I2C_IT_EVT: Event interrupt enable ++ * @arg I2C_IT_ERR: Error interrupt enable ++ * @retval The new state of __INTERRUPT__ (TRUE or FALSE). ++ */ ++#define __HAL_I2C_GET_IT_SOURCE(__HANDLE__, __INTERRUPT__) ((((__HANDLE__)->Instance->CR2 & (__INTERRUPT__)) == (__INTERRUPT__)) ? SET : RESET) ++ ++/** @brief Checks whether the specified I2C flag is set or not. ++ * @param __HANDLE__ specifies the I2C Handle. ++ * This parameter can be I2C where x: 1, 2, or 3 to select the I2C peripheral. ++ * @param __FLAG__ specifies the flag to check. ++ * This parameter can be one of the following values: ++ * @arg I2C_FLAG_SMBALERT: SMBus Alert flag ++ * @arg I2C_FLAG_TIMEOUT: Timeout or Tlow error flag ++ * @arg I2C_FLAG_PECERR: PEC error in reception flag ++ * @arg I2C_FLAG_OVR: Overrun/Underrun flag ++ * @arg I2C_FLAG_AF: Acknowledge failure flag ++ * @arg I2C_FLAG_ARLO: Arbitration lost flag ++ * @arg I2C_FLAG_BERR: Bus error flag ++ * @arg I2C_FLAG_TXE: Data register empty flag ++ * @arg I2C_FLAG_RXNE: Data register not empty flag ++ * @arg I2C_FLAG_STOPF: Stop detection flag ++ * @arg I2C_FLAG_ADD10: 10-bit header sent flag ++ * @arg I2C_FLAG_BTF: Byte transfer finished flag ++ * @arg I2C_FLAG_ADDR: Address sent flag ++ * Address matched flag ++ * @arg I2C_FLAG_SB: Start bit flag ++ * @arg I2C_FLAG_DUALF: Dual flag ++ * @arg I2C_FLAG_SMBHOST: SMBus host header ++ * @arg I2C_FLAG_SMBDEFAULT: SMBus default header ++ * @arg I2C_FLAG_GENCALL: General call header flag ++ * @arg I2C_FLAG_TRA: Transmitter/Receiver flag ++ * @arg I2C_FLAG_BUSY: Bus busy flag ++ * @arg I2C_FLAG_MSL: Master/Slave flag ++ * @retval The new state of __FLAG__ (TRUE or FALSE). ++ */ ++#define __HAL_I2C_GET_FLAG(__HANDLE__, __FLAG__) ((((uint8_t)((__FLAG__) >> 16U)) == 0x01U)?((((__HANDLE__)->Instance->SR1) & ((__FLAG__) & I2C_FLAG_MASK)) == ((__FLAG__) & I2C_FLAG_MASK)): \ ++ ((((__HANDLE__)->Instance->SR2) & ((__FLAG__) & I2C_FLAG_MASK)) == ((__FLAG__) & I2C_FLAG_MASK))) ++ ++/** @brief Clears the I2C pending flags which are cleared by writing 0 in a specific bit. ++ * @param __HANDLE__ specifies the I2C Handle. ++ * This parameter can be I2C where x: 1, 2, or 3 to select the I2C peripheral. ++ * @param __FLAG__ specifies the flag to clear. ++ * This parameter can be any combination of the following values: ++ * @arg I2C_FLAG_SMBALERT: SMBus Alert flag ++ * @arg I2C_FLAG_TIMEOUT: Timeout or Tlow error flag ++ * @arg I2C_FLAG_PECERR: PEC error in reception flag ++ * @arg I2C_FLAG_OVR: Overrun/Underrun flag (Slave mode) ++ * @arg I2C_FLAG_AF: Acknowledge failure flag ++ * @arg I2C_FLAG_ARLO: Arbitration lost flag (Master mode) ++ * @arg I2C_FLAG_BERR: Bus error flag ++ * @retval None ++ */ ++#define __HAL_I2C_CLEAR_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->Instance->SR1 = ~((__FLAG__) & I2C_FLAG_MASK)) ++ ++/** @brief Clears the I2C ADDR pending flag. ++ * @param __HANDLE__ specifies the I2C Handle. ++ * This parameter can be I2C where x: 1, 2, or 3 to select the I2C peripheral. ++ * @retval None ++ */ ++#define __HAL_I2C_CLEAR_ADDRFLAG(__HANDLE__) \ ++ do{ \ ++ __IO uint32_t tmpreg = 0x00U; \ ++ tmpreg = (__HANDLE__)->Instance->SR1; \ ++ tmpreg = (__HANDLE__)->Instance->SR2; \ ++ UNUSED(tmpreg); \ ++ } while(0) ++ ++/** @brief Clears the I2C STOPF pending flag. ++ * @param __HANDLE__ specifies the I2C Handle. ++ * This parameter can be I2C where x: 1, 2, or 3 to select the I2C peripheral. ++ * @retval None ++ */ ++#define __HAL_I2C_CLEAR_STOPFLAG(__HANDLE__) \ ++ do{ \ ++ __IO uint32_t tmpreg = 0x00U; \ ++ tmpreg = (__HANDLE__)->Instance->SR1; \ ++ (__HANDLE__)->Instance->CR1 |= I2C_CR1_PE; \ ++ UNUSED(tmpreg); \ ++ } while(0) ++ ++/** @brief Enable the I2C peripheral. ++ * @param __HANDLE__ specifies the I2C Handle. ++ * This parameter can be I2Cx where x: 1 or 2 to select the I2C peripheral. ++ * @retval None ++ */ ++#define __HAL_I2C_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->CR1 |= I2C_CR1_PE) ++ ++/** @brief Disable the I2C peripheral. ++ * @param __HANDLE__ specifies the I2C Handle. ++ * This parameter can be I2Cx where x: 1 or 2 to select the I2C peripheral. ++ * @retval None ++ */ ++#define __HAL_I2C_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->CR1 &= ~I2C_CR1_PE) ++ ++/** ++ * @} ++ */ ++ ++/* Include I2C HAL Extension module */ ++#include "stm32f4xx_hal_i2c_ex.h" ++ ++/* Exported functions --------------------------------------------------------*/ ++/** @addtogroup I2C_Exported_Functions ++ * @{ ++ */ ++ ++/** @addtogroup I2C_Exported_Functions_Group1 ++ * @{ ++ */ ++/* Initialization/de-initialization functions **********************************/ ++HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c); ++HAL_StatusTypeDef HAL_I2C_DeInit (I2C_HandleTypeDef *hi2c); ++void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c); ++void HAL_I2C_MspDeInit(I2C_HandleTypeDef *hi2c); ++/** ++ * @} ++ */ ++ ++/** @addtogroup I2C_Exported_Functions_Group2 ++ * @{ ++ */ ++/* I/O operation functions *****************************************************/ ++/******* Blocking mode: Polling */ ++HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout); ++HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout); ++HAL_StatusTypeDef HAL_I2C_Slave_Transmit(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout); ++HAL_StatusTypeDef HAL_I2C_Slave_Receive(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout); ++HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout); ++HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout); ++HAL_StatusTypeDef HAL_I2C_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout); ++ ++/******* Non-Blocking mode: Interrupt */ ++HAL_StatusTypeDef HAL_I2C_Master_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); ++HAL_StatusTypeDef HAL_I2C_Master_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); ++HAL_StatusTypeDef HAL_I2C_Slave_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size); ++HAL_StatusTypeDef HAL_I2C_Slave_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size); ++HAL_StatusTypeDef HAL_I2C_Mem_Write_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size); ++HAL_StatusTypeDef HAL_I2C_Mem_Read_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size); ++ ++HAL_StatusTypeDef HAL_I2C_Master_Sequential_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions); ++HAL_StatusTypeDef HAL_I2C_Master_Sequential_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions); ++HAL_StatusTypeDef HAL_I2C_Slave_Sequential_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions); ++HAL_StatusTypeDef HAL_I2C_Slave_Sequential_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions); ++HAL_StatusTypeDef HAL_I2C_Master_Abort_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress); ++HAL_StatusTypeDef HAL_I2C_EnableListen_IT(I2C_HandleTypeDef *hi2c); ++HAL_StatusTypeDef HAL_I2C_DisableListen_IT(I2C_HandleTypeDef *hi2c); ++ ++/******* Non-Blocking mode: DMA */ ++HAL_StatusTypeDef HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); ++HAL_StatusTypeDef HAL_I2C_Master_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); ++HAL_StatusTypeDef HAL_I2C_Slave_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size); ++HAL_StatusTypeDef HAL_I2C_Slave_Receive_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size); ++HAL_StatusTypeDef HAL_I2C_Mem_Write_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size); ++HAL_StatusTypeDef HAL_I2C_Mem_Read_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size); ++ ++/******* I2C IRQHandler and Callbacks used in non blocking modes (Interrupt and DMA) */ ++void HAL_I2C_EV_IRQHandler(I2C_HandleTypeDef *hi2c); ++void HAL_I2C_ER_IRQHandler(I2C_HandleTypeDef *hi2c); ++void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c); ++void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c); ++void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c); ++void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c); ++void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode); ++void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c); ++void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c); ++void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c); ++void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c); ++void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c); ++/** ++ * @} ++ */ ++ ++/** @addtogroup I2C_Exported_Functions_Group3 ++ * @{ ++ */ ++/* Peripheral State, Mode and Errors functions *********************************/ ++HAL_I2C_StateTypeDef HAL_I2C_GetState(I2C_HandleTypeDef *hi2c); ++HAL_I2C_ModeTypeDef HAL_I2C_GetMode(I2C_HandleTypeDef *hi2c); ++uint32_t HAL_I2C_GetError(I2C_HandleTypeDef *hi2c); ++ ++/** ++ * @} ++ */ ++ ++/** ++ * @} ++ */ ++/* Private types -------------------------------------------------------------*/ ++/* Private variables ---------------------------------------------------------*/ ++/* Private constants ---------------------------------------------------------*/ ++/** @defgroup I2C_Private_Constants I2C Private Constants ++ * @{ ++ */ ++#define I2C_FLAG_MASK 0x0000FFFFU ++/** ++ * @} ++ */ ++ ++/* Private macros ------------------------------------------------------------*/ ++/** @defgroup I2C_Private_Macros I2C Private Macros ++ * @{ ++ */ ++ ++#define I2C_FREQRANGE(__PCLK__) ((__PCLK__)/1000000U) ++#define I2C_RISE_TIME(__FREQRANGE__, __SPEED__) (((__SPEED__) <= 100000U) ? ((__FREQRANGE__) + 1U) : ((((__FREQRANGE__) * 300U) / 1000U) + 1U)) ++#define I2C_SPEED_STANDARD(__PCLK__, __SPEED__) (((((__PCLK__)/((__SPEED__) << 1U)) & I2C_CCR_CCR) < 4U)? 4U:((__PCLK__) / ((__SPEED__) << 1U))) ++#define I2C_SPEED_FAST(__PCLK__, __SPEED__, __DUTYCYCLE__) (((__DUTYCYCLE__) == I2C_DUTYCYCLE_2)? ((__PCLK__) / ((__SPEED__) * 3U)) : (((__PCLK__) / ((__SPEED__) * 25U)) | I2C_DUTYCYCLE_16_9)) ++#define I2C_SPEED(__PCLK__, __SPEED__, __DUTYCYCLE__) (((__SPEED__) <= 100000U)? (I2C_SPEED_STANDARD((__PCLK__), (__SPEED__))) : \ ++ ((I2C_SPEED_FAST((__PCLK__), (__SPEED__), (__DUTYCYCLE__)) & I2C_CCR_CCR) == 0U)? 1U : \ ++ ((I2C_SPEED_FAST((__PCLK__), (__SPEED__), (__DUTYCYCLE__))) | I2C_CCR_FS)) ++ ++#define I2C_7BIT_ADD_WRITE(__ADDRESS__) ((uint8_t)((__ADDRESS__) & (~I2C_OAR1_ADD0))) ++#define I2C_7BIT_ADD_READ(__ADDRESS__) ((uint8_t)((__ADDRESS__) | I2C_OAR1_ADD0)) ++ ++#define I2C_10BIT_ADDRESS(__ADDRESS__) ((uint8_t)((uint16_t)((__ADDRESS__) & (uint16_t)0x00FF))) ++#define I2C_10BIT_HEADER_WRITE(__ADDRESS__) ((uint8_t)((uint16_t)((uint16_t)(((uint16_t)((__ADDRESS__) & (uint16_t)0x0300)) >> 7) | (uint16_t)0x00F0))) ++#define I2C_10BIT_HEADER_READ(__ADDRESS__) ((uint8_t)((uint16_t)((uint16_t)(((uint16_t)((__ADDRESS__) & (uint16_t)0x0300)) >> 7) | (uint16_t)(0x00F1)))) ++ ++#define I2C_MEM_ADD_MSB(__ADDRESS__) ((uint8_t)((uint16_t)(((uint16_t)((__ADDRESS__) & (uint16_t)0xFF00)) >> 8))) ++#define I2C_MEM_ADD_LSB(__ADDRESS__) ((uint8_t)((uint16_t)((__ADDRESS__) & (uint16_t)0x00FF))) ++ ++/** @defgroup I2C_IS_RTC_Definitions I2C Private macros to check input parameters ++ * @{ ++ */ ++#define IS_I2C_DUTY_CYCLE(CYCLE) (((CYCLE) == I2C_DUTYCYCLE_2) || \ ++ ((CYCLE) == I2C_DUTYCYCLE_16_9)) ++#define IS_I2C_ADDRESSING_MODE(ADDRESS) (((ADDRESS) == I2C_ADDRESSINGMODE_7BIT) || \ ++ ((ADDRESS) == I2C_ADDRESSINGMODE_10BIT)) ++#define IS_I2C_DUAL_ADDRESS(ADDRESS) (((ADDRESS) == I2C_DUALADDRESS_DISABLE) || \ ++ ((ADDRESS) == I2C_DUALADDRESS_ENABLE)) ++#define IS_I2C_GENERAL_CALL(CALL) (((CALL) == I2C_GENERALCALL_DISABLE) || \ ++ ((CALL) == I2C_GENERALCALL_ENABLE)) ++#define IS_I2C_NO_STRETCH(STRETCH) (((STRETCH) == I2C_NOSTRETCH_DISABLE) || \ ++ ((STRETCH) == I2C_NOSTRETCH_ENABLE)) ++#define IS_I2C_MEMADD_SIZE(SIZE) (((SIZE) == I2C_MEMADD_SIZE_8BIT) || \ ++ ((SIZE) == I2C_MEMADD_SIZE_16BIT)) ++#define IS_I2C_CLOCK_SPEED(SPEED) (((SPEED) > 0U) && ((SPEED) <= 400000U)) ++#define IS_I2C_OWN_ADDRESS1(ADDRESS1) (((ADDRESS1) & 0xFFFFFC00U) == 0U) ++#define IS_I2C_OWN_ADDRESS2(ADDRESS2) (((ADDRESS2) & 0xFFFFFF01U) == 0U) ++#define IS_I2C_TRANSFER_OPTIONS_REQUEST(REQUEST) (((REQUEST) == I2C_FIRST_FRAME) || \ ++ ((REQUEST) == I2C_NEXT_FRAME) || \ ++ ((REQUEST) == I2C_FIRST_AND_LAST_FRAME) || \ ++ ((REQUEST) == I2C_LAST_FRAME)) ++/** ++ * @} ++ */ ++ ++/** ++ * @} ++ */ ++ ++/* Private functions ---------------------------------------------------------*/ ++/** @defgroup I2C_Private_Functions I2C Private Functions ++ * @{ ++ */ ++ ++/** ++ * @} ++ */ ++ ++/** ++ * @} ++ */ ++ ++/** ++ * @} ++ */ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++ ++#endif /* __STM32F4xx_HAL_I2C_H */ ++ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +diff --git a/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c_ex.h b/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c_ex.h +new file mode 100644 +index 0000000..ff47d5c +--- /dev/null ++++ b/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c_ex.h +@@ -0,0 +1,137 @@ ++/** ++ ****************************************************************************** ++ * @file stm32f4xx_hal_i2c_ex.h ++ * @author MCD Application Team ++ * @brief Header file of I2C HAL Extension module. ++ ****************************************************************************** ++ * @attention ++ * ++ *

© COPYRIGHT(c) 2017 STMicroelectronics

++ * ++ * Redistribution and use in source and binary forms, with or without modification, ++ * are permitted provided that the following conditions are met: ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions and the following disclaimer. ++ * 2. 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. ++ * 3. Neither the name of STMicroelectronics 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. ++ * ++ ****************************************************************************** ++ */ ++ ++/* Define to prevent recursive inclusion -------------------------------------*/ ++#ifndef __STM32F4xx_HAL_I2C_EX_H ++#define __STM32F4xx_HAL_I2C_EX_H ++ ++#ifdef __cplusplus ++ extern "C" { ++#endif ++ ++#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) ||\ ++ defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F411xE) || defined(STM32F446xx) ||\ ++ defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F413xx) || defined(STM32F423xx) ++/* Includes ------------------------------------------------------------------*/ ++#include "stm32f4xx_hal_def.h" ++ ++/** @addtogroup STM32F4xx_HAL_Driver ++ * @{ ++ */ ++ ++/** @addtogroup I2CEx ++ * @{ ++ */ ++ ++/* Exported types ------------------------------------------------------------*/ ++/* Exported constants --------------------------------------------------------*/ ++/** @defgroup I2CEx_Exported_Constants I2C Exported Constants ++ * @{ ++ */ ++ ++/** @defgroup I2CEx_Analog_Filter I2C Analog Filter ++ * @{ ++ */ ++#define I2C_ANALOGFILTER_ENABLE 0x00000000U ++#define I2C_ANALOGFILTER_DISABLE I2C_FLTR_ANOFF ++/** ++ * @} ++ */ ++ ++/** ++ * @} ++ */ ++ ++/* Exported macro ------------------------------------------------------------*/ ++/* Exported functions --------------------------------------------------------*/ ++/** @addtogroup I2CEx_Exported_Functions ++ * @{ ++ */ ++ ++/** @addtogroup I2CEx_Exported_Functions_Group1 ++ * @{ ++ */ ++/* Peripheral Control functions ************************************************/ ++HAL_StatusTypeDef HAL_I2CEx_ConfigAnalogFilter(I2C_HandleTypeDef *hi2c, uint32_t AnalogFilter); ++HAL_StatusTypeDef HAL_I2CEx_ConfigDigitalFilter(I2C_HandleTypeDef *hi2c, uint32_t DigitalFilter); ++/** ++ * @} ++ */ ++ ++/** ++ * @} ++ */ ++/* Private types -------------------------------------------------------------*/ ++/* Private variables ---------------------------------------------------------*/ ++/* Private constants ---------------------------------------------------------*/ ++/** @defgroup I2CEx_Private_Constants I2C Private Constants ++ * @{ ++ */ ++ ++/** ++ * @} ++ */ ++ ++/* Private macros ------------------------------------------------------------*/ ++/** @defgroup I2CEx_Private_Macros I2C Private Macros ++ * @{ ++ */ ++#define IS_I2C_ANALOG_FILTER(FILTER) (((FILTER) == I2C_ANALOGFILTER_ENABLE) || \ ++ ((FILTER) == I2C_ANALOGFILTER_DISABLE)) ++#define IS_I2C_DIGITAL_FILTER(FILTER) ((FILTER) <= 0x0000000FU) ++/** ++ * @} ++ */ ++ ++/** ++ * @} ++ */ ++ ++/** ++ * @} ++ */ ++ ++#endif /* STM32F427xx || STM32F429xx || STM32F437xx || STM32F439xx || STM32F401xC ||\ ++ STM32F401xE || STM32F411xE || STM32F446xx || STM32F469xx || STM32F479xx ||\ ++ STM32F413xx || STM32F423xx */ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __STM32F4xx_HAL_I2C_EX_H */ ++ ++ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +diff --git a/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c b/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c +new file mode 100644 +index 0000000..da18520 +--- /dev/null ++++ b/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c +@@ -0,0 +1,5494 @@ ++/** ++ ****************************************************************************** ++ * @file stm32f4xx_hal_i2c.c ++ * @author MCD Application Team ++ * @brief I2C HAL module driver. ++ * This file provides firmware functions to manage the following ++ * functionalities of the Inter Integrated Circuit (I2C) peripheral: ++ * + Initialization and de-initialization functions ++ * + IO operation functions ++ * + Peripheral State, Mode and Error functions ++ * ++ @verbatim ++ ============================================================================== ++ ##### How to use this driver ##### ++ ============================================================================== ++ [..] ++ The I2C HAL driver can be used as follows: ++ ++ (#) Declare a I2C_HandleTypeDef handle structure, for example: ++ I2C_HandleTypeDef hi2c; ++ ++ (#)Initialize the I2C low level resources by implementing the HAL_I2C_MspInit() API: ++ (##) Enable the I2Cx interface clock ++ (##) I2C pins configuration ++ (+++) Enable the clock for the I2C GPIOs ++ (+++) Configure I2C pins as alternate function open-drain ++ (##) NVIC configuration if you need to use interrupt process ++ (+++) Configure the I2Cx interrupt priority ++ (+++) Enable the NVIC I2C IRQ Channel ++ (##) DMA Configuration if you need to use DMA process ++ (+++) Declare a DMA_HandleTypeDef handle structure for the transmit or receive stream ++ (+++) Enable the DMAx interface clock using ++ (+++) Configure the DMA handle parameters ++ (+++) Configure the DMA Tx or Rx Stream ++ (+++) Associate the initialized DMA handle to the hi2c DMA Tx or Rx handle ++ (+++) Configure the priority and enable the NVIC for the transfer complete interrupt on ++ the DMA Tx or Rx Stream ++ ++ (#) Configure the Communication Speed, Duty cycle, Addressing mode, Own Address1, ++ Dual Addressing mode, Own Address2, General call and Nostretch mode in the hi2c Init structure. ++ ++ (#) Initialize the I2C registers by calling the HAL_I2C_Init(), configures also the low level Hardware ++ (GPIO, CLOCK, NVIC...etc) by calling the customized HAL_I2C_MspInit(&hi2c) API. ++ ++ (#) To check if target device is ready for communication, use the function HAL_I2C_IsDeviceReady() ++ ++ (#) For I2C IO and IO MEM operations, three operation modes are available within this driver : ++ ++ *** Polling mode IO operation *** ++ ================================= ++ [..] ++ (+) Transmit in master mode an amount of data in blocking mode using HAL_I2C_Master_Transmit() ++ (+) Receive in master mode an amount of data in blocking mode using HAL_I2C_Master_Receive() ++ (+) Transmit in slave mode an amount of data in blocking mode using HAL_I2C_Slave_Transmit() ++ (+) Receive in slave mode an amount of data in blocking mode using HAL_I2C_Slave_Receive() ++ ++ *** Polling mode IO MEM operation *** ++ ===================================== ++ [..] ++ (+) Write an amount of data in blocking mode to a specific memory address using HAL_I2C_Mem_Write() ++ (+) Read an amount of data in blocking mode from a specific memory address using HAL_I2C_Mem_Read() ++ ++ ++ *** Interrupt mode IO operation *** ++ =================================== ++ [..] ++ (+) Transmit in master mode an amount of data in non blocking mode using HAL_I2C_Master_Transmit_IT() ++ (+) At transmission end of transfer HAL_I2C_MasterTxCpltCallback is executed and user can ++ add his own code by customization of function pointer HAL_I2C_MasterTxCpltCallback ++ (+) Receive in master mode an amount of data in non blocking mode using HAL_I2C_Master_Receive_IT() ++ (+) At reception end of transfer HAL_I2C_MasterRxCpltCallback is executed and user can ++ add his own code by customization of function pointer HAL_I2C_MasterRxCpltCallback ++ (+) Transmit in slave mode an amount of data in non blocking mode using HAL_I2C_Slave_Transmit_IT() ++ (+) At transmission end of transfer HAL_I2C_SlaveTxCpltCallback is executed and user can ++ add his own code by customization of function pointer HAL_I2C_SlaveTxCpltCallback ++ (+) Receive in slave mode an amount of data in non blocking mode using HAL_I2C_Slave_Receive_IT() ++ (+) At reception end of transfer HAL_I2C_SlaveRxCpltCallback is executed and user can ++ add his own code by customization of function pointer HAL_I2C_SlaveRxCpltCallback ++ (+) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and user can ++ add his own code by customization of function pointer HAL_I2C_ErrorCallback ++ (+) Abort a master I2C process communication with Interrupt using HAL_I2C_Master_Abort_IT() ++ (+) End of abort process, HAL_I2C_AbortCpltCallback() is executed and user can ++ add his own code by customization of function pointer HAL_I2C_AbortCpltCallback() ++ ++ *** Interrupt mode IO sequential operation *** ++ ============================================== ++ [..] ++ (@) These interfaces allow to manage a sequential transfer with a repeated start condition ++ when a direction change during transfer ++ [..] ++ (+) A specific option field manage the different steps of a sequential transfer ++ (+) Option field values are defined through @ref I2C_XFEROPTIONS and are listed below: ++ (++) I2C_FIRST_AND_LAST_FRAME: No sequential usage, functionnal is same as associated interfaces in no sequential mode ++ (++) I2C_FIRST_FRAME: Sequential usage, this option allow to manage a sequence with start condition, address ++ and data to transfer without a final stop condition ++ (++) I2C_NEXT_FRAME: Sequential usage, this option allow to manage a sequence with a restart condition, address ++ and with new data to transfer if the direction change or manage only the new data to transfer ++ if no direction change and without a final stop condition in both cases ++ (++) I2C_LAST_FRAME: Sequential usage, this option allow to manage a sequance with a restart condition, address ++ and with new data to transfer if the direction change or manage only the new data to transfer ++ if no direction change and with a final stop condition in both cases ++ ++ (+) Differents sequential I2C interfaces are listed below: ++ (++) Sequential transmit in master I2C mode an amount of data in non-blocking mode using HAL_I2C_Master_Sequential_Transmit_IT() ++ (+++) At transmission end of current frame transfer, HAL_I2C_MasterTxCpltCallback() is executed and user can ++ add his own code by customization of function pointer HAL_I2C_MasterTxCpltCallback() ++ (++) Sequential receive in master I2C mode an amount of data in non-blocking mode using HAL_I2C_Master_Sequential_Receive_IT() ++ (+++) At reception end of current frame transfer, HAL_I2C_MasterRxCpltCallback() is executed and user can ++ add his own code by customization of function pointer HAL_I2C_MasterRxCpltCallback() ++ (++) Abort a master I2C process communication with Interrupt using HAL_I2C_Master_Abort_IT() ++ (+++) End of abort process, HAL_I2C_AbortCpltCallback() is executed and user can ++ add his own code by customization of function pointer HAL_I2C_AbortCpltCallback() ++ (++) Enable/disable the Address listen mode in slave I2C mode using HAL_I2C_EnableListen_IT() HAL_I2C_DisableListen_IT() ++ (+++) When address slave I2C match, HAL_I2C_AddrCallback() is executed and user can ++ add his own code to check the Address Match Code and the transmission direction request by master (Write/Read). ++ (+++) At Listen mode end HAL_I2C_ListenCpltCallback() is executed and user can ++ add his own code by customization of function pointer HAL_I2C_ListenCpltCallback() ++ (++) Sequential transmit in slave I2C mode an amount of data in non-blocking mode using HAL_I2C_Slave_Sequential_Transmit_IT() ++ (+++) At transmission end of current frame transfer, HAL_I2C_SlaveTxCpltCallback() is executed and user can ++ add his own code by customization of function pointer HAL_I2C_SlaveTxCpltCallback() ++ (++) Sequential receive in slave I2C mode an amount of data in non-blocking mode using HAL_I2C_Slave_Sequential_Receive_IT() ++ (+++) At reception end of current frame transfer, HAL_I2C_SlaveRxCpltCallback() is executed and user can ++ add his own code by customization of function pointer HAL_I2C_SlaveRxCpltCallback() ++ (++) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and user can ++ add his own code by customization of function pointer HAL_I2C_ErrorCallback() ++ (++) Abort a master I2C process communication with Interrupt using HAL_I2C_Master_Abort_IT() ++ (++) End of abort process, HAL_I2C_AbortCpltCallback() is executed and user can ++ add his own code by customization of function pointer HAL_I2C_AbortCpltCallback() ++ ++ *** Interrupt mode IO MEM operation *** ++ ======================================= ++ [..] ++ (+) Write an amount of data in no-blocking mode with Interrupt to a specific memory address using ++ HAL_I2C_Mem_Write_IT() ++ (+) At MEM end of write transfer HAL_I2C_MemTxCpltCallback is executed and user can ++ add his own code by customization of function pointer HAL_I2C_MemTxCpltCallback ++ (+) Read an amount of data in no-blocking mode with Interrupt from a specific memory address using ++ HAL_I2C_Mem_Read_IT() ++ (+) At MEM end of read transfer HAL_I2C_MemRxCpltCallback is executed and user can ++ add his own code by customization of function pointer HAL_I2C_MemRxCpltCallback ++ (+) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and user can ++ add his own code by customization of function pointer HAL_I2C_ErrorCallback ++ ++ *** DMA mode IO operation *** ++ ============================== ++ [..] ++ (+) Transmit in master mode an amount of data in non blocking mode (DMA) using ++ HAL_I2C_Master_Transmit_DMA() ++ (+) At transmission end of transfer HAL_I2C_MasterTxCpltCallback is executed and user can ++ add his own code by customization of function pointer HAL_I2C_MasterTxCpltCallback ++ (+) Receive in master mode an amount of data in non blocking mode (DMA) using ++ HAL_I2C_Master_Receive_DMA() ++ (+) At reception end of transfer HAL_I2C_MasterRxCpltCallback is executed and user can ++ add his own code by customization of function pointer HAL_I2C_MasterRxCpltCallback ++ (+) Transmit in slave mode an amount of data in non blocking mode (DMA) using ++ HAL_I2C_Slave_Transmit_DMA() ++ (+) At transmission end of transfer HAL_I2C_SlaveTxCpltCallback is executed and user can ++ add his own code by customization of function pointer HAL_I2C_SlaveTxCpltCallback ++ (+) Receive in slave mode an amount of data in non blocking mode (DMA) using ++ HAL_I2C_Slave_Receive_DMA() ++ (+) At reception end of transfer HAL_I2C_SlaveRxCpltCallback is executed and user can ++ add his own code by customization of function pointer HAL_I2C_SlaveRxCpltCallback ++ (+) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and user can ++ add his own code by customization of function pointer HAL_I2C_ErrorCallback ++ (+) Abort a master I2C process communication with Interrupt using HAL_I2C_Master_Abort_IT() ++ (+) End of abort process, HAL_I2C_AbortCpltCallback() is executed and user can ++ add his own code by customization of function pointer HAL_I2C_AbortCpltCallback() ++ ++ *** DMA mode IO MEM operation *** ++ ================================= ++ [..] ++ (+) Write an amount of data in no-blocking mode with DMA to a specific memory address using ++ HAL_I2C_Mem_Write_DMA() ++ (+) At MEM end of write transfer HAL_I2C_MemTxCpltCallback is executed and user can ++ add his own code by customization of function pointer HAL_I2C_MemTxCpltCallback ++ (+) Read an amount of data in no-blocking mode with DMA from a specific memory address using ++ HAL_I2C_Mem_Read_DMA() ++ (+) At MEM end of read transfer HAL_I2C_MemRxCpltCallback is executed and user can ++ add his own code by customization of function pointer HAL_I2C_MemRxCpltCallback ++ (+) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and user can ++ add his own code by customization of function pointer HAL_I2C_ErrorCallback ++ ++ ++ *** I2C HAL driver macros list *** ++ ================================== ++ [..] ++ Below the list of most used macros in I2C HAL driver. ++ ++ (+) __HAL_I2C_ENABLE: Enable the I2C peripheral ++ (+) __HAL_I2C_DISABLE: Disable the I2C peripheral ++ (+) __HAL_I2C_GET_FLAG : Checks whether the specified I2C flag is set or not ++ (+) __HAL_I2C_CLEAR_FLAG : Clear the specified I2C pending flag ++ (+) __HAL_I2C_ENABLE_IT: Enable the specified I2C interrupt ++ (+) __HAL_I2C_DISABLE_IT: Disable the specified I2C interrupt ++ ++ [..] ++ (@) You can refer to the I2C HAL driver header file for more useful macros ++ ++ ++ @endverbatim ++ ****************************************************************************** ++ * @attention ++ * ++ *

© COPYRIGHT(c) 2017 STMicroelectronics

++ * ++ * Redistribution and use in source and binary forms, with or without modification, ++ * are permitted provided that the following conditions are met: ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions and the following disclaimer. ++ * 2. 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. ++ * 3. Neither the name of STMicroelectronics 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. ++ * ++ ****************************************************************************** ++ */ ++ ++/* Includes ------------------------------------------------------------------*/ ++#include "stm32f4xx_hal.h" ++ ++/** @addtogroup STM32F4xx_HAL_Driver ++ * @{ ++ */ ++ ++/** @defgroup I2C I2C ++ * @brief I2C HAL module driver ++ * @{ ++ */ ++ ++#ifdef HAL_I2C_MODULE_ENABLED ++ ++/* Private typedef -----------------------------------------------------------*/ ++/* Private define ------------------------------------------------------------*/ ++/** @addtogroup I2C_Private_Define ++ * @{ ++ */ ++#define I2C_TIMEOUT_FLAG 35U /*!< Timeout 35 ms */ ++#define I2C_TIMEOUT_BUSY_FLAG 25U /*!< Timeout 25 ms */ ++#define I2C_NO_OPTION_FRAME 0xFFFF0000U /*!< XferOptions default value */ ++ ++/* Private define for @ref PreviousState usage */ ++#define I2C_STATE_MSK ((uint32_t)((HAL_I2C_STATE_BUSY_TX | HAL_I2C_STATE_BUSY_RX) & (~(uint32_t)HAL_I2C_STATE_READY))) /*!< Mask State define, keep only RX and TX bits */ ++#define I2C_STATE_NONE ((uint32_t)(HAL_I2C_MODE_NONE)) /*!< Default Value */ ++#define I2C_STATE_MASTER_BUSY_TX ((uint32_t)((HAL_I2C_STATE_BUSY_TX & I2C_STATE_MSK) | HAL_I2C_MODE_MASTER)) /*!< Master Busy TX, combinaison of State LSB and Mode enum */ ++#define I2C_STATE_MASTER_BUSY_RX ((uint32_t)((HAL_I2C_STATE_BUSY_RX & I2C_STATE_MSK) | HAL_I2C_MODE_MASTER)) /*!< Master Busy RX, combinaison of State LSB and Mode enum */ ++#define I2C_STATE_SLAVE_BUSY_TX ((uint32_t)((HAL_I2C_STATE_BUSY_TX & I2C_STATE_MSK) | HAL_I2C_MODE_SLAVE)) /*!< Slave Busy TX, combinaison of State LSB and Mode enum */ ++#define I2C_STATE_SLAVE_BUSY_RX ((uint32_t)((HAL_I2C_STATE_BUSY_RX & I2C_STATE_MSK) | HAL_I2C_MODE_SLAVE)) /*!< Slave Busy RX, combinaison of State LSB and Mode enum */ ++ ++/** ++ * @} ++ */ ++ ++/* Private macro -------------------------------------------------------------*/ ++/* Private variables ---------------------------------------------------------*/ ++/* Private function prototypes -----------------------------------------------*/ ++/** @addtogroup I2C_Private_Functions ++ * @{ ++ */ ++/* Private functions to handle DMA transfer */ ++static void I2C_DMAXferCplt(DMA_HandleTypeDef *hdma); ++static void I2C_DMAError(DMA_HandleTypeDef *hdma); ++static void I2C_DMAAbort(DMA_HandleTypeDef *hdma); ++ ++static void I2C_ITError(I2C_HandleTypeDef *hi2c); ++ ++static HAL_StatusTypeDef I2C_MasterRequestWrite(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Timeout, uint32_t Tickstart); ++static HAL_StatusTypeDef I2C_MasterRequestRead(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Timeout, uint32_t Tickstart); ++static HAL_StatusTypeDef I2C_RequestMemoryWrite(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout, uint32_t Tickstart); ++static HAL_StatusTypeDef I2C_RequestMemoryRead(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout, uint32_t Tickstart); ++static HAL_StatusTypeDef I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, FlagStatus Status, uint32_t Timeout, uint32_t Tickstart); ++static HAL_StatusTypeDef I2C_WaitOnMasterAddressFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, uint32_t Timeout, uint32_t Tickstart); ++static HAL_StatusTypeDef I2C_WaitOnTXEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart); ++static HAL_StatusTypeDef I2C_WaitOnBTFFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart); ++static HAL_StatusTypeDef I2C_WaitOnRXNEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart); ++static HAL_StatusTypeDef I2C_WaitOnSTOPFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart); ++static HAL_StatusTypeDef I2C_IsAcknowledgeFailed(I2C_HandleTypeDef *hi2c); ++ ++/* Private functions for I2C transfer IRQ handler */ ++static HAL_StatusTypeDef I2C_MasterTransmit_TXE(I2C_HandleTypeDef *hi2c); ++static HAL_StatusTypeDef I2C_MasterTransmit_BTF(I2C_HandleTypeDef *hi2c); ++static HAL_StatusTypeDef I2C_MasterReceive_RXNE(I2C_HandleTypeDef *hi2c); ++static HAL_StatusTypeDef I2C_MasterReceive_BTF(I2C_HandleTypeDef *hi2c); ++static HAL_StatusTypeDef I2C_Master_SB(I2C_HandleTypeDef *hi2c); ++static HAL_StatusTypeDef I2C_Master_ADD10(I2C_HandleTypeDef *hi2c); ++static HAL_StatusTypeDef I2C_Master_ADDR(I2C_HandleTypeDef *hi2c); ++ ++static HAL_StatusTypeDef I2C_SlaveTransmit_TXE(I2C_HandleTypeDef *hi2c); ++static HAL_StatusTypeDef I2C_SlaveTransmit_BTF(I2C_HandleTypeDef *hi2c); ++static HAL_StatusTypeDef I2C_SlaveReceive_RXNE(I2C_HandleTypeDef *hi2c); ++static HAL_StatusTypeDef I2C_SlaveReceive_BTF(I2C_HandleTypeDef *hi2c); ++static HAL_StatusTypeDef I2C_Slave_ADDR(I2C_HandleTypeDef *hi2c); ++static HAL_StatusTypeDef I2C_Slave_STOPF(I2C_HandleTypeDef *hi2c); ++static HAL_StatusTypeDef I2C_Slave_AF(I2C_HandleTypeDef *hi2c); ++/** ++ * @} ++ */ ++ ++/* Exported functions --------------------------------------------------------*/ ++/** @defgroup I2C_Exported_Functions I2C Exported Functions ++ * @{ ++ */ ++ ++/** @defgroup I2C_Exported_Functions_Group1 Initialization and de-initialization functions ++ * @brief Initialization and Configuration functions ++ * ++@verbatim ++ =============================================================================== ++ ##### Initialization and de-initialization functions ##### ++ =============================================================================== ++ [..] This subsection provides a set of functions allowing to initialize and ++ de-initialize the I2Cx peripheral: ++ ++ (+) User must Implement HAL_I2C_MspInit() function in which he configures ++ all related peripherals resources (CLOCK, GPIO, DMA, IT and NVIC). ++ ++ (+) Call the function HAL_I2C_Init() to configure the selected device with ++ the selected configuration: ++ (++) Communication Speed ++ (++) Duty cycle ++ (++) Addressing mode ++ (++) Own Address 1 ++ (++) Dual Addressing mode ++ (++) Own Address 2 ++ (++) General call mode ++ (++) Nostretch mode ++ ++ (+) Call the function HAL_I2C_DeInit() to restore the default configuration ++ of the selected I2Cx peripheral. ++ ++@endverbatim ++ * @{ ++ */ ++ ++/** ++ * @brief Initializes the I2C according to the specified parameters ++ * in the I2C_InitTypeDef and create the associated handle. ++ * @param hi2c pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c) ++{ ++ uint32_t freqrange = 0U; ++ uint32_t pclk1 = 0U; ++ ++ /* Check the I2C handle allocation */ ++ if(hi2c == NULL) ++ { ++ return HAL_ERROR; ++ } ++ ++ /* Check the parameters */ ++ assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance)); ++ assert_param(IS_I2C_CLOCK_SPEED(hi2c->Init.ClockSpeed)); ++ assert_param(IS_I2C_DUTY_CYCLE(hi2c->Init.DutyCycle)); ++ assert_param(IS_I2C_OWN_ADDRESS1(hi2c->Init.OwnAddress1)); ++ assert_param(IS_I2C_ADDRESSING_MODE(hi2c->Init.AddressingMode)); ++ assert_param(IS_I2C_DUAL_ADDRESS(hi2c->Init.DualAddressMode)); ++ assert_param(IS_I2C_OWN_ADDRESS2(hi2c->Init.OwnAddress2)); ++ assert_param(IS_I2C_GENERAL_CALL(hi2c->Init.GeneralCallMode)); ++ assert_param(IS_I2C_NO_STRETCH(hi2c->Init.NoStretchMode)); ++ ++ if(hi2c->State == HAL_I2C_STATE_RESET) ++ { ++ /* Allocate lock resource and initialize it */ ++ hi2c->Lock = HAL_UNLOCKED; ++ /* Init the low level hardware : GPIO, CLOCK, NVIC */ ++ HAL_I2C_MspInit(hi2c); ++ } ++ ++ hi2c->State = HAL_I2C_STATE_BUSY; ++ ++ /* Disable the selected I2C peripheral */ ++ __HAL_I2C_DISABLE(hi2c); ++ ++ /* Get PCLK1 frequency */ ++ pclk1 = HAL_RCC_GetPCLK1Freq(); ++ ++ /* Calculate frequency range */ ++ freqrange = I2C_FREQRANGE(pclk1); ++ ++ /*---------------------------- I2Cx CR2 Configuration ----------------------*/ ++ /* Configure I2Cx: Frequency range */ ++ hi2c->Instance->CR2 = freqrange; ++ ++ /*---------------------------- I2Cx TRISE Configuration --------------------*/ ++ /* Configure I2Cx: Rise Time */ ++ hi2c->Instance->TRISE = I2C_RISE_TIME(freqrange, hi2c->Init.ClockSpeed); ++ ++ /*---------------------------- I2Cx CCR Configuration ----------------------*/ ++ /* Configure I2Cx: Speed */ ++ hi2c->Instance->CCR = I2C_SPEED(pclk1, hi2c->Init.ClockSpeed, hi2c->Init.DutyCycle); ++ ++ /*---------------------------- I2Cx CR1 Configuration ----------------------*/ ++ /* Configure I2Cx: Generalcall and NoStretch mode */ ++ hi2c->Instance->CR1 = (hi2c->Init.GeneralCallMode | hi2c->Init.NoStretchMode); ++ ++ /*---------------------------- I2Cx OAR1 Configuration ---------------------*/ ++ /* Configure I2Cx: Own Address1 and addressing mode */ ++ hi2c->Instance->OAR1 = (hi2c->Init.AddressingMode | hi2c->Init.OwnAddress1); ++ ++ /*---------------------------- I2Cx OAR2 Configuration ---------------------*/ ++ /* Configure I2Cx: Dual mode and Own Address2 */ ++ hi2c->Instance->OAR2 = (hi2c->Init.DualAddressMode | hi2c->Init.OwnAddress2); ++ ++ /* Enable the selected I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ return HAL_OK; ++} ++ ++/** ++ * @brief DeInitializes the I2C peripheral. ++ * @param hi2c pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_DeInit(I2C_HandleTypeDef *hi2c) ++{ ++ /* Check the I2C handle allocation */ ++ if(hi2c == NULL) ++ { ++ return HAL_ERROR; ++ } ++ ++ /* Check the parameters */ ++ assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance)); ++ ++ hi2c->State = HAL_I2C_STATE_BUSY; ++ ++ /* Disable the I2C Peripheral Clock */ ++ __HAL_I2C_DISABLE(hi2c); ++ ++ /* DeInit the low level hardware: GPIO, CLOCK, NVIC */ ++ HAL_I2C_MspDeInit(hi2c); ++ ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ hi2c->State = HAL_I2C_STATE_RESET; ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ /* Release Lock */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_OK; ++} ++ ++/** ++ * @brief I2C MSP Init. ++ * @param hi2c pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval None ++ */ ++ __weak void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c) ++{ ++ /* Prevent unused argument(s) compilation warning */ ++ UNUSED(hi2c); ++ /* NOTE : This function Should not be modified, when the callback is needed, ++ the HAL_I2C_MspInit could be implemented in the user file ++ */ ++} ++ ++/** ++ * @brief I2C MSP DeInit ++ * @param hi2c pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval None ++ */ ++ __weak void HAL_I2C_MspDeInit(I2C_HandleTypeDef *hi2c) ++{ ++ /* Prevent unused argument(s) compilation warning */ ++ UNUSED(hi2c); ++ /* NOTE : This function Should not be modified, when the callback is needed, ++ the HAL_I2C_MspDeInit could be implemented in the user file ++ */ ++} ++ ++/** ++ * @} ++ */ ++ ++/** @defgroup I2C_Exported_Functions_Group2 IO operation functions ++ * @brief Data transfers functions ++ * ++@verbatim ++ =============================================================================== ++ ##### IO operation functions ##### ++ =============================================================================== ++ [..] ++ This subsection provides a set of functions allowing to manage the I2C data ++ transfers. ++ ++ (#) There are two modes of transfer: ++ (++) Blocking mode : The communication is performed in the polling mode. ++ The status of all data processing is returned by the same function ++ after finishing transfer. ++ (++) No-Blocking mode : The communication is performed using Interrupts ++ or DMA. These functions return the status of the transfer startup. ++ The end of the data processing will be indicated through the ++ dedicated I2C IRQ when using Interrupt mode or the DMA IRQ when ++ using DMA mode. ++ ++ (#) Blocking mode functions are : ++ (++) HAL_I2C_Master_Transmit() ++ (++) HAL_I2C_Master_Receive() ++ (++) HAL_I2C_Slave_Transmit() ++ (++) HAL_I2C_Slave_Receive() ++ (++) HAL_I2C_Mem_Write() ++ (++) HAL_I2C_Mem_Read() ++ (++) HAL_I2C_IsDeviceReady() ++ ++ (#) No-Blocking mode functions with Interrupt are : ++ (++) HAL_I2C_Master_Transmit_IT() ++ (++) HAL_I2C_Master_Receive_IT() ++ (++) HAL_I2C_Slave_Transmit_IT() ++ (++) HAL_I2C_Slave_Receive_IT() ++ (++) HAL_I2C_Master_Sequential_Transmit_IT() ++ (++) HAL_I2C_Master_Sequential_Receive_IT() ++ (++) HAL_I2C_Slave_Sequential_Transmit_IT() ++ (++) HAL_I2C_Slave_Sequential_Receive_IT() ++ (++) HAL_I2C_Mem_Write_IT() ++ (++) HAL_I2C_Mem_Read_IT() ++ ++ (#) No-Blocking mode functions with DMA are : ++ (++) HAL_I2C_Master_Transmit_DMA() ++ (++) HAL_I2C_Master_Receive_DMA() ++ (++) HAL_I2C_Slave_Transmit_DMA() ++ (++) HAL_I2C_Slave_Receive_DMA() ++ (++) HAL_I2C_Mem_Write_DMA() ++ (++) HAL_I2C_Mem_Read_DMA() ++ ++ (#) A set of Transfer Complete Callbacks are provided in non Blocking mode: ++ (++) HAL_I2C_MemTxCpltCallback() ++ (++) HAL_I2C_MemRxCpltCallback() ++ (++) HAL_I2C_MasterTxCpltCallback() ++ (++) HAL_I2C_MasterRxCpltCallback() ++ (++) HAL_I2C_SlaveTxCpltCallback() ++ (++) HAL_I2C_SlaveRxCpltCallback() ++ (++) HAL_I2C_ErrorCallback() ++ (++) HAL_I2C_AbortCpltCallback() ++ ++@endverbatim ++ * @{ ++ */ ++ ++/** ++ * @brief Transmits in master mode an amount of data in blocking mode. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param DevAddress Target device address The device 7 bits address value ++ * in datasheet must be shifted to the left before calling the interface ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @param Timeout Timeout duration ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout) ++{ ++ uint32_t tickstart = 0x00U; ++ ++ /* Init tickstart for timeout management*/ ++ tickstart = HAL_GetTick(); ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ /* Wait until BUSY flag is reset */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) ++ { ++ return HAL_BUSY; ++ } ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_TX; ++ hi2c->Mode = HAL_I2C_MODE_MASTER; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->XferSize = hi2c->XferCount; ++ ++ /* Send Slave Address */ ++ if(I2C_MasterRequestWrite(hi2c, DevAddress, Timeout, tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ return HAL_ERROR; ++ } ++ else ++ { ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ while(hi2c->XferSize > 0U) ++ { ++ /* Wait until TXE flag is set */ ++ if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* Write data to DR */ ++ hi2c->Instance->DR = (*hi2c->pBuffPtr++); ++ hi2c->XferCount--; ++ hi2c->XferSize--; ++ ++ if((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) && (hi2c->XferSize != 0U)) ++ { ++ /* Write data to DR */ ++ hi2c->Instance->DR = (*hi2c->pBuffPtr++); ++ hi2c->XferCount--; ++ hi2c->XferSize--; ++ } ++ ++ /* Wait until BTF flag is set */ ++ if(I2C_WaitOnBTFFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ } ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Receives in master mode an amount of data in blocking mode. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param DevAddress Target device address The device 7 bits address value ++ * in datasheet must be shifted to the left before calling the interface ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @param Timeout Timeout duration ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout) ++{ ++ uint32_t tickstart = 0x00U; ++ ++ /* Init tickstart for timeout management*/ ++ tickstart = HAL_GetTick(); ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ /* Wait until BUSY flag is reset */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) ++ { ++ return HAL_BUSY; ++ } ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_RX; ++ hi2c->Mode = HAL_I2C_MODE_MASTER; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->XferSize = hi2c->XferCount; ++ ++ /* Send Slave Address */ ++ if(I2C_MasterRequestRead(hi2c, DevAddress, Timeout, tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ return HAL_ERROR; ++ } ++ else ++ { ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ if(hi2c->XferSize == 0U) ++ { ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ } ++ else if(hi2c->XferSize == 1U) ++ { ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ } ++ else if(hi2c->XferSize == 2U) ++ { ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ /* Enable Pos */ ++ hi2c->Instance->CR1 |= I2C_CR1_POS; ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ } ++ else ++ { ++ /* Enable Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ } ++ ++ while(hi2c->XferSize > 0U) ++ { ++ if(hi2c->XferSize <= 3U) ++ { ++ /* One byte */ ++ if(hi2c->XferSize == 1U) ++ { ++ /* Wait until RXNE flag is set */ ++ if(I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_TIMEOUT) ++ { ++ return HAL_TIMEOUT; ++ } ++ else ++ { ++ return HAL_ERROR; ++ } ++ } ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ } ++ /* Two bytes */ ++ else if(hi2c->XferSize == 2U) ++ { ++ /* Wait until BTF flag is set */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ } ++ /* 3 Last bytes */ ++ else ++ { ++ /* Wait until BTF flag is set */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ ++ /* Wait until BTF flag is set */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ } ++ } ++ else ++ { ++ /* Wait until RXNE flag is set */ ++ if(I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_TIMEOUT) ++ { ++ return HAL_TIMEOUT; ++ } ++ else ++ { ++ return HAL_ERROR; ++ } ++ } ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ ++ if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) ++ { ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ } ++ } ++ } ++ ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Transmits in slave mode an amount of data in blocking mode. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @param Timeout Timeout duration ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Slave_Transmit(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout) ++{ ++ uint32_t tickstart = 0x00U; ++ ++ /* Init tickstart for timeout management*/ ++ tickstart = HAL_GetTick(); ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ if((pData == NULL) || (Size == 0U)) ++ { ++ return HAL_ERROR; ++ } ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_TX; ++ hi2c->Mode = HAL_I2C_MODE_SLAVE; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->XferSize = hi2c->XferCount; ++ ++ /* Enable Address Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Wait until ADDR flag is set */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, RESET, Timeout, tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* If 10bit addressing mode is selected */ ++ if(hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_10BIT) ++ { ++ /* Wait until ADDR flag is set */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, RESET, Timeout, tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ } ++ ++ while(hi2c->XferSize > 0U) ++ { ++ /* Wait until TXE flag is set */ ++ if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) ++ { ++ /* Disable Address Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* Write data to DR */ ++ hi2c->Instance->DR = (*hi2c->pBuffPtr++); ++ hi2c->XferCount--; ++ hi2c->XferSize--; ++ ++ if((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) && (hi2c->XferSize != 0U)) ++ { ++ /* Write data to DR */ ++ hi2c->Instance->DR = (*hi2c->pBuffPtr++); ++ hi2c->XferCount--; ++ hi2c->XferSize--; ++ } ++ } ++ ++ /* Wait until AF flag is set */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_AF, RESET, Timeout, tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ /* Clear AF flag */ ++ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); ++ ++ /* Disable Address Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Receive in slave mode an amount of data in blocking mode ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @param Timeout Timeout duration ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Slave_Receive(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout) ++{ ++ uint32_t tickstart = 0x00U; ++ ++ /* Init tickstart for timeout management*/ ++ tickstart = HAL_GetTick(); ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ if((pData == NULL) || (Size == 0)) ++ { ++ return HAL_ERROR; ++ } ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_RX; ++ hi2c->Mode = HAL_I2C_MODE_SLAVE; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->XferSize = hi2c->XferCount; ++ ++ /* Enable Address Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Wait until ADDR flag is set */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, RESET, Timeout, tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ while(hi2c->XferSize > 0U) ++ { ++ /* Wait until RXNE flag is set */ ++ if(I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) ++ { ++ /* Disable Address Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_TIMEOUT) ++ { ++ return HAL_TIMEOUT; ++ } ++ else ++ { ++ return HAL_ERROR; ++ } ++ } ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ ++ if((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) && (Size != 0U)) ++ { ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ } ++ } ++ ++ /* Wait until STOP flag is set */ ++ if(I2C_WaitOnSTOPFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) ++ { ++ /* Disable Address Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* Clear STOP flag */ ++ __HAL_I2C_CLEAR_STOPFLAG(hi2c); ++ ++ /* Disable Address Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Transmit in master mode an amount of data in non-blocking mode with Interrupt ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param DevAddress Target device address The device 7 bits address value ++ * in datasheet must be shifted to the left before calling the interface ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Master_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size) ++{ ++ __IO uint32_t count = 0U; ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ /* Wait until BUSY flag is reset */ ++ count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); ++ do ++ { ++ if(count-- == 0U) ++ { ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_TX; ++ hi2c->Mode = HAL_I2C_MODE_MASTER; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->XferSize = hi2c->XferCount; ++ hi2c->Devaddress = DevAddress; ++ ++ /* Generate Start */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ /* Enable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Receive in master mode an amount of data in non-blocking mode with Interrupt ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param DevAddress Target device address The device 7 bits address value ++ * in datasheet must be shifted to the left before calling the interface ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Master_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size) ++{ ++ __IO uint32_t count = 0U; ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ /* Wait until BUSY flag is reset */ ++ count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); ++ do ++ { ++ if(count-- == 0U) ++ { ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_RX; ++ hi2c->Mode = HAL_I2C_MODE_MASTER; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->XferSize = hi2c->XferCount; ++ hi2c->Devaddress = DevAddress; ++ ++ /* Enable Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Generate Start */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ ++ /* Enable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Sequential transmit in master mode an amount of data in non-blocking mode with Interrupt ++ * @note This interface allow to manage repeated start condition when a direction change during transfer ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param DevAddress Target device address The device 7 bits address value ++ * in datasheet must be shifted to the left before calling the interface ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @param XferOptions Options of Transfer, value of @ref I2C_XferOptions_definition ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Master_Sequential_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions) ++{ ++ __IO uint32_t Prev_State = 0x00U; ++ __IO uint32_t count = 0x00U; ++ ++ /* Check the parameters */ ++ assert_param(IS_I2C_TRANSFER_OPTIONS_REQUEST(XferOptions)); ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ /* Check Busy Flag only if FIRST call of Master interface */ ++ if((XferOptions == I2C_FIRST_AND_LAST_FRAME) || (XferOptions == I2C_FIRST_FRAME)) ++ { ++ /* Wait until BUSY flag is reset */ ++ count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); ++ do ++ { ++ if(count-- == 0U) ++ { ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); ++ } ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_TX; ++ hi2c->Mode = HAL_I2C_MODE_MASTER; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = XferOptions; ++ hi2c->XferSize = hi2c->XferCount; ++ hi2c->Devaddress = DevAddress; ++ ++ Prev_State = hi2c->PreviousState; ++ ++ /* Generate Start */ ++ if((Prev_State == I2C_STATE_MASTER_BUSY_RX) || (Prev_State == I2C_STATE_NONE)) ++ { ++ /* Generate Start condition if first transfer */ ++ if((XferOptions == I2C_FIRST_AND_LAST_FRAME) || (XferOptions == I2C_FIRST_FRAME)) ++ { ++ /* Generate Start */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ } ++ else ++ { ++ /* Generate ReStart */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ } ++ } ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ ++ /* Enable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Sequential receive in master mode an amount of data in non-blocking mode with Interrupt ++ * @note This interface allow to manage repeated start condition when a direction change during transfer ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param DevAddress Target device address The device 7 bits address value ++ * in datasheet must be shifted to the left before calling the interface ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @param XferOptions Options of Transfer, value of @ref I2C_XferOptions_definition ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Master_Sequential_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions) ++{ ++ __IO uint32_t count = 0U; ++ ++ /* Check the parameters */ ++ assert_param(IS_I2C_TRANSFER_OPTIONS_REQUEST(XferOptions)); ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ /* Check Busy Flag only if FIRST call of Master interface */ ++ if((XferOptions == I2C_FIRST_AND_LAST_FRAME) || (XferOptions == I2C_FIRST_FRAME)) ++ { ++ /* Wait until BUSY flag is reset */ ++ count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); ++ do ++ { ++ if(count-- == 0U) ++ { ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); ++ } ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_RX; ++ hi2c->Mode = HAL_I2C_MODE_MASTER; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = XferOptions; ++ hi2c->XferSize = hi2c->XferCount; ++ hi2c->Devaddress = DevAddress; ++ ++ if((hi2c->PreviousState == I2C_STATE_MASTER_BUSY_TX) || (hi2c->PreviousState == I2C_STATE_NONE)) ++ { ++ /* Generate Start condition if first transfer */ ++ if((XferOptions == I2C_FIRST_AND_LAST_FRAME) || (XferOptions == I2C_FIRST_FRAME) || (XferOptions == I2C_NO_OPTION_FRAME)) ++ { ++ /* Enable Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Generate Start */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ } ++ else if(hi2c->PreviousState == I2C_STATE_MASTER_BUSY_TX) ++ { ++ /* Enable Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Generate ReStart */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ } ++ } ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ ++ /* Enable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Transmit in slave mode an amount of data in non-blocking mode with Interrupt ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Slave_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size) ++{ ++ __IO uint32_t count = 0U; ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ if((pData == NULL) || (Size == 0U)) ++ { ++ return HAL_ERROR; ++ } ++ ++ /* Wait until BUSY flag is reset */ ++ count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); ++ do ++ { ++ if(count-- == 0U) ++ { ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_TX; ++ hi2c->Mode = HAL_I2C_MODE_SLAVE; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->XferSize = hi2c->XferCount; ++ ++ /* Enable Address Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ ++ /* Enable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Receive in slave mode an amount of data in non-blocking mode with Interrupt ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Slave_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size) ++{ ++ __IO uint32_t count = 0U; ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ if((pData == NULL) || (Size == 0U)) ++ { ++ return HAL_ERROR; ++ } ++ ++ /* Wait until BUSY flag is reset */ ++ count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); ++ do ++ { ++ if(count-- == 0U) ++ { ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_RX; ++ hi2c->Mode = HAL_I2C_MODE_SLAVE; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferSize = Size; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ ++ /* Enable Address Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ ++ /* Enable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Sequential transmit in slave mode an amount of data in no-blocking mode with Interrupt ++ * @note This interface allow to manage repeated start condition when a direction change during transfer ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @param XferOptions Options of Transfer, value of @ref I2C_XferOptions_definition ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Slave_Sequential_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions) ++{ ++ /* Check the parameters */ ++ assert_param(IS_I2C_TRANSFER_OPTIONS_REQUEST(XferOptions)); ++ ++ if(hi2c->State == HAL_I2C_STATE_LISTEN) ++ { ++ if((pData == NULL) || (Size == 0U)) ++ { ++ return HAL_ERROR; ++ } ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_TX_LISTEN; ++ hi2c->Mode = HAL_I2C_MODE_SLAVE; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = XferOptions; ++ hi2c->XferSize = hi2c->XferCount; ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ ++ /* Enable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Sequential receive in slave mode an amount of data in non-blocking mode with Interrupt ++ * @note This interface allow to manage repeated start condition when a direction change during transfer ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @param XferOptions Options of Transfer, value of @ref I2C_XferOptions_definition ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Slave_Sequential_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions) ++{ ++ /* Check the parameters */ ++ assert_param(IS_I2C_TRANSFER_OPTIONS_REQUEST(XferOptions)); ++ ++ if(hi2c->State == HAL_I2C_STATE_LISTEN) ++ { ++ if((pData == NULL) || (Size == 0U)) ++ { ++ return HAL_ERROR; ++ } ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_RX_LISTEN; ++ hi2c->Mode = HAL_I2C_MODE_SLAVE; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = XferOptions; ++ hi2c->XferSize = hi2c->XferCount; ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ ++ /* Enable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Enable the Address listen mode with Interrupt. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_EnableListen_IT(I2C_HandleTypeDef *hi2c) ++{ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ hi2c->State = HAL_I2C_STATE_LISTEN; ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Enable Address Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Enable EVT and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Disable the Address listen mode with Interrupt. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_DisableListen_IT(I2C_HandleTypeDef *hi2c) ++{ ++ /* Declaration of tmp to prevent undefined behavior of volatile usage */ ++ uint32_t tmp; ++ ++ /* Disable Address listen mode only if a transfer is not ongoing */ ++ if(hi2c->State == HAL_I2C_STATE_LISTEN) ++ { ++ tmp = (uint32_t)(hi2c->State) & I2C_STATE_MSK; ++ hi2c->PreviousState = tmp | (uint32_t)(hi2c->Mode); ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ /* Disable Address Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ /* Disable EVT and ERR interrupt */ ++ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Transmit in master mode an amount of data in non-blocking mode with DMA ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param DevAddress Target device address The device 7 bits address value ++ * in datasheet must be shifted to the left before calling the interface ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size) ++{ ++ __IO uint32_t count = 0U; ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ /* Wait until BUSY flag is reset */ ++ count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); ++ do ++ { ++ if(count-- == 0U) ++ { ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_TX; ++ hi2c->Mode = HAL_I2C_MODE_MASTER; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->XferSize = hi2c->XferCount; ++ hi2c->Devaddress = DevAddress; ++ ++ if(hi2c->XferSize > 0U) ++ { ++ /* Set the I2C DMA transfer complete callback */ ++ hi2c->hdmatx->XferCpltCallback = I2C_DMAXferCplt; ++ ++ /* Set the DMA error callback */ ++ hi2c->hdmatx->XferErrorCallback = I2C_DMAError; ++ ++ /* Set the unused DMA callbacks to NULL */ ++ hi2c->hdmatx->XferHalfCpltCallback = NULL; ++ hi2c->hdmatx->XferM1CpltCallback = NULL; ++ hi2c->hdmatx->XferM1HalfCpltCallback = NULL; ++ hi2c->hdmatx->XferAbortCallback = NULL; ++ ++ /* Enable the DMA Stream */ ++ HAL_DMA_Start_IT(hi2c->hdmatx, (uint32_t)hi2c->pBuffPtr, (uint32_t)&hi2c->Instance->DR, hi2c->XferSize); ++ ++ /* Enable Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Generate Start */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ ++ /* Enable EVT and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); ++ ++ /* Enable DMA Request */ ++ hi2c->Instance->CR2 |= I2C_CR2_DMAEN; ++ } ++ else ++ { ++ /* Enable Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Generate Start */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ ++ /* Enable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ } ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Receive in master mode an amount of data in non-blocking mode with DMA ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param DevAddress Target device address The device 7 bits address value ++ * in datasheet must be shifted to the left before calling the interface ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Master_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size) ++{ ++ __IO uint32_t count = 0U; ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ /* Wait until BUSY flag is reset */ ++ count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); ++ do ++ { ++ if(count-- == 0U) ++ { ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_RX; ++ hi2c->Mode = HAL_I2C_MODE_MASTER; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->XferSize = hi2c->XferCount; ++ hi2c->Devaddress = DevAddress; ++ ++ if(hi2c->XferSize > 0U) ++ { ++ /* Set the I2C DMA transfer complete callback */ ++ hi2c->hdmarx->XferCpltCallback = I2C_DMAXferCplt; ++ ++ /* Set the DMA error callback */ ++ hi2c->hdmarx->XferErrorCallback = I2C_DMAError; ++ ++ /* Set the unused DMA callbacks to NULL */ ++ hi2c->hdmarx->XferHalfCpltCallback = NULL; ++ hi2c->hdmarx->XferM1CpltCallback = NULL; ++ hi2c->hdmarx->XferM1HalfCpltCallback = NULL; ++ hi2c->hdmarx->XferAbortCallback = NULL; ++ ++ /* Enable the DMA Stream */ ++ HAL_DMA_Start_IT(hi2c->hdmarx, (uint32_t)&hi2c->Instance->DR, (uint32_t)hi2c->pBuffPtr, hi2c->XferSize); ++ ++ /* Enable Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Generate Start */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ ++ /* Enable EVT and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); ++ ++ /* Enable DMA Request */ ++ hi2c->Instance->CR2 |= I2C_CR2_DMAEN; ++ } ++ else ++ { ++ /* Enable Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Generate Start */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ ++ /* Enable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ } ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Abort a master I2C process communication with Interrupt. ++ * @note This abort can be called only if state is ready ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param DevAddress Target device address The device 7 bits address value ++ * in datasheet must be shifted to the left before calling the interface ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Master_Abort_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress) ++{ ++ /* Prevent unused argument(s) compilation warning */ ++ UNUSED(DevAddress); ++ ++ /* Abort Master transfer during Receive or Transmit process */ ++ if(hi2c->Mode == HAL_I2C_MODE_MASTER) ++ { ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State = HAL_I2C_STATE_ABORT; ++ ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ ++ hi2c->XferCount = 0U; ++ ++ /* Disable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Call the corresponding callback to inform upper layer of End of Transfer */ ++ I2C_ITError(hi2c); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ /* Wrong usage of abort function */ ++ /* This function should be used only in case of abort monitored by master device */ ++ return HAL_ERROR; ++ } ++} ++ ++/** ++ * @brief Transmit in slave mode an amount of data in non-blocking mode with DMA ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Slave_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size) ++{ ++ __IO uint32_t count = 0U; ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ if((pData == NULL) || (Size == 0U)) ++ { ++ return HAL_ERROR; ++ } ++ ++ /* Wait until BUSY flag is reset */ ++ count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); ++ do ++ { ++ if(count-- == 0U) ++ { ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_TX; ++ hi2c->Mode = HAL_I2C_MODE_SLAVE; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->XferSize = hi2c->XferCount; ++ ++ /* Set the I2C DMA transfer complete callback */ ++ hi2c->hdmatx->XferCpltCallback = I2C_DMAXferCplt; ++ ++ /* Set the DMA error callback */ ++ hi2c->hdmatx->XferErrorCallback = I2C_DMAError; ++ ++ /* Set the unused DMA callbacks to NULL */ ++ hi2c->hdmatx->XferHalfCpltCallback = NULL; ++ hi2c->hdmatx->XferM1CpltCallback = NULL; ++ hi2c->hdmatx->XferM1HalfCpltCallback = NULL; ++ hi2c->hdmatx->XferAbortCallback = NULL; ++ ++ /* Enable the DMA Stream */ ++ HAL_DMA_Start_IT(hi2c->hdmatx, (uint32_t)hi2c->pBuffPtr, (uint32_t)&hi2c->Instance->DR, hi2c->XferSize); ++ ++ /* Enable Address Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ /* Enable EVT and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); ++ ++ /* Enable DMA Request */ ++ hi2c->Instance->CR2 |= I2C_CR2_DMAEN; ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Receive in slave mode an amount of data in non-blocking mode with DMA ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Slave_Receive_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size) ++{ ++ __IO uint32_t count = 0U; ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ if((pData == NULL) || (Size == 0U)) ++ { ++ return HAL_ERROR; ++ } ++ ++ /* Wait until BUSY flag is reset */ ++ count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); ++ do ++ { ++ if(count-- == 0U) ++ { ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_RX; ++ hi2c->Mode = HAL_I2C_MODE_SLAVE; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->XferSize = hi2c->XferCount; ++ ++ /* Set the I2C DMA transfer complete callback */ ++ hi2c->hdmarx->XferCpltCallback = I2C_DMAXferCplt; ++ ++ /* Set the DMA error callback */ ++ hi2c->hdmarx->XferErrorCallback = I2C_DMAError; ++ ++ /* Set the unused DMA callbacks to NULL */ ++ hi2c->hdmarx->XferHalfCpltCallback = NULL; ++ hi2c->hdmarx->XferM1CpltCallback = NULL; ++ hi2c->hdmarx->XferM1HalfCpltCallback = NULL; ++ hi2c->hdmarx->XferAbortCallback = NULL; ++ ++ /* Enable the DMA Stream */ ++ HAL_DMA_Start_IT(hi2c->hdmarx, (uint32_t)&hi2c->Instance->DR, (uint32_t)hi2c->pBuffPtr, hi2c->XferSize); ++ ++ /* Enable Address Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ /* Enable EVT and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); ++ ++ /* Enable DMA Request */ ++ hi2c->Instance->CR2 |= I2C_CR2_DMAEN; ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++/** ++ * @brief Write an amount of data in blocking mode to a specific memory address ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param DevAddress Target device address ++ * @param MemAddress Internal memory address ++ * @param MemAddSize Size of internal memory address ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @param Timeout Timeout duration ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout) ++{ ++ uint32_t tickstart = 0x00U; ++ ++ /* Init tickstart for timeout management*/ ++ tickstart = HAL_GetTick(); ++ ++ /* Check the parameters */ ++ assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ /* Wait until BUSY flag is reset */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) ++ { ++ return HAL_BUSY; ++ } ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_TX; ++ hi2c->Mode = HAL_I2C_MODE_MEM; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->XferSize = hi2c->XferCount; ++ ++ /* Send Slave Address and Memory Address */ ++ if(I2C_RequestMemoryWrite(hi2c, DevAddress, MemAddress, MemAddSize, Timeout, tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ return HAL_ERROR; ++ } ++ else ++ { ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ while(hi2c->XferSize > 0U) ++ { ++ /* Wait until TXE flag is set */ ++ if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* Write data to DR */ ++ hi2c->Instance->DR = (*hi2c->pBuffPtr++); ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ ++ if((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) && (hi2c->XferSize != 0U)) ++ { ++ /* Write data to DR */ ++ hi2c->Instance->DR = (*hi2c->pBuffPtr++); ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ } ++ } ++ ++ /* Wait until BTF flag is set */ ++ if(I2C_WaitOnBTFFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Read an amount of data in blocking mode from a specific memory address ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param DevAddress Target device address ++ * @param MemAddress Internal memory address ++ * @param MemAddSize Size of internal memory address ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @param Timeout Timeout duration ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout) ++{ ++ uint32_t tickstart = 0x00U; ++ ++ /* Init tickstart for timeout management*/ ++ tickstart = HAL_GetTick(); ++ ++ /* Check the parameters */ ++ assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ /* Wait until BUSY flag is reset */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) ++ { ++ return HAL_BUSY; ++ } ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_RX; ++ hi2c->Mode = HAL_I2C_MODE_MEM; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->XferSize = hi2c->XferCount; ++ ++ /* Send Slave Address and Memory Address */ ++ if(I2C_RequestMemoryRead(hi2c, DevAddress, MemAddress, MemAddSize, Timeout, tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ return HAL_ERROR; ++ } ++ else ++ { ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ if(hi2c->XferSize == 0U) ++ { ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ } ++ else if(hi2c->XferSize == 1U) ++ { ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ } ++ else if(hi2c->XferSize == 2U) ++ { ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ /* Enable Pos */ ++ hi2c->Instance->CR1 |= I2C_CR1_POS; ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ } ++ else ++ { ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ } ++ ++ while(hi2c->XferSize > 0U) ++ { ++ if(hi2c->XferSize <= 3U) ++ { ++ /* One byte */ ++ if(hi2c->XferSize== 1U) ++ { ++ /* Wait until RXNE flag is set */ ++ if(I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_TIMEOUT) ++ { ++ return HAL_TIMEOUT; ++ } ++ else ++ { ++ return HAL_ERROR; ++ } ++ } ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ } ++ /* Two bytes */ ++ else if(hi2c->XferSize == 2U) ++ { ++ /* Wait until BTF flag is set */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ } ++ /* 3 Last bytes */ ++ else ++ { ++ /* Wait until BTF flag is set */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ ++ /* Wait until BTF flag is set */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ } ++ } ++ else ++ { ++ /* Wait until RXNE flag is set */ ++ if(I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_TIMEOUT) ++ { ++ return HAL_TIMEOUT; ++ } ++ else ++ { ++ return HAL_ERROR; ++ } ++ } ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ ++ if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) ++ { ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferSize--; ++ hi2c->XferCount--; ++ } ++ } ++ } ++ ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Write an amount of data in non-blocking mode with Interrupt to a specific memory address ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param DevAddress Target device address ++ * @param MemAddress Internal memory address ++ * @param MemAddSize Size of internal memory address ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Mem_Write_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size) ++{ ++ __IO uint32_t count = 0U; ++ ++ /* Check the parameters */ ++ assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ /* Wait until BUSY flag is reset */ ++ count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); ++ do ++ { ++ if(count-- == 0U) ++ { ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_TX; ++ hi2c->Mode = HAL_I2C_MODE_MEM; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferSize = Size; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->Devaddress = DevAddress; ++ hi2c->Memaddress = MemAddress; ++ hi2c->MemaddSize = MemAddSize; ++ hi2c->EventCount = 0U; ++ ++ /* Generate Start */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ ++ /* Enable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Read an amount of data in non-blocking mode with Interrupt from a specific memory address ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param DevAddress Target device address ++ * @param MemAddress Internal memory address ++ * @param MemAddSize Size of internal memory address ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Mem_Read_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size) ++{ ++ __IO uint32_t count = 0U; ++ ++ /* Check the parameters */ ++ assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ /* Wait until BUSY flag is reset */ ++ count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); ++ do ++ { ++ if(count-- == 0U) ++ { ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_RX; ++ hi2c->Mode = HAL_I2C_MODE_MEM; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferSize = Size; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->Devaddress = DevAddress; ++ hi2c->Memaddress = MemAddress; ++ hi2c->MemaddSize = MemAddSize; ++ hi2c->EventCount = 0U; ++ ++ /* Enable Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Generate Start */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ if(hi2c->XferSize > 0U) ++ { ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ ++ /* Enable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ } ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Write an amount of data in non-blocking mode with DMA to a specific memory address ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param DevAddress Target device address ++ * @param MemAddress Internal memory address ++ * @param MemAddSize Size of internal memory address ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be sent ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Mem_Write_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size) ++{ ++ __IO uint32_t count = 0U; ++ ++ uint32_t tickstart = 0x00U; ++ ++ /* Init tickstart for timeout management*/ ++ tickstart = HAL_GetTick(); ++ ++ /* Check the parameters */ ++ assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ /* Wait until BUSY flag is reset */ ++ count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); ++ do ++ { ++ if(count-- == 0U) ++ { ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_TX; ++ hi2c->Mode = HAL_I2C_MODE_MEM; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferSize = Size; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ ++ if(hi2c->XferSize > 0U) ++ { ++ /* Set the I2C DMA transfer complete callback */ ++ hi2c->hdmatx->XferCpltCallback = I2C_DMAXferCplt; ++ ++ /* Set the DMA error callback */ ++ hi2c->hdmatx->XferErrorCallback = I2C_DMAError; ++ ++ /* Set the unused DMA callbacks to NULL */ ++ hi2c->hdmatx->XferHalfCpltCallback = NULL; ++ hi2c->hdmatx->XferM1CpltCallback = NULL; ++ hi2c->hdmatx->XferM1HalfCpltCallback = NULL; ++ hi2c->hdmatx->XferAbortCallback = NULL; ++ ++ /* Enable the DMA Stream */ ++ HAL_DMA_Start_IT(hi2c->hdmatx, (uint32_t)hi2c->pBuffPtr, (uint32_t)&hi2c->Instance->DR, hi2c->XferSize); ++ ++ /* Send Slave Address and Memory Address */ ++ if(I2C_RequestMemoryWrite(hi2c, DevAddress, MemAddress, MemAddSize, I2C_TIMEOUT_FLAG, tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ return HAL_ERROR; ++ } ++ else ++ { ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ /* Enable ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_ERR); ++ ++ /* Enable DMA Request */ ++ hi2c->Instance->CR2 |= I2C_CR2_DMAEN; ++ } ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Reads an amount of data in non-blocking mode with DMA from a specific memory address. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param DevAddress Target device address ++ * @param MemAddress Internal memory address ++ * @param MemAddSize Size of internal memory address ++ * @param pData Pointer to data buffer ++ * @param Size Amount of data to be read ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_Mem_Read_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size) ++{ ++ uint32_t tickstart = 0x00U; ++ __IO uint32_t count = 0U; ++ ++ /* Init tickstart for timeout management*/ ++ tickstart = HAL_GetTick(); ++ ++ /* Check the parameters */ ++ assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ /* Wait until BUSY flag is reset */ ++ count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); ++ do ++ { ++ if(count-- == 0U) ++ { ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY_RX; ++ hi2c->Mode = HAL_I2C_MODE_MEM; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Prepare transfer parameters */ ++ hi2c->pBuffPtr = pData; ++ hi2c->XferCount = Size; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->XferSize = hi2c->XferCount; ++ ++ if(hi2c->XferSize > 0U) ++ { ++ /* Set the I2C DMA transfer complete callback */ ++ hi2c->hdmarx->XferCpltCallback = I2C_DMAXferCplt; ++ ++ /* Set the DMA error callback */ ++ hi2c->hdmarx->XferErrorCallback = I2C_DMAError; ++ ++ /* Set the unused DMA callbacks to NULL */ ++ hi2c->hdmarx->XferHalfCpltCallback = NULL; ++ hi2c->hdmarx->XferM1CpltCallback = NULL; ++ hi2c->hdmarx->XferM1HalfCpltCallback = NULL; ++ hi2c->hdmarx->XferAbortCallback = NULL; ++ ++ /* Enable the DMA Stream */ ++ HAL_DMA_Start_IT(hi2c->hdmarx, (uint32_t)&hi2c->Instance->DR, (uint32_t)hi2c->pBuffPtr, hi2c->XferSize); ++ ++ /* Send Slave Address and Memory Address */ ++ if(I2C_RequestMemoryRead(hi2c, DevAddress, MemAddress, MemAddSize, I2C_TIMEOUT_FLAG, tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ return HAL_ERROR; ++ } ++ else ++ { ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ if(Size == 1U) ++ { ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ } ++ else ++ { ++ /* Enable Last DMA bit */ ++ hi2c->Instance->CR2 |= I2C_CR2_LAST; ++ } ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ /* Note : The I2C interrupts must be enabled after unlocking current process ++ to avoid the risk of I2C interrupt handle execution before current ++ process unlock */ ++ /* Enable ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_ERR); ++ ++ /* Enable DMA Request */ ++ hi2c->Instance->CR2 |= I2C_CR2_DMAEN; ++ } ++ else ++ { ++ /* Send Slave Address and Memory Address */ ++ if(I2C_RequestMemoryRead(hi2c, DevAddress, MemAddress, MemAddSize, I2C_TIMEOUT_FLAG, tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ return HAL_ERROR; ++ } ++ else ++ { ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ ++ hi2c->State = HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ } ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Checks if target device is ready for communication. ++ * @note This function is used with Memory devices ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param DevAddress Target device address ++ * @param Trials Number of trials ++ * @param Timeout Timeout duration ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2C_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout) ++{ ++ uint32_t tickstart = 0U, tmp1 = 0U, tmp2 = 0U, tmp3 = 0U, I2C_Trials = 1U; ++ ++ /* Get tick */ ++ tickstart = HAL_GetTick(); ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ /* Wait until BUSY flag is reset */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) ++ { ++ return HAL_BUSY; ++ } ++ ++ /* Process Locked */ ++ __HAL_LOCK(hi2c); ++ ++ /* Check if the I2C is already enabled */ ++ if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) ++ { ++ /* Enable I2C peripheral */ ++ __HAL_I2C_ENABLE(hi2c); ++ } ++ ++ /* Disable Pos */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ hi2c->State = HAL_I2C_STATE_BUSY; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ ++ do ++ { ++ /* Generate Start */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ ++ /* Wait until SB flag is set */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ /* Send slave address */ ++ hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(DevAddress); ++ ++ /* Wait until ADDR or AF flag are set */ ++ /* Get tick */ ++ tickstart = HAL_GetTick(); ++ ++ tmp1 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR); ++ tmp2 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF); ++ tmp3 = hi2c->State; ++ while((tmp1 == RESET) && (tmp2 == RESET) && (tmp3 != HAL_I2C_STATE_TIMEOUT)) ++ { ++ if((Timeout == 0U)||((HAL_GetTick() - tickstart ) > Timeout)) ++ { ++ hi2c->State = HAL_I2C_STATE_TIMEOUT; ++ } ++ tmp1 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR); ++ tmp2 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF); ++ tmp3 = hi2c->State; ++ } ++ ++ hi2c->State = HAL_I2C_STATE_READY; ++ ++ /* Check if the ADDR flag has been set */ ++ if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR) == SET) ++ { ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ ++ /* Clear ADDR Flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* Wait until BUSY flag is reset */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ hi2c->State = HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_OK; ++ } ++ else ++ { ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ ++ /* Clear AF Flag */ ++ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); ++ ++ /* Wait until BUSY flag is reset */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ }while(I2C_Trials++ < Trials); ++ ++ hi2c->State = HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief This function handles I2C event interrupt request. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @retval None ++ */ ++void HAL_I2C_EV_IRQHandler(I2C_HandleTypeDef *hi2c) ++{ ++ uint32_t sr2itflags = READ_REG(hi2c->Instance->SR2); ++ uint32_t sr1itflags = READ_REG(hi2c->Instance->SR1); ++ uint32_t itsources = READ_REG(hi2c->Instance->CR2); ++ ++ uint32_t CurrentMode = hi2c->Mode; ++ ++ /* Master or Memory mode selected */ ++ if((CurrentMode == HAL_I2C_MODE_MASTER) || (CurrentMode == HAL_I2C_MODE_MEM)) ++ { ++ /* SB Set ----------------------------------------------------------------*/ ++ if(((sr1itflags & I2C_FLAG_SB) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) ++ { ++ I2C_Master_SB(hi2c); ++ } ++ /* ADD10 Set -------------------------------------------------------------*/ ++ else if(((sr1itflags & I2C_FLAG_ADD10) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) ++ { ++ I2C_Master_ADD10(hi2c); ++ } ++ /* ADDR Set --------------------------------------------------------------*/ ++ else if(((sr1itflags & I2C_FLAG_ADDR) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) ++ { ++ I2C_Master_ADDR(hi2c); ++ } ++ ++ /* I2C in mode Transmitter -----------------------------------------------*/ ++ if((sr2itflags & I2C_FLAG_TRA) != RESET) ++ { ++ /* TXE set and BTF reset -----------------------------------------------*/ ++ if(((sr1itflags & I2C_FLAG_TXE) != RESET) && ((itsources & I2C_IT_BUF) != RESET) && ((sr1itflags & I2C_FLAG_BTF) == RESET)) ++ { ++ I2C_MasterTransmit_TXE(hi2c); ++ } ++ /* BTF set -------------------------------------------------------------*/ ++ else if(((sr1itflags & I2C_FLAG_BTF) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) ++ { ++ I2C_MasterTransmit_BTF(hi2c); ++ } ++ } ++ /* I2C in mode Receiver --------------------------------------------------*/ ++ else ++ { ++ /* RXNE set and BTF reset -----------------------------------------------*/ ++ if(((sr1itflags & I2C_FLAG_RXNE) != RESET) && ((itsources & I2C_IT_BUF) != RESET) && ((sr1itflags & I2C_FLAG_BTF) == RESET)) ++ { ++ I2C_MasterReceive_RXNE(hi2c); ++ } ++ /* BTF set -------------------------------------------------------------*/ ++ else if(((sr1itflags & I2C_FLAG_BTF) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) ++ { ++ I2C_MasterReceive_BTF(hi2c); ++ } ++ } ++ } ++ /* Slave mode selected */ ++ else ++ { ++ /* ADDR set --------------------------------------------------------------*/ ++ if(((sr1itflags & I2C_FLAG_ADDR) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) ++ { ++ I2C_Slave_ADDR(hi2c); ++ } ++ /* STOPF set --------------------------------------------------------------*/ ++ else if(((sr1itflags & I2C_FLAG_STOPF) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) ++ { ++ I2C_Slave_STOPF(hi2c); ++ } ++ /* I2C in mode Transmitter -----------------------------------------------*/ ++ else if((sr2itflags & I2C_FLAG_TRA) != RESET) ++ { ++ /* TXE set and BTF reset -----------------------------------------------*/ ++ if(((sr1itflags & I2C_FLAG_TXE) != RESET) && ((itsources & I2C_IT_BUF) != RESET) && ((sr1itflags & I2C_FLAG_BTF) == RESET)) ++ { ++ I2C_SlaveTransmit_TXE(hi2c); ++ } ++ /* BTF set -------------------------------------------------------------*/ ++ else if(((sr1itflags & I2C_FLAG_BTF) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) ++ { ++ I2C_SlaveTransmit_BTF(hi2c); ++ } ++ } ++ /* I2C in mode Receiver --------------------------------------------------*/ ++ else ++ { ++ /* RXNE set and BTF reset ----------------------------------------------*/ ++ if(((sr1itflags & I2C_FLAG_RXNE) != RESET) && ((itsources & I2C_IT_BUF) != RESET) && ((sr1itflags & I2C_FLAG_BTF) == RESET)) ++ { ++ I2C_SlaveReceive_RXNE(hi2c); ++ } ++ /* BTF set -------------------------------------------------------------*/ ++ else if(((sr1itflags & I2C_FLAG_BTF) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) ++ { ++ I2C_SlaveReceive_BTF(hi2c); ++ } ++ } ++ } ++} ++ ++/** ++ * @brief This function handles I2C error interrupt request. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @retval None ++ */ ++void HAL_I2C_ER_IRQHandler(I2C_HandleTypeDef *hi2c) ++{ ++ uint32_t tmp1 = 0U, tmp2 = 0U, tmp3 = 0U, tmp4 = 0U; ++ uint32_t sr1itflags = READ_REG(hi2c->Instance->SR1); ++ uint32_t itsources = READ_REG(hi2c->Instance->CR2); ++ ++ /* I2C Bus error interrupt occurred ----------------------------------------*/ ++ if(((sr1itflags & I2C_FLAG_BERR) != RESET) && ((itsources & I2C_IT_ERR) != RESET)) ++ { ++ hi2c->ErrorCode |= HAL_I2C_ERROR_BERR; ++ ++ /* Clear BERR flag */ ++ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_BERR); ++ } ++ ++ /* I2C Arbitration Loss error interrupt occurred ---------------------------*/ ++ if(((sr1itflags & I2C_FLAG_ARLO) != RESET) && ((itsources & I2C_IT_ERR) != RESET)) ++ { ++ hi2c->ErrorCode |= HAL_I2C_ERROR_ARLO; ++ ++ /* Clear ARLO flag */ ++ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ARLO); ++ } ++ ++ /* I2C Acknowledge failure error interrupt occurred ------------------------*/ ++ if(((sr1itflags & I2C_FLAG_AF) != RESET) && ((itsources & I2C_IT_ERR) != RESET)) ++ { ++ tmp1 = hi2c->Mode; ++ tmp2 = hi2c->XferCount; ++ tmp3 = hi2c->State; ++ tmp4 = hi2c->PreviousState; ++ if((tmp1 == HAL_I2C_MODE_SLAVE) && (tmp2 == 0U) && \ ++ ((tmp3 == HAL_I2C_STATE_BUSY_TX) || (tmp3 == HAL_I2C_STATE_BUSY_TX_LISTEN) || \ ++ ((tmp3 == HAL_I2C_STATE_LISTEN) && (tmp4 == I2C_STATE_SLAVE_BUSY_TX)))) ++ { ++ I2C_Slave_AF(hi2c); ++ } ++ else ++ { ++ hi2c->ErrorCode |= HAL_I2C_ERROR_AF; ++ ++ /* Do not generate a STOP in case of Slave receive non acknowledge during transfer (mean not at the end of transfer) */ ++ if(hi2c->Mode == HAL_I2C_MODE_MASTER) ++ { ++ /* Generate Stop */ ++ SET_BIT(hi2c->Instance->CR1,I2C_CR1_STOP); ++ } ++ ++ /* Clear AF flag */ ++ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); ++ } ++ } ++ ++ /* I2C Over-Run/Under-Run interrupt occurred -------------------------------*/ ++ if(((sr1itflags & I2C_FLAG_OVR) != RESET) && ((itsources & I2C_IT_ERR) != RESET)) ++ { ++ hi2c->ErrorCode |= HAL_I2C_ERROR_OVR; ++ /* Clear OVR flag */ ++ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_OVR); ++ } ++ ++ /* Call the Error Callback in case of Error detected -----------------------*/ ++ if(hi2c->ErrorCode != HAL_I2C_ERROR_NONE) ++ { ++ I2C_ITError(hi2c); ++ } ++} ++ ++/** ++ * @brief Master Tx Transfer completed callback. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @retval None ++ */ ++__weak void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c) ++{ ++ /* Prevent unused argument(s) compilation warning */ ++ UNUSED(hi2c); ++ ++ /* NOTE : This function should not be modified, when the callback is needed, ++ the HAL_I2C_MasterTxCpltCallback can be implemented in the user file ++ */ ++} ++ ++/** ++ * @brief Master Rx Transfer completed callback. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @retval None ++ */ ++__weak void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c) ++{ ++ /* Prevent unused argument(s) compilation warning */ ++ UNUSED(hi2c); ++ ++ /* NOTE : This function should not be modified, when the callback is needed, ++ the HAL_I2C_MasterRxCpltCallback can be implemented in the user file ++ */ ++} ++ ++/** @brief Slave Tx Transfer completed callback. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @retval None ++ */ ++__weak void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c) ++{ ++ /* Prevent unused argument(s) compilation warning */ ++ UNUSED(hi2c); ++ ++ /* NOTE : This function should not be modified, when the callback is needed, ++ the HAL_I2C_SlaveTxCpltCallback can be implemented in the user file ++ */ ++} ++ ++/** ++ * @brief Slave Rx Transfer completed callback. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @retval None ++ */ ++__weak void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c) ++{ ++ /* Prevent unused argument(s) compilation warning */ ++ UNUSED(hi2c); ++ ++ /* NOTE : This function should not be modified, when the callback is needed, ++ the HAL_I2C_SlaveRxCpltCallback can be implemented in the user file ++ */ ++} ++ ++/** ++ * @brief Slave Address Match callback. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param TransferDirection Master request Transfer Direction (Write/Read), value of @ref I2C_XferOptions_definition ++ * @param AddrMatchCode Address Match Code ++ * @retval None ++ */ ++__weak void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode) ++{ ++ /* Prevent unused argument(s) compilation warning */ ++ UNUSED(hi2c); ++ UNUSED(TransferDirection); ++ UNUSED(AddrMatchCode); ++ ++ /* NOTE : This function should not be modified, when the callback is needed, ++ the HAL_I2C_AddrCallback can be implemented in the user file ++ */ ++} ++ ++/** ++ * @brief Listen Complete callback. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @retval None ++ */ ++__weak void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c) ++{ ++ /* Prevent unused argument(s) compilation warning */ ++ UNUSED(hi2c); ++ ++ /* NOTE : This function should not be modified, when the callback is needed, ++ the HAL_I2C_ListenCpltCallback can be implemented in the user file ++ */ ++} ++ ++/** ++ * @brief Memory Tx Transfer completed callback. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @retval None ++ */ ++__weak void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c) ++{ ++ /* Prevent unused argument(s) compilation warning */ ++ UNUSED(hi2c); ++ ++ /* NOTE : This function should not be modified, when the callback is needed, ++ the HAL_I2C_MemTxCpltCallback can be implemented in the user file ++ */ ++} ++ ++/** ++ * @brief Memory Rx Transfer completed callback. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @retval None ++ */ ++__weak void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c) ++{ ++ /* Prevent unused argument(s) compilation warning */ ++ UNUSED(hi2c); ++ ++ /* NOTE : This function should not be modified, when the callback is needed, ++ the HAL_I2C_MemRxCpltCallback can be implemented in the user file ++ */ ++} ++ ++/** ++ * @brief I2C error callback. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @retval None ++ */ ++__weak void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) ++{ ++ /* Prevent unused argument(s) compilation warning */ ++ UNUSED(hi2c); ++ ++ /* NOTE : This function should not be modified, when the callback is needed, ++ the HAL_I2C_ErrorCallback can be implemented in the user file ++ */ ++} ++ ++/** ++ * @brief I2C abort callback. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @retval None ++ */ ++__weak void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c) ++{ ++ /* Prevent unused argument(s) compilation warning */ ++ UNUSED(hi2c); ++ ++ /* NOTE : This function should not be modified, when the callback is needed, ++ the HAL_I2C_AbortCpltCallback could be implemented in the user file ++ */ ++} ++ ++/** ++ * @} ++ */ ++ ++/** @defgroup I2C_Exported_Functions_Group3 Peripheral State, Mode and Error functions ++ * @brief Peripheral State and Errors functions ++ * ++@verbatim ++ =============================================================================== ++ ##### Peripheral State, Mode and Error functions ##### ++ =============================================================================== ++ [..] ++ This subsection permits to get in run-time the status of the peripheral ++ and the data flow. ++ ++@endverbatim ++ * @{ ++ */ ++ ++/** ++ * @brief Return the I2C handle state. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @retval HAL state ++ */ ++HAL_I2C_StateTypeDef HAL_I2C_GetState(I2C_HandleTypeDef *hi2c) ++{ ++ /* Return I2C handle state */ ++ return hi2c->State; ++} ++ ++/** ++ * @brief Return the I2C Master, Slave, Memory or no mode. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval HAL mode ++ */ ++HAL_I2C_ModeTypeDef HAL_I2C_GetMode(I2C_HandleTypeDef *hi2c) ++{ ++ return hi2c->Mode; ++} ++ ++/** ++ * @brief Return the I2C error code ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @retval I2C Error Code ++ */ ++uint32_t HAL_I2C_GetError(I2C_HandleTypeDef *hi2c) ++{ ++ return hi2c->ErrorCode; ++} ++ ++/** ++ * @} ++ */ ++ ++/** ++ * @brief Handle TXE flag for Master ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_MasterTransmit_TXE(I2C_HandleTypeDef *hi2c) ++{ ++ /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ ++ uint32_t CurrentState = hi2c->State; ++ uint32_t CurrentMode = hi2c->Mode; ++ uint32_t CurrentXferOptions = hi2c->XferOptions; ++ ++ if((hi2c->XferSize == 0U) && (CurrentState == HAL_I2C_STATE_BUSY_TX)) ++ { ++ /* Call TxCpltCallback() directly if no stop mode is set */ ++ if((CurrentXferOptions != I2C_FIRST_AND_LAST_FRAME) && (CurrentXferOptions != I2C_LAST_FRAME) && (CurrentXferOptions != I2C_NO_OPTION_FRAME)) ++ { ++ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ hi2c->PreviousState = I2C_STATE_MASTER_BUSY_TX; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ hi2c->State = HAL_I2C_STATE_READY; ++ ++ HAL_I2C_MasterTxCpltCallback(hi2c); ++ } ++ else /* Generate Stop condition then Call TxCpltCallback() */ ++ { ++ /* Disable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State = HAL_I2C_STATE_READY; ++ ++ if(hi2c->Mode == HAL_I2C_MODE_MEM) ++ { ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ HAL_I2C_MemTxCpltCallback(hi2c); ++ } ++ else ++ { ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ HAL_I2C_MasterTxCpltCallback(hi2c); ++ } ++ } ++ } ++ else if((CurrentState == HAL_I2C_STATE_BUSY_TX) || \ ++ ((CurrentMode == HAL_I2C_MODE_MEM) && (CurrentState == HAL_I2C_STATE_BUSY_RX))) ++ { ++ if(hi2c->XferCount == 0U) ++ { ++ /* Disable BUF interrupt */ ++ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); ++ } ++ else ++ { ++ if(hi2c->Mode == HAL_I2C_MODE_MEM) ++ { ++ if(hi2c->EventCount == 0) ++ { ++ /* If Memory address size is 8Bit */ ++ if(hi2c->MemaddSize == I2C_MEMADD_SIZE_8BIT) ++ { ++ /* Send Memory Address */ ++ hi2c->Instance->DR = I2C_MEM_ADD_LSB(hi2c->Memaddress); ++ ++ hi2c->EventCount += 2; ++ } ++ /* If Memory address size is 16Bit */ ++ else ++ { ++ /* Send MSB of Memory Address */ ++ hi2c->Instance->DR = I2C_MEM_ADD_MSB(hi2c->Memaddress); ++ ++ hi2c->EventCount++; ++ } ++ } ++ else if(hi2c->EventCount == 1) ++ { ++ /* Send LSB of Memory Address */ ++ hi2c->Instance->DR = I2C_MEM_ADD_LSB(hi2c->Memaddress); ++ ++ hi2c->EventCount++; ++ } ++ else if(hi2c->EventCount == 2) ++ { ++ if(hi2c->State == HAL_I2C_STATE_BUSY_RX) ++ { ++ /* Generate Restart */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ } ++ else if(hi2c->State == HAL_I2C_STATE_BUSY_TX) ++ { ++ /* Write data to DR */ ++ hi2c->Instance->DR = (*hi2c->pBuffPtr++); ++ hi2c->XferCount--; ++ } ++ } ++ } ++ else ++ { ++ /* Write data to DR */ ++ hi2c->Instance->DR = (*hi2c->pBuffPtr++); ++ hi2c->XferCount--; ++ } ++ } ++ } ++ return HAL_OK; ++} ++ ++/** ++ * @brief Handle BTF flag for Master transmitter ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_MasterTransmit_BTF(I2C_HandleTypeDef *hi2c) ++{ ++ /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ ++ uint32_t CurrentXferOptions = hi2c->XferOptions; ++ ++ if(hi2c->State == HAL_I2C_STATE_BUSY_TX) ++ { ++ if(hi2c->XferCount != 0U) ++ { ++ /* Write data to DR */ ++ hi2c->Instance->DR = (*hi2c->pBuffPtr++); ++ hi2c->XferCount--; ++ } ++ else ++ { ++ /* Call TxCpltCallback() directly if no stop mode is set */ ++ if((CurrentXferOptions != I2C_FIRST_AND_LAST_FRAME) && (CurrentXferOptions != I2C_LAST_FRAME) && (CurrentXferOptions != I2C_NO_OPTION_FRAME)) ++ { ++ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ hi2c->PreviousState = I2C_STATE_MASTER_BUSY_TX; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ hi2c->State = HAL_I2C_STATE_READY; ++ ++ HAL_I2C_MasterTxCpltCallback(hi2c); ++ } ++ else /* Generate Stop condition then Call TxCpltCallback() */ ++ { ++ /* Disable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State = HAL_I2C_STATE_READY; ++ ++ if(hi2c->Mode == HAL_I2C_MODE_MEM) ++ { ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ HAL_I2C_MemTxCpltCallback(hi2c); ++ } ++ else ++ { ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ HAL_I2C_MasterTxCpltCallback(hi2c); ++ } ++ } ++ } ++ } ++ return HAL_OK; ++} ++ ++/** ++ * @brief Handle RXNE flag for Master ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_MasterReceive_RXNE(I2C_HandleTypeDef *hi2c) ++{ ++ if(hi2c->State == HAL_I2C_STATE_BUSY_RX) ++ { ++ uint32_t tmp = 0U; ++ ++ tmp = hi2c->XferCount; ++ if(tmp > 3U) ++ { ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferCount--; ++ ++ if(hi2c->XferCount == 3) ++ { ++ /* Disable BUF interrupt, this help to treat correctly the last 4 bytes ++ on BTF subroutine */ ++ /* Disable BUF interrupt */ ++ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); ++ } ++ } ++ else if((tmp == 1U) || (tmp == 0U)) ++ { ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ /* Disable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferCount--; ++ ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->PreviousState = I2C_STATE_NONE; ++ ++ if(hi2c->Mode == HAL_I2C_MODE_MEM) ++ { ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ HAL_I2C_MemRxCpltCallback(hi2c); ++ } ++ else ++ { ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ HAL_I2C_MasterRxCpltCallback(hi2c); ++ } ++ } ++ } ++ return HAL_OK; ++} ++ ++/** ++ * @brief Handle BTF flag for Master receiver ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_MasterReceive_BTF(I2C_HandleTypeDef *hi2c) ++{ ++ /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ ++ uint32_t CurrentXferOptions = hi2c->XferOptions; ++ ++ if(hi2c->XferCount == 4U) ++ { ++ /* Disable BUF interrupt, this help to treat correctly the last 2 bytes ++ on BTF subroutine if there is a reception delay between N-1 and N byte */ ++ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferCount--; ++ } ++ else if(hi2c->XferCount == 3U) ++ { ++ /* Disable BUF interrupt, this help to treat correctly the last 2 bytes ++ on BTF subroutine if there is a reception delay between N-1 and N byte */ ++ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); ++ ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferCount--; ++ } ++ else if(hi2c->XferCount == 2U) ++ { ++ /* Prepare next transfer or stop current transfer */ ++ if((CurrentXferOptions == I2C_NEXT_FRAME) || (CurrentXferOptions == I2C_FIRST_FRAME)) ++ { ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ /* Generate ReStart */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ } ++ else ++ { ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ } ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferCount--; ++ ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferCount--; ++ ++ /* Disable EVT and ERR interrupt */ ++ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); ++ ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->PreviousState = I2C_STATE_NONE; ++ ++ if(hi2c->Mode == HAL_I2C_MODE_MEM) ++ { ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ HAL_I2C_MemRxCpltCallback(hi2c); ++ } ++ else ++ { ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ HAL_I2C_MasterRxCpltCallback(hi2c); ++ } ++ } ++ else ++ { ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferCount--; ++ } ++ return HAL_OK; ++} ++ ++/** ++ * @brief Handle SB flag for Master ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_Master_SB(I2C_HandleTypeDef *hi2c) ++{ ++ if(hi2c->Mode == HAL_I2C_MODE_MEM) ++ { ++ if(hi2c->EventCount == 0U) ++ { ++ /* Send slave address */ ++ hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(hi2c->Devaddress); ++ } ++ else ++ { ++ hi2c->Instance->DR = I2C_7BIT_ADD_READ(hi2c->Devaddress); ++ } ++ } ++ else ++ { ++ if(hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_7BIT) ++ { ++ /* Send slave 7 Bits address */ ++ if(hi2c->State == HAL_I2C_STATE_BUSY_TX) ++ { ++ hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(hi2c->Devaddress); ++ } ++ else ++ { ++ hi2c->Instance->DR = I2C_7BIT_ADD_READ(hi2c->Devaddress); ++ } ++ } ++ else ++ { ++ if(hi2c->EventCount == 0U) ++ { ++ /* Send header of slave address */ ++ hi2c->Instance->DR = I2C_10BIT_HEADER_WRITE(hi2c->Devaddress); ++ } ++ else if(hi2c->EventCount == 1U) ++ { ++ /* Send header of slave address */ ++ hi2c->Instance->DR = I2C_10BIT_HEADER_READ(hi2c->Devaddress); ++ } ++ } ++ } ++ ++ return HAL_OK; ++} ++ ++/** ++ * @brief Handle ADD10 flag for Master ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_Master_ADD10(I2C_HandleTypeDef *hi2c) ++{ ++ /* Send slave address */ ++ hi2c->Instance->DR = I2C_10BIT_ADDRESS(hi2c->Devaddress); ++ ++ return HAL_OK; ++} ++ ++/** ++ * @brief Handle ADDR flag for Master ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_Master_ADDR(I2C_HandleTypeDef *hi2c) ++{ ++ /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ ++ uint32_t CurrentMode = hi2c->Mode; ++ uint32_t CurrentXferOptions = hi2c->XferOptions; ++ uint32_t Prev_State = hi2c->PreviousState; ++ ++ if(hi2c->State == HAL_I2C_STATE_BUSY_RX) ++ { ++ if((hi2c->EventCount == 0U) && (CurrentMode == HAL_I2C_MODE_MEM)) ++ { ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ } ++ else if((hi2c->EventCount == 0U) && (hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_10BIT)) ++ { ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* Generate Restart */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ ++ hi2c->EventCount++; ++ } ++ else ++ { ++ if(hi2c->XferCount == 0U) ++ { ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ } ++ else if(hi2c->XferCount == 1U) ++ { ++ if(CurrentXferOptions == I2C_NO_OPTION_FRAME) ++ { ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ if((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) ++ { ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ } ++ else ++ { ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ } ++ } ++ /* Prepare next transfer or stop current transfer */ ++ else if((CurrentXferOptions != I2C_FIRST_AND_LAST_FRAME) && (CurrentXferOptions != I2C_LAST_FRAME) \ ++ && (Prev_State != I2C_STATE_MASTER_BUSY_RX)) ++ { ++ if(hi2c->XferOptions != I2C_NEXT_FRAME) ++ { ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ } ++ else ++ { ++ /* Enable Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ } ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ } ++ else ++ { ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ } ++ } ++ else if(hi2c->XferCount == 2U) ++ { ++ if(hi2c->XferOptions != I2C_NEXT_FRAME) ++ { ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ /* Enable Pos */ ++ hi2c->Instance->CR1 |= I2C_CR1_POS; ++ } ++ else ++ { ++ /* Enable Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ } ++ ++ if((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) ++ { ++ /* Enable Last DMA bit */ ++ hi2c->Instance->CR2 |= I2C_CR2_LAST; ++ } ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ } ++ else ++ { ++ /* Enable Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ if((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) ++ { ++ /* Enable Last DMA bit */ ++ hi2c->Instance->CR2 |= I2C_CR2_LAST; ++ } ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ } ++ ++ /* Reset Event counter */ ++ hi2c->EventCount = 0U; ++ } ++ } ++ else ++ { ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ } ++ ++ return HAL_OK; ++} ++ ++/** ++ * @brief Handle TXE flag for Slave ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_SlaveTransmit_TXE(I2C_HandleTypeDef *hi2c) ++{ ++ /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ ++ uint32_t CurrentState = hi2c->State; ++ ++ if(hi2c->XferCount != 0U) ++ { ++ /* Write data to DR */ ++ hi2c->Instance->DR = (*hi2c->pBuffPtr++); ++ hi2c->XferCount--; ++ ++ if((hi2c->XferCount == 0U) && (CurrentState == HAL_I2C_STATE_BUSY_TX_LISTEN)) ++ { ++ /* Last Byte is received, disable Interrupt */ ++ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); ++ ++ /* Set state at HAL_I2C_STATE_LISTEN */ ++ hi2c->PreviousState = I2C_STATE_SLAVE_BUSY_TX; ++ hi2c->State = HAL_I2C_STATE_LISTEN; ++ ++ /* Call the Tx complete callback to inform upper layer of the end of receive process */ ++ HAL_I2C_SlaveTxCpltCallback(hi2c); ++ } ++ } ++ return HAL_OK; ++} ++ ++/** ++ * @brief Handle BTF flag for Slave transmitter ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_SlaveTransmit_BTF(I2C_HandleTypeDef *hi2c) ++{ ++ if(hi2c->XferCount != 0U) ++ { ++ /* Write data to DR */ ++ hi2c->Instance->DR = (*hi2c->pBuffPtr++); ++ hi2c->XferCount--; ++ } ++ return HAL_OK; ++} ++ ++/** ++ * @brief Handle RXNE flag for Slave ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_SlaveReceive_RXNE(I2C_HandleTypeDef *hi2c) ++{ ++ /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ ++ uint32_t CurrentState = hi2c->State; ++ ++ if(hi2c->XferCount != 0U) ++ { ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferCount--; ++ ++ if((hi2c->XferCount == 0U) && (CurrentState == HAL_I2C_STATE_BUSY_RX_LISTEN)) ++ { ++ /* Last Byte is received, disable Interrupt */ ++ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); ++ ++ /* Set state at HAL_I2C_STATE_LISTEN */ ++ hi2c->PreviousState = I2C_STATE_SLAVE_BUSY_RX; ++ hi2c->State = HAL_I2C_STATE_LISTEN; ++ ++ /* Call the Rx complete callback to inform upper layer of the end of receive process */ ++ HAL_I2C_SlaveRxCpltCallback(hi2c); ++ } ++ } ++ return HAL_OK; ++} ++ ++/** ++ * @brief Handle BTF flag for Slave receiver ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_SlaveReceive_BTF(I2C_HandleTypeDef *hi2c) ++{ ++ if(hi2c->XferCount != 0U) ++ { ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferCount--; ++ } ++ return HAL_OK; ++} ++ ++/** ++ * @brief Handle ADD flag for Slave ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_Slave_ADDR(I2C_HandleTypeDef *hi2c) ++{ ++ uint8_t TransferDirection = I2C_DIRECTION_RECEIVE; ++ uint16_t SlaveAddrCode = 0U; ++ ++ /* Transfer Direction requested by Master */ ++ if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TRA) == RESET) ++ { ++ TransferDirection = I2C_DIRECTION_TRANSMIT; ++ } ++ ++ if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_DUALF) == RESET) ++ { ++ SlaveAddrCode = hi2c->Init.OwnAddress1; ++ } ++ else ++ { ++ SlaveAddrCode = hi2c->Init.OwnAddress2; ++ } ++ ++ /* Call Slave Addr callback */ ++ HAL_I2C_AddrCallback(hi2c, TransferDirection, SlaveAddrCode); ++ ++ return HAL_OK; ++} ++ ++/** ++ * @brief Handle STOPF flag for Slave ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_Slave_STOPF(I2C_HandleTypeDef *hi2c) ++{ ++ /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ ++ uint32_t CurrentState = hi2c->State; ++ ++ /* Disable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ /* Clear STOPF flag */ ++ __HAL_I2C_CLEAR_STOPFLAG(hi2c); ++ ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ /* If a DMA is ongoing, Update handle size context */ ++ if((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) ++ { ++ if((hi2c->State == HAL_I2C_STATE_BUSY_RX) || (hi2c->State == HAL_I2C_STATE_BUSY_RX_LISTEN)) ++ { ++ hi2c->XferCount = __HAL_DMA_GET_COUNTER(hi2c->hdmarx); ++ } ++ else ++ { ++ hi2c->XferCount = __HAL_DMA_GET_COUNTER(hi2c->hdmatx); ++ } ++ } ++ ++ /* All data are not transferred, so set error code accordingly */ ++ if(hi2c->XferCount != 0U) ++ { ++ /* Store Last receive data if any */ ++ if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) ++ { ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferCount--; ++ } ++ ++ /* Store Last receive data if any */ ++ if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET) ++ { ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ hi2c->XferCount--; ++ } ++ ++ /* Set ErrorCode corresponding to a Non-Acknowledge */ ++ //hi2c->ErrorCode |= HAL_I2C_ERROR_AF; ++ } ++ ++ if(hi2c->ErrorCode != HAL_I2C_ERROR_NONE) ++ { ++ /* Call the corresponding callback to inform upper layer of End of Transfer */ ++ I2C_ITError(hi2c); ++ } ++ else ++ { ++ if((CurrentState == HAL_I2C_STATE_LISTEN ) || (CurrentState == HAL_I2C_STATE_BUSY_RX_LISTEN) || \ ++ (CurrentState == HAL_I2C_STATE_BUSY_TX_LISTEN)) ++ { ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ /* Call the Listen Complete callback, to inform upper layer of the end of Listen usecase */ ++ HAL_I2C_ListenCpltCallback(hi2c); ++ } ++ else ++ { ++ if((hi2c->PreviousState == I2C_STATE_SLAVE_BUSY_RX) || (CurrentState == HAL_I2C_STATE_BUSY_RX)) ++ { ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ HAL_I2C_SlaveRxCpltCallback(hi2c); ++ } ++ } ++ } ++ return HAL_OK; ++} ++ ++/** ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_Slave_AF(I2C_HandleTypeDef *hi2c) ++{ ++ /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ ++ uint32_t CurrentState = hi2c->State; ++ uint32_t CurrentXferOptions = hi2c->XferOptions; ++ ++ if(((CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_LAST_FRAME)) && \ ++ (CurrentState == HAL_I2C_STATE_LISTEN)) ++ { ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ ++ /* Disable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ /* Clear AF flag */ ++ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); ++ ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ /* Call the Listen Complete callback, to inform upper layer of the end of Listen usecase */ ++ HAL_I2C_ListenCpltCallback(hi2c); ++ } ++ else if(CurrentState == HAL_I2C_STATE_BUSY_TX) ++ { ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->PreviousState = I2C_STATE_SLAVE_BUSY_TX; ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ /* Disable EVT, BUF and ERR interrupt */ ++ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); ++ ++ /* Clear AF flag */ ++ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); ++ ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ HAL_I2C_SlaveTxCpltCallback(hi2c); ++ } ++ else ++ { ++ /* Clear AF flag only */ ++ /* State Listen, but XferOptions == FIRST or NEXT */ ++ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); ++ } ++ ++ return HAL_OK; ++} ++ ++/** ++ * @brief I2C interrupts error process ++ * @param hi2c I2C handle. ++ * @retval None ++ */ ++static void I2C_ITError(I2C_HandleTypeDef *hi2c) ++{ ++ /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ ++ uint32_t CurrentState = hi2c->State; ++ ++ if((CurrentState == HAL_I2C_STATE_BUSY_TX_LISTEN) || (CurrentState == HAL_I2C_STATE_BUSY_RX_LISTEN)) ++ { ++ /* keep HAL_I2C_STATE_LISTEN */ ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State = HAL_I2C_STATE_LISTEN; ++ } ++ else ++ { ++ /* If state is an abort treatment on going, don't change state */ ++ /* This change will be do later */ ++ if((hi2c->State != HAL_I2C_STATE_ABORT) && ((hi2c->Instance->CR2 & I2C_CR2_DMAEN) != I2C_CR2_DMAEN)) ++ { ++ hi2c->State = HAL_I2C_STATE_READY; ++ } ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ } ++ ++ /* Disable Pos bit in I2C CR1 when error occurred in Master/Mem Receive IT Process */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_POS; ++ ++ /* Abort DMA transfer */ ++ if((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) ++ { ++ hi2c->Instance->CR2 &= ~I2C_CR2_DMAEN; ++ ++ if(hi2c->hdmatx->State != HAL_DMA_STATE_READY) ++ { ++ /* Set the DMA Abort callback : ++ will lead to call HAL_I2C_ErrorCallback() at end of DMA abort procedure */ ++ hi2c->hdmatx->XferAbortCallback = I2C_DMAAbort; ++ ++ if(HAL_DMA_Abort_IT(hi2c->hdmatx) != HAL_OK) ++ { ++ /* Disable I2C peripheral to prevent dummy data in buffer */ ++ __HAL_I2C_DISABLE(hi2c); ++ ++ hi2c->State = HAL_I2C_STATE_READY; ++ ++ /* Call Directly XferAbortCallback function in case of error */ ++ hi2c->hdmatx->XferAbortCallback(hi2c->hdmatx); ++ } ++ } ++ else ++ { ++ /* Set the DMA Abort callback : ++ will lead to call HAL_I2C_ErrorCallback() at end of DMA abort procedure */ ++ hi2c->hdmarx->XferAbortCallback = I2C_DMAAbort; ++ ++ if(HAL_DMA_Abort_IT(hi2c->hdmarx) != HAL_OK) ++ { ++ /* Store Last receive data if any */ ++ if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET) ++ { ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ } ++ ++ /* Disable I2C peripheral to prevent dummy data in buffer */ ++ __HAL_I2C_DISABLE(hi2c); ++ ++ hi2c->State = HAL_I2C_STATE_READY; ++ ++ /* Call Directly hi2c->hdmarx->XferAbortCallback function in case of error */ ++ hi2c->hdmarx->XferAbortCallback(hi2c->hdmarx); ++ } ++ } ++ } ++ else if(hi2c->State == HAL_I2C_STATE_ABORT) ++ { ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Store Last receive data if any */ ++ if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET) ++ { ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ } ++ ++ /* Disable I2C peripheral to prevent dummy data in buffer */ ++ __HAL_I2C_DISABLE(hi2c); ++ ++ /* Call the corresponding callback to inform upper layer of End of Transfer */ ++ HAL_I2C_AbortCpltCallback(hi2c); ++ } ++ else ++ { ++ /* Store Last receive data if any */ ++ if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET) ++ { ++ /* Read data from DR */ ++ (*hi2c->pBuffPtr++) = hi2c->Instance->DR; ++ } ++ ++ /* Call user error callback */ ++ HAL_I2C_ErrorCallback(hi2c); ++ } ++ /* STOP Flag is not set after a NACK reception */ ++ /* So may inform upper layer that listen phase is stopped */ ++ /* during NACK error treatment */ ++ if((hi2c->State == HAL_I2C_STATE_LISTEN) && ((hi2c->ErrorCode & HAL_I2C_ERROR_AF) == HAL_I2C_ERROR_AF)) ++ { ++ hi2c->XferOptions = I2C_NO_OPTION_FRAME; ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ /* Call the Listen Complete callback, to inform upper layer of the end of Listen usecase */ ++ HAL_I2C_ListenCpltCallback(hi2c); ++ } ++} ++ ++/** ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @param DevAddress Target device address The device 7 bits address value ++ * in datasheet must be shifted to the left before calling the interface ++ * @param Timeout Timeout duration ++ * @param Tickstart Tick start value ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_MasterRequestWrite(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Timeout, uint32_t Tickstart) ++{ ++ /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ ++ uint32_t CurrentXferOptions = hi2c->XferOptions; ++ ++ /* Generate Start condition if first transfer */ ++ if((CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_FIRST_FRAME) || (CurrentXferOptions == I2C_NO_OPTION_FRAME)) ++ { ++ /* Generate Start */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ } ++ else if(hi2c->PreviousState == I2C_STATE_MASTER_BUSY_RX) ++ { ++ /* Generate ReStart */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ } ++ ++ /* Wait until SB flag is set */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ if(hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_7BIT) ++ { ++ /* Send slave address */ ++ hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(DevAddress); ++ } ++ else ++ { ++ /* Send header of slave address */ ++ hi2c->Instance->DR = I2C_10BIT_HEADER_WRITE(DevAddress); ++ ++ /* Wait until ADD10 flag is set */ ++ if(I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADD10, Timeout, Tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* Send slave address */ ++ hi2c->Instance->DR = I2C_10BIT_ADDRESS(DevAddress); ++ } ++ ++ /* Wait until ADDR flag is set */ ++ if(I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ return HAL_OK; ++} ++ ++/** ++ * @brief Master sends target device address for read request. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @param DevAddress Target device address The device 7 bits address value ++ * in datasheet must be shifted to the left before calling the interface ++ * @param Timeout Timeout duration ++ * @param Tickstart Tick start value ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_MasterRequestRead(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Timeout, uint32_t Tickstart) ++{ ++ /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ ++ uint32_t CurrentXferOptions = hi2c->XferOptions; ++ ++ /* Enable Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Generate Start condition if first transfer */ ++ if((CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_FIRST_FRAME) || (CurrentXferOptions == I2C_NO_OPTION_FRAME)) ++ { ++ /* Generate Start */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ } ++ else if(hi2c->PreviousState == I2C_STATE_MASTER_BUSY_TX) ++ { ++ /* Generate ReStart */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ } ++ ++ /* Wait until SB flag is set */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ if(hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_7BIT) ++ { ++ /* Send slave address */ ++ hi2c->Instance->DR = I2C_7BIT_ADD_READ(DevAddress); ++ } ++ else ++ { ++ /* Send header of slave address */ ++ hi2c->Instance->DR = I2C_10BIT_HEADER_WRITE(DevAddress); ++ ++ /* Wait until ADD10 flag is set */ ++ if(I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADD10, Timeout, Tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* Send slave address */ ++ hi2c->Instance->DR = I2C_10BIT_ADDRESS(DevAddress); ++ ++ /* Wait until ADDR flag is set */ ++ if(I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* Generate Restart */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ ++ /* Wait until SB flag is set */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ /* Send header of slave address */ ++ hi2c->Instance->DR = I2C_10BIT_HEADER_READ(DevAddress); ++ } ++ ++ /* Wait until ADDR flag is set */ ++ if(I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ return HAL_OK; ++} ++ ++/** ++ * @brief Master sends target device address followed by internal memory address for write request. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @param DevAddress Target device address ++ * @param MemAddress Internal memory address ++ * @param MemAddSize Size of internal memory address ++ * @param Timeout Timeout duration ++ * @param Tickstart Tick start value ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_RequestMemoryWrite(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout, uint32_t Tickstart) ++{ ++ /* Generate Start */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ ++ /* Wait until SB flag is set */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ /* Send slave address */ ++ hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(DevAddress); ++ ++ /* Wait until ADDR flag is set */ ++ if(I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* Wait until TXE flag is set */ ++ if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* If Memory address size is 8Bit */ ++ if(MemAddSize == I2C_MEMADD_SIZE_8BIT) ++ { ++ /* Send Memory Address */ ++ hi2c->Instance->DR = I2C_MEM_ADD_LSB(MemAddress); ++ } ++ /* If Memory address size is 16Bit */ ++ else ++ { ++ /* Send MSB of Memory Address */ ++ hi2c->Instance->DR = I2C_MEM_ADD_MSB(MemAddress); ++ ++ /* Wait until TXE flag is set */ ++ if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* Send LSB of Memory Address */ ++ hi2c->Instance->DR = I2C_MEM_ADD_LSB(MemAddress); ++ } ++ ++ return HAL_OK; ++} ++ ++/** ++ * @brief Master sends target device address followed by internal memory address for read request. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @param DevAddress Target device address ++ * @param MemAddress Internal memory address ++ * @param MemAddSize Size of internal memory address ++ * @param Timeout Timeout duration ++ * @param Tickstart Tick start value ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_RequestMemoryRead(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout, uint32_t Tickstart) ++{ ++ /* Enable Acknowledge */ ++ hi2c->Instance->CR1 |= I2C_CR1_ACK; ++ ++ /* Generate Start */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ ++ /* Wait until SB flag is set */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ /* Send slave address */ ++ hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(DevAddress); ++ ++ /* Wait until ADDR flag is set */ ++ if(I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* Clear ADDR flag */ ++ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); ++ ++ /* Wait until TXE flag is set */ ++ if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* If Memory address size is 8Bit */ ++ if(MemAddSize == I2C_MEMADD_SIZE_8BIT) ++ { ++ /* Send Memory Address */ ++ hi2c->Instance->DR = I2C_MEM_ADD_LSB(MemAddress); ++ } ++ /* If Memory address size is 16Bit */ ++ else ++ { ++ /* Send MSB of Memory Address */ ++ hi2c->Instance->DR = I2C_MEM_ADD_MSB(MemAddress); ++ ++ /* Wait until TXE flag is set */ ++ if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* Send LSB of Memory Address */ ++ hi2c->Instance->DR = I2C_MEM_ADD_LSB(MemAddress); ++ } ++ ++ /* Wait until TXE flag is set */ ++ if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* Generate Restart */ ++ hi2c->Instance->CR1 |= I2C_CR1_START; ++ ++ /* Wait until SB flag is set */ ++ if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) ++ { ++ return HAL_TIMEOUT; ++ } ++ ++ /* Send slave address */ ++ hi2c->Instance->DR = I2C_7BIT_ADD_READ(DevAddress); ++ ++ /* Wait until ADDR flag is set */ ++ if(I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) ++ { ++ if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) ++ { ++ return HAL_ERROR; ++ } ++ else ++ { ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ return HAL_OK; ++} ++ ++/** ++ * @brief DMA I2C process complete callback. ++ * @param hdma DMA handle ++ * @retval None ++ */ ++static void I2C_DMAXferCplt(DMA_HandleTypeDef *hdma) ++{ ++ I2C_HandleTypeDef* hi2c = (I2C_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent; ++ ++ /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ ++ uint32_t CurrentState = hi2c->State; ++ uint32_t CurrentMode = hi2c->Mode; ++ ++ if((CurrentState == HAL_I2C_STATE_BUSY_TX) || ((CurrentState == HAL_I2C_STATE_BUSY_RX) && (CurrentMode == HAL_I2C_MODE_SLAVE))) ++ { ++ /* Disable DMA Request */ ++ hi2c->Instance->CR2 &= ~I2C_CR2_DMAEN; ++ ++ hi2c->XferCount = 0U; ++ ++ /* Enable EVT and ERR interrupt */ ++ __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); ++ } ++ else ++ { ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ ++ /* Disable Last DMA */ ++ hi2c->Instance->CR2 &= ~I2C_CR2_LAST; ++ ++ /* Disable DMA Request */ ++ hi2c->Instance->CR2 &= ~I2C_CR2_DMAEN; ++ ++ hi2c->XferCount = 0U; ++ ++ /* Check if Errors has been detected during transfer */ ++ if(hi2c->ErrorCode != HAL_I2C_ERROR_NONE) ++ { ++ HAL_I2C_ErrorCallback(hi2c); ++ } ++ else ++ { ++ hi2c->State = HAL_I2C_STATE_READY; ++ ++ if(hi2c->Mode == HAL_I2C_MODE_MEM) ++ { ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ HAL_I2C_MemRxCpltCallback(hi2c); ++ } ++ else ++ { ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ HAL_I2C_MasterRxCpltCallback(hi2c); ++ } ++ } ++ } ++} ++ ++/** ++ * @brief DMA I2C communication error callback. ++ * @param hdma DMA handle ++ * @retval None ++ */ ++static void I2C_DMAError(DMA_HandleTypeDef *hdma) ++{ ++ I2C_HandleTypeDef* hi2c = (I2C_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent; ++ ++ /* Ignore DMA FIFO error */ ++ if(HAL_DMA_GetError(hdma) != HAL_DMA_ERROR_FE) ++ { ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ hi2c->XferCount = 0U; ++ ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ hi2c->ErrorCode |= HAL_I2C_ERROR_DMA; ++ ++ HAL_I2C_ErrorCallback(hi2c); ++ } ++} ++ ++/** ++ * @brief DMA I2C communication abort callback ++ * (To be called at end of DMA Abort procedure). ++ * @param hdma DMA handle. ++ * @retval None ++ */ ++static void I2C_DMAAbort(DMA_HandleTypeDef *hdma) ++{ ++ I2C_HandleTypeDef* hi2c = ( I2C_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; ++ ++ /* Disable Acknowledge */ ++ hi2c->Instance->CR1 &= ~I2C_CR1_ACK; ++ ++ hi2c->XferCount = 0U; ++ ++ /* Reset XferAbortCallback */ ++ hi2c->hdmatx->XferAbortCallback = NULL; ++ hi2c->hdmarx->XferAbortCallback = NULL; ++ ++ /* Check if come from abort from user */ ++ if(hi2c->State == HAL_I2C_STATE_ABORT) ++ { ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ ++ /* Disable I2C peripheral to prevent dummy data in buffer */ ++ __HAL_I2C_DISABLE(hi2c); ++ ++ /* Call the corresponding callback to inform upper layer of End of Transfer */ ++ HAL_I2C_AbortCpltCallback(hi2c); ++ } ++ else ++ { ++ hi2c->State = HAL_I2C_STATE_READY; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ /* Disable I2C peripheral to prevent dummy data in buffer */ ++ __HAL_I2C_DISABLE(hi2c); ++ ++ /* Call the corresponding callback to inform upper layer of End of Transfer */ ++ HAL_I2C_ErrorCallback(hi2c); ++ } ++} ++ ++/** ++ * @brief This function handles I2C Communication Timeout. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @param Flag specifies the I2C flag to check. ++ * @param Status The new Flag status (SET or RESET). ++ * @param Timeout Timeout duration ++ * @param Tickstart Tick start value ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, FlagStatus Status, uint32_t Timeout, uint32_t Tickstart) ++{ ++ /* Wait until flag is set */ ++ while((__HAL_I2C_GET_FLAG(hi2c, Flag) ? SET : RESET) == Status) ++ { ++ /* Check for the Timeout */ ++ if(Timeout != HAL_MAX_DELAY) ++ { ++ if((Timeout == 0U)||((HAL_GetTick() - Tickstart ) > Timeout)) ++ { ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ hi2c->Mode = HAL_I2C_MODE_NONE; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ } ++ ++ return HAL_OK; ++} ++ ++/** ++ * @brief This function handles I2C Communication Timeout for Master addressing phase. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for I2C module ++ * @param Flag specifies the I2C flag to check. ++ * @param Timeout Timeout duration ++ * @param Tickstart Tick start value ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_WaitOnMasterAddressFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, uint32_t Timeout, uint32_t Tickstart) ++{ ++ while(__HAL_I2C_GET_FLAG(hi2c, Flag) == RESET) ++ { ++ if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) ++ { ++ /* Generate Stop */ ++ hi2c->Instance->CR1 |= I2C_CR1_STOP; ++ ++ /* Clear AF Flag */ ++ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); ++ ++ hi2c->ErrorCode = HAL_I2C_ERROR_AF; ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_ERROR; ++ } ++ ++ /* Check for the Timeout */ ++ if(Timeout != HAL_MAX_DELAY) ++ { ++ if((Timeout == 0U)||((HAL_GetTick() - Tickstart ) > Timeout)) ++ { ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ } ++ return HAL_OK; ++} ++ ++/** ++ * @brief This function handles I2C Communication Timeout for specific usage of TXE flag. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param Timeout Timeout duration ++ * @param Tickstart Tick start value ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_WaitOnTXEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) ++{ ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET) ++ { ++ /* Check if a NACK is detected */ ++ if(I2C_IsAcknowledgeFailed(hi2c) != HAL_OK) ++ { ++ return HAL_ERROR; ++ } ++ ++ /* Check for the Timeout */ ++ if(Timeout != HAL_MAX_DELAY) ++ { ++ if((Timeout == 0U) || ((HAL_GetTick()-Tickstart) > Timeout)) ++ { ++ hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ } ++ return HAL_OK; ++} ++ ++/** ++ * @brief This function handles I2C Communication Timeout for specific usage of BTF flag. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param Timeout Timeout duration ++ * @param Tickstart Tick start value ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_WaitOnBTFFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) ++{ ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == RESET) ++ { ++ /* Check if a NACK is detected */ ++ if(I2C_IsAcknowledgeFailed(hi2c) != HAL_OK) ++ { ++ return HAL_ERROR; ++ } ++ ++ /* Check for the Timeout */ ++ if(Timeout != HAL_MAX_DELAY) ++ { ++ if((Timeout == 0U) || ((HAL_GetTick()-Tickstart) > Timeout)) ++ { ++ hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ } ++ return HAL_OK; ++} ++ ++/** ++ * @brief This function handles I2C Communication Timeout for specific usage of STOP flag. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param Timeout Timeout duration ++ * @param Tickstart Tick start value ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_WaitOnSTOPFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) ++{ ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == RESET) ++ { ++ /* Check if a NACK is detected */ ++ if(I2C_IsAcknowledgeFailed(hi2c) != HAL_OK) ++ { ++ return HAL_ERROR; ++ } ++ ++ /* Check for the Timeout */ ++ if((Timeout == 0U) || ((HAL_GetTick()-Tickstart) > Timeout)) ++ { ++ hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ return HAL_OK; ++} ++ ++/** ++ * @brief This function handles I2C Communication Timeout for specific usage of RXNE flag. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @param Timeout Timeout duration ++ * @param Tickstart Tick start value ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_WaitOnRXNEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) ++{ ++ ++ while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == RESET) ++ { ++ /* Check if a STOPF is detected */ ++ if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET) ++ { ++ /* Clear STOP Flag */ ++ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); ++ ++ hi2c->ErrorCode = HAL_I2C_ERROR_NONE; ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_ERROR; ++ } ++ ++ /* Check for the Timeout */ ++ if((Timeout == 0U) || ((HAL_GetTick()-Tickstart) > Timeout)) ++ { ++ hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ return HAL_OK; ++} ++ ++/** ++ * @brief This function handles Acknowledge failed detection during an I2C Communication. ++ * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2C. ++ * @retval HAL status ++ */ ++static HAL_StatusTypeDef I2C_IsAcknowledgeFailed(I2C_HandleTypeDef *hi2c) ++{ ++ if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) ++ { ++ /* Clear NACKF Flag */ ++ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); ++ ++ hi2c->ErrorCode = HAL_I2C_ERROR_AF; ++ hi2c->PreviousState = I2C_STATE_NONE; ++ hi2c->State= HAL_I2C_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(hi2c); ++ ++ return HAL_ERROR; ++ } ++ return HAL_OK; ++} ++/** ++ * @} ++ */ ++ ++#endif /* HAL_I2C_MODULE_ENABLED */ ++ ++/** ++ * @} ++ */ ++ ++/** ++ * @} ++ */ ++ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +diff --git a/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c b/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c +new file mode 100644 +index 0000000..de8f160 +--- /dev/null ++++ b/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c +@@ -0,0 +1,204 @@ ++/** ++ ****************************************************************************** ++ * @file stm32f4xx_hal_i2c_ex.c ++ * @author MCD Application Team ++ * @brief I2C Extension HAL module driver. ++ * This file provides firmware functions to manage the following ++ * functionalities of I2C extension peripheral: ++ * + Extension features functions ++ * ++ @verbatim ++ ============================================================================== ++ ##### I2C peripheral extension features ##### ++ ============================================================================== ++ ++ [..] Comparing to other previous devices, the I2C interface for STM32F427xx/437xx/ ++ 429xx/439xx devices contains the following additional features : ++ ++ (+) Possibility to disable or enable Analog Noise Filter ++ (+) Use of a configured Digital Noise Filter ++ ++ ##### How to use this driver ##### ++ ============================================================================== ++ [..] This driver provides functions to configure Noise Filter ++ (#) Configure I2C Analog noise filter using the function HAL_I2C_AnalogFilter_Config() ++ (#) Configure I2C Digital noise filter using the function HAL_I2C_DigitalFilter_Config() ++ ++ @endverbatim ++ ****************************************************************************** ++ * @attention ++ * ++ *

© COPYRIGHT(c) 2017 STMicroelectronics

++ * ++ * Redistribution and use in source and binary forms, with or without modification, ++ * are permitted provided that the following conditions are met: ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions and the following disclaimer. ++ * 2. 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. ++ * 3. Neither the name of STMicroelectronics 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. ++ * ++ ****************************************************************************** ++ */ ++ ++/* Includes ------------------------------------------------------------------*/ ++#include "stm32f4xx_hal.h" ++ ++/** @addtogroup STM32F4xx_HAL_Driver ++ * @{ ++ */ ++ ++/** @defgroup I2CEx I2CEx ++ * @brief I2C HAL module driver ++ * @{ ++ */ ++ ++#ifdef HAL_I2C_MODULE_ENABLED ++ ++#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) ||\ ++ defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F411xE) || defined(STM32F446xx) ||\ ++ defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F413xx) || defined(STM32F423xx) ++/* Private typedef -----------------------------------------------------------*/ ++/* Private define ------------------------------------------------------------*/ ++/* Private macro -------------------------------------------------------------*/ ++/* Private variables ---------------------------------------------------------*/ ++/* Private function prototypes -----------------------------------------------*/ ++/* Exported functions --------------------------------------------------------*/ ++/** @defgroup I2CEx_Exported_Functions I2C Exported Functions ++ * @{ ++ */ ++ ++ ++/** @defgroup I2CEx_Exported_Functions_Group1 Extension features functions ++ * @brief Extension features functions ++ * ++@verbatim ++ =============================================================================== ++ ##### Extension features functions ##### ++ =============================================================================== ++ [..] This section provides functions allowing to: ++ (+) Configure Noise Filters ++ ++@endverbatim ++ * @{ ++ */ ++ ++/** ++ * @brief Configures I2C Analog noise filter. ++ * @param hi2c pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2Cx peripheral. ++ * @param AnalogFilter new state of the Analog filter. ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2CEx_ConfigAnalogFilter(I2C_HandleTypeDef *hi2c, uint32_t AnalogFilter) ++{ ++ /* Check the parameters */ ++ assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance)); ++ assert_param(IS_I2C_ANALOG_FILTER(AnalogFilter)); ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ hi2c->State = HAL_I2C_STATE_BUSY; ++ ++ /* Disable the selected I2C peripheral */ ++ __HAL_I2C_DISABLE(hi2c); ++ ++ /* Reset I2Cx ANOFF bit */ ++ hi2c->Instance->FLTR &= ~(I2C_FLTR_ANOFF); ++ ++ /* Disable the analog filter */ ++ hi2c->Instance->FLTR |= AnalogFilter; ++ ++ __HAL_I2C_ENABLE(hi2c); ++ ++ hi2c->State = HAL_I2C_STATE_READY; ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @brief Configures I2C Digital noise filter. ++ * @param hi2c pointer to a I2C_HandleTypeDef structure that contains ++ * the configuration information for the specified I2Cx peripheral. ++ * @param DigitalFilter Coefficient of digital noise filter between 0x00 and 0x0F. ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_I2CEx_ConfigDigitalFilter(I2C_HandleTypeDef *hi2c, uint32_t DigitalFilter) ++{ ++ uint16_t tmpreg = 0; ++ ++ /* Check the parameters */ ++ assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance)); ++ assert_param(IS_I2C_DIGITAL_FILTER(DigitalFilter)); ++ ++ if(hi2c->State == HAL_I2C_STATE_READY) ++ { ++ hi2c->State = HAL_I2C_STATE_BUSY; ++ ++ /* Disable the selected I2C peripheral */ ++ __HAL_I2C_DISABLE(hi2c); ++ ++ /* Get the old register value */ ++ tmpreg = hi2c->Instance->FLTR; ++ ++ /* Reset I2Cx DNF bit [3:0] */ ++ tmpreg &= ~(I2C_FLTR_DNF); ++ ++ /* Set I2Cx DNF coefficient */ ++ tmpreg |= DigitalFilter; ++ ++ /* Store the new register value */ ++ hi2c->Instance->FLTR = tmpreg; ++ ++ __HAL_I2C_ENABLE(hi2c); ++ ++ hi2c->State = HAL_I2C_STATE_READY; ++ ++ return HAL_OK; ++ } ++ else ++ { ++ return HAL_BUSY; ++ } ++} ++ ++/** ++ * @} ++ */ ++ ++/** ++ * @} ++ */ ++#endif /* STM32F427xx || STM32F429xx || STM32F437xx || STM32F439xx || STM32F401xC ||\ ++ STM32F401xE || STM32F446xx || STM32F469xx || STM32F479xx || STM32F413xx ||\ ++ STM32F423xx */ ++ ++#endif /* HAL_I2C_MODULE_ENABLED */ ++/** ++ * @} ++ */ ++ ++/** ++ * @} ++ */ ++ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +diff --git a/Firmware/Board/v3/Inc/i2c.h b/Firmware/Board/v3/Inc/i2c.h +new file mode 100644 +index 0000000..f449b88 +--- /dev/null ++++ b/Firmware/Board/v3/Inc/i2c.h +@@ -0,0 +1,91 @@ ++/** ++ ****************************************************************************** ++ * File Name : I2C.h ++ * Description : This file provides code for the configuration ++ * of the I2C instances. ++ ****************************************************************************** ++ * This notice applies to any and all portions of this file ++ * that are not between comment pairs USER CODE BEGIN and ++ * USER CODE END. Other portions of this file, whether ++ * inserted by the user or by software development tools ++ * are owned by their respective copyright owners. ++ * ++ * Copyright (c) 2018 STMicroelectronics International N.V. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted, provided that the following conditions are met: ++ * ++ * 1. Redistribution of source code must retain the above copyright notice, ++ * this list of conditions and the following disclaimer. ++ * 2. 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. ++ * 3. Neither the name of STMicroelectronics nor the names of other ++ * contributors to this software may be used to endorse or promote products ++ * derived from this software without specific written permission. ++ * 4. This software, including modifications and/or derivative works of this ++ * software, must execute solely and exclusively on microcontroller or ++ * microprocessor devices manufactured by or for STMicroelectronics. ++ * 5. Redistribution and use of this software other than as permitted under ++ * this license is void and will automatically terminate your rights under ++ * this license. ++ * ++ * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A ++ * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY ++ * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT ++ * SHALL STMICROELECTRONICS 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. ++ * ++ ****************************************************************************** ++ */ ++/* Define to prevent recursive inclusion -------------------------------------*/ ++#ifndef __i2c_H ++#define __i2c_H ++#ifdef __cplusplus ++ extern "C" { ++#endif ++ ++/* Includes ------------------------------------------------------------------*/ ++#include "stm32f4xx_hal.h" ++#include "main.h" ++ ++/* USER CODE BEGIN Includes */ ++ ++/* USER CODE END Includes */ ++ ++extern I2C_HandleTypeDef hi2c1; ++ ++/* USER CODE BEGIN Private defines */ ++ ++/* USER CODE END Private defines */ ++ ++extern void _Error_Handler(char *, int); ++ ++void MX_I2C1_Init(uint8_t addr); ++ ++/* USER CODE BEGIN Prototypes */ ++ ++/* USER CODE END Prototypes */ ++ ++#ifdef __cplusplus ++} ++#endif ++#endif /*__ i2c_H */ ++ ++/** ++ * @} ++ */ ++ ++/** ++ * @} ++ */ ++ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +diff --git a/Firmware/Board/v3/Inc/stm32f4xx_hal_conf.h b/Firmware/Board/v3/Inc/stm32f4xx_hal_conf.h +index d0f48f5..b3ef59a 100644 +--- a/Firmware/Board/v3/Inc/stm32f4xx_hal_conf.h ++++ b/Firmware/Board/v3/Inc/stm32f4xx_hal_conf.h +@@ -65,7 +65,7 @@ + /* #define HAL_SRAM_MODULE_ENABLED */ + /* #define HAL_SDRAM_MODULE_ENABLED */ + /* #define HAL_HASH_MODULE_ENABLED */ +-/* #define HAL_I2C_MODULE_ENABLED */ ++#define HAL_I2C_MODULE_ENABLED + /* #define HAL_I2S_MODULE_ENABLED */ + /* #define HAL_IWDG_MODULE_ENABLED */ + /* #define HAL_LTDC_MODULE_ENABLED */ +diff --git a/Firmware/Board/v3/Src/i2c.c b/Firmware/Board/v3/Src/i2c.c +new file mode 100644 +index 0000000..bae77f1 +--- /dev/null ++++ b/Firmware/Board/v3/Src/i2c.c +@@ -0,0 +1,198 @@ ++/** ++ ****************************************************************************** ++ * File Name : I2C.c ++ * Description : This file provides code for the configuration ++ * of the I2C instances. ++ ****************************************************************************** ++ * This notice applies to any and all portions of this file ++ * that are not between comment pairs USER CODE BEGIN and ++ * USER CODE END. Other portions of this file, whether ++ * inserted by the user or by software development tools ++ * are owned by their respective copyright owners. ++ * ++ * Copyright (c) 2018 STMicroelectronics International N.V. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted, provided that the following conditions are met: ++ * ++ * 1. Redistribution of source code must retain the above copyright notice, ++ * this list of conditions and the following disclaimer. ++ * 2. 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. ++ * 3. Neither the name of STMicroelectronics nor the names of other ++ * contributors to this software may be used to endorse or promote products ++ * derived from this software without specific written permission. ++ * 4. This software, including modifications and/or derivative works of this ++ * software, must execute solely and exclusively on microcontroller or ++ * microprocessor devices manufactured by or for STMicroelectronics. ++ * 5. Redistribution and use of this software other than as permitted under ++ * this license is void and will automatically terminate your rights under ++ * this license. ++ * ++ * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A ++ * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY ++ * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT ++ * SHALL STMICROELECTRONICS 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. ++ * ++ ****************************************************************************** ++ */ ++ ++/* Includes ------------------------------------------------------------------*/ ++#include "i2c.h" ++ ++#include "gpio.h" ++#include "dma.h" ++ ++/* USER CODE BEGIN 0 */ ++ ++/* USER CODE END 0 */ ++ ++I2C_HandleTypeDef hi2c1; ++DMA_HandleTypeDef hdma_i2c1_rx; ++DMA_HandleTypeDef hdma_i2c1_tx; ++ ++/* I2C1 init function */ ++void MX_I2C1_Init(uint8_t addr) ++{ ++ ++ hi2c1.Instance = I2C1; ++ hi2c1.Init.ClockSpeed = 100000; ++ hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; ++ hi2c1.Init.OwnAddress1 = addr << 1; ++ hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; ++ hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; ++ hi2c1.Init.OwnAddress2 = 0; ++ hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; ++ hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; ++ if (HAL_I2C_Init(&hi2c1) != HAL_OK) ++ { ++ _Error_Handler(__FILE__, __LINE__); ++ } ++ ++} ++ ++void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle) ++{ ++ ++ GPIO_InitTypeDef GPIO_InitStruct; ++ if(i2cHandle->Instance==I2C1) ++ { ++ /* USER CODE BEGIN I2C1_MspInit 0 */ ++ ++ /* USER CODE END I2C1_MspInit 0 */ ++ ++ /**I2C1 GPIO Configuration ++ PB8 ------> I2C1_SCL ++ PB9 ------> I2C1_SDA ++ */ ++ GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9; ++ GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; ++ GPIO_InitStruct.Pull = GPIO_PULLUP; ++ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; ++ GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; ++ HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); ++ ++ /* I2C1 clock enable */ ++ __HAL_RCC_I2C1_CLK_ENABLE(); ++ ++ /* I2C1 DMA Init */ ++ /* I2C1_RX Init */ ++ hdma_i2c1_rx.Instance = DMA1_Stream0; ++ hdma_i2c1_rx.Init.Channel = DMA_CHANNEL_1; ++ hdma_i2c1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; ++ hdma_i2c1_rx.Init.PeriphInc = DMA_PINC_DISABLE; ++ hdma_i2c1_rx.Init.MemInc = DMA_MINC_ENABLE; ++ hdma_i2c1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; ++ hdma_i2c1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; ++ hdma_i2c1_rx.Init.Mode = DMA_CIRCULAR; ++ hdma_i2c1_rx.Init.Priority = DMA_PRIORITY_LOW; ++ hdma_i2c1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; ++ if (HAL_DMA_Init(&hdma_i2c1_rx) != HAL_OK) ++ { ++ _Error_Handler(__FILE__, __LINE__); ++ } ++ ++ __HAL_LINKDMA(i2cHandle,hdmarx,hdma_i2c1_rx); ++ ++ /* I2C1_TX Init */ ++ hdma_i2c1_tx.Instance = DMA1_Stream6; ++ hdma_i2c1_tx.Init.Channel = DMA_CHANNEL_1; ++ hdma_i2c1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; ++ hdma_i2c1_tx.Init.PeriphInc = DMA_PINC_DISABLE; ++ hdma_i2c1_tx.Init.MemInc = DMA_MINC_ENABLE; ++ hdma_i2c1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; ++ hdma_i2c1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; ++ hdma_i2c1_tx.Init.Mode = DMA_NORMAL; ++ hdma_i2c1_tx.Init.Priority = DMA_PRIORITY_LOW; ++ hdma_i2c1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; ++ if (HAL_DMA_Init(&hdma_i2c1_tx) != HAL_OK) ++ { ++ _Error_Handler(__FILE__, __LINE__); ++ } ++ ++ __HAL_LINKDMA(i2cHandle,hdmatx,hdma_i2c1_tx); ++ ++ /* I2C1 interrupt Init */ ++ HAL_NVIC_SetPriority(I2C1_EV_IRQn, 5, 0); ++ HAL_NVIC_EnableIRQ(I2C1_EV_IRQn); ++ HAL_NVIC_SetPriority(I2C1_ER_IRQn, 5, 0); ++ HAL_NVIC_EnableIRQ(I2C1_ER_IRQn); ++ /* USER CODE BEGIN I2C1_MspInit 1 */ ++ ++ /* USER CODE END I2C1_MspInit 1 */ ++ } ++} ++ ++void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle) ++{ ++ ++ if(i2cHandle->Instance==I2C1) ++ { ++ /* USER CODE BEGIN I2C1_MspDeInit 0 */ ++ ++ /* USER CODE END I2C1_MspDeInit 0 */ ++ /* Peripheral clock disable */ ++ __HAL_RCC_I2C1_CLK_DISABLE(); ++ ++ /**I2C1 GPIO Configuration ++ PB8 ------> I2C1_SCL ++ PB9 ------> I2C1_SDA ++ */ ++ HAL_GPIO_DeInit(GPIOB, GPIO_PIN_8|GPIO_PIN_9); ++ ++ /* I2C1 DMA DeInit */ ++ HAL_DMA_DeInit(i2cHandle->hdmarx); ++ HAL_DMA_DeInit(i2cHandle->hdmatx); ++ ++ /* I2C1 interrupt Deinit */ ++ HAL_NVIC_DisableIRQ(I2C1_EV_IRQn); ++ HAL_NVIC_DisableIRQ(I2C1_ER_IRQn); ++ /* USER CODE BEGIN I2C1_MspDeInit 1 */ ++ ++ /* USER CODE END I2C1_MspDeInit 1 */ ++ } ++} ++ ++/* USER CODE BEGIN 1 */ ++ ++/* USER CODE END 1 */ ++ ++/** ++ * @} ++ */ ++ ++/** ++ * @} ++ */ ++ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +diff --git a/Firmware/Board/v3/Src/main.c b/Firmware/Board/v3/Src/main.c +index 987e0bd..efaeef1 100644 +--- a/Firmware/Board/v3/Src/main.c ++++ b/Firmware/Board/v3/Src/main.c +@@ -187,7 +187,6 @@ int main(void) + MX_ADC3_Init(); + MX_TIM2_Init(); + MX_UART4_Init(); +- MX_CAN1_Init(); + /* USER CODE BEGIN 2 */ + + //Required to use OC4 for ADC triggering. +-- +2.17.0 + diff --git a/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c.h b/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c.h new file mode 100644 index 00000000..5452a507 --- /dev/null +++ b/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c.h @@ -0,0 +1,649 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_i2c.h + * @author MCD Application Team + * @brief Header file of I2C HAL module. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_I2C_H +#define __STM32F4xx_HAL_I2C_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal_def.h" + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @addtogroup I2C + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup I2C_Exported_Types I2C Exported Types + * @{ + */ + +/** + * @brief I2C Configuration Structure definition + */ +typedef struct +{ + uint32_t ClockSpeed; /*!< Specifies the clock frequency. + This parameter must be set to a value lower than 400kHz */ + + uint32_t DutyCycle; /*!< Specifies the I2C fast mode duty cycle. + This parameter can be a value of @ref I2C_duty_cycle_in_fast_mode */ + + uint32_t OwnAddress1; /*!< Specifies the first device own address. + This parameter can be a 7-bit or 10-bit address. */ + + uint32_t AddressingMode; /*!< Specifies if 7-bit or 10-bit addressing mode is selected. + This parameter can be a value of @ref I2C_addressing_mode */ + + uint32_t DualAddressMode; /*!< Specifies if dual addressing mode is selected. + This parameter can be a value of @ref I2C_dual_addressing_mode */ + + uint32_t OwnAddress2; /*!< Specifies the second device own address if dual addressing mode is selected + This parameter can be a 7-bit address. */ + + uint32_t GeneralCallMode; /*!< Specifies if general call mode is selected. + This parameter can be a value of @ref I2C_general_call_addressing_mode */ + + uint32_t NoStretchMode; /*!< Specifies if nostretch mode is selected. + This parameter can be a value of @ref I2C_nostretch_mode */ + +}I2C_InitTypeDef; + +/** + * @brief HAL State structure definition + * @note HAL I2C State value coding follow below described bitmap : + * b7-b6 Error information + * 00 : No Error + * 01 : Abort (Abort user request on going) + * 10 : Timeout + * 11 : Error + * b5 IP initilisation status + * 0 : Reset (IP not initialized) + * 1 : Init done (IP initialized and ready to use. HAL I2C Init function called) + * b4 (not used) + * x : Should be set to 0 + * b3 + * 0 : Ready or Busy (No Listen mode ongoing) + * 1 : Listen (IP in Address Listen Mode) + * b2 Intrinsic process state + * 0 : Ready + * 1 : Busy (IP busy with some configuration or internal operations) + * b1 Rx state + * 0 : Ready (no Rx operation ongoing) + * 1 : Busy (Rx operation ongoing) + * b0 Tx state + * 0 : Ready (no Tx operation ongoing) + * 1 : Busy (Tx operation ongoing) + */ +typedef enum +{ + HAL_I2C_STATE_RESET = 0x00U, /*!< Peripheral is not yet Initialized */ + HAL_I2C_STATE_READY = 0x20U, /*!< Peripheral Initialized and ready for use */ + HAL_I2C_STATE_BUSY = 0x24U, /*!< An internal process is ongoing */ + HAL_I2C_STATE_BUSY_TX = 0x21U, /*!< Data Transmission process is ongoing */ + HAL_I2C_STATE_BUSY_RX = 0x22U, /*!< Data Reception process is ongoing */ + HAL_I2C_STATE_LISTEN = 0x28U, /*!< Address Listen Mode is ongoing */ + HAL_I2C_STATE_BUSY_TX_LISTEN = 0x29U, /*!< Address Listen Mode and Data Transmission + process is ongoing */ + HAL_I2C_STATE_BUSY_RX_LISTEN = 0x2AU, /*!< Address Listen Mode and Data Reception + process is ongoing */ + HAL_I2C_STATE_ABORT = 0x60U, /*!< Abort user request ongoing */ + HAL_I2C_STATE_TIMEOUT = 0xA0U, /*!< Timeout state */ + HAL_I2C_STATE_ERROR = 0xE0U /*!< Error */ + +}HAL_I2C_StateTypeDef; + +/** + * @brief HAL Mode structure definition + * @note HAL I2C Mode value coding follow below described bitmap : + * b7 (not used) + * x : Should be set to 0 + * b6 + * 0 : None + * 1 : Memory (HAL I2C communication is in Memory Mode) + * b5 + * 0 : None + * 1 : Slave (HAL I2C communication is in Slave Mode) + * b4 + * 0 : None + * 1 : Master (HAL I2C communication is in Master Mode) + * b3-b2-b1-b0 (not used) + * xxxx : Should be set to 0000 + */ +typedef enum +{ + HAL_I2C_MODE_NONE = 0x00U, /*!< No I2C communication on going */ + HAL_I2C_MODE_MASTER = 0x10U, /*!< I2C communication is in Master Mode */ + HAL_I2C_MODE_SLAVE = 0x20U, /*!< I2C communication is in Slave Mode */ + HAL_I2C_MODE_MEM = 0x40U /*!< I2C communication is in Memory Mode */ + +}HAL_I2C_ModeTypeDef; + +/** + * @brief I2C handle Structure definition + */ +typedef struct +{ + I2C_TypeDef *Instance; /*!< I2C registers base address */ + + I2C_InitTypeDef Init; /*!< I2C communication parameters */ + + uint8_t *pBuffPtr; /*!< Pointer to I2C transfer buffer */ + + uint16_t XferSize; /*!< I2C transfer size */ + + __IO uint16_t XferCount; /*!< I2C transfer counter */ + + __IO uint32_t XferOptions; /*!< I2C transfer options */ + + __IO uint32_t PreviousState; /*!< I2C communication Previous state and mode + context for internal usage */ + + DMA_HandleTypeDef *hdmatx; /*!< I2C Tx DMA handle parameters */ + + DMA_HandleTypeDef *hdmarx; /*!< I2C Rx DMA handle parameters */ + + HAL_LockTypeDef Lock; /*!< I2C locking object */ + + __IO HAL_I2C_StateTypeDef State; /*!< I2C communication state */ + + __IO HAL_I2C_ModeTypeDef Mode; /*!< I2C communication mode */ + + __IO uint32_t ErrorCode; /*!< I2C Error code */ + + __IO uint32_t Devaddress; /*!< I2C Target device address */ + + __IO uint32_t Memaddress; /*!< I2C Target memory address */ + + __IO uint32_t MemaddSize; /*!< I2C Target memory address size */ + + __IO uint32_t EventCount; /*!< I2C Event counter */ + +}I2C_HandleTypeDef; + +/** + * @} + */ + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup I2C_Exported_Constants I2C Exported Constants + * @{ + */ + +/** @defgroup I2C_Error_Code I2C Error Code + * @brief I2C Error Code + * @{ + */ +#define HAL_I2C_ERROR_NONE 0x00000000U /*!< No error */ +#define HAL_I2C_ERROR_BERR 0x00000001U /*!< BERR error */ +#define HAL_I2C_ERROR_ARLO 0x00000002U /*!< ARLO error */ +#define HAL_I2C_ERROR_AF 0x00000004U /*!< AF error */ +#define HAL_I2C_ERROR_OVR 0x00000008U /*!< OVR error */ +#define HAL_I2C_ERROR_DMA 0x00000010U /*!< DMA transfer error */ +#define HAL_I2C_ERROR_TIMEOUT 0x00000020U /*!< Timeout Error */ +/** + * @} + */ + +/** @defgroup I2C_duty_cycle_in_fast_mode I2C duty cycle in fast mode + * @{ + */ +#define I2C_DUTYCYCLE_2 0x00000000U +#define I2C_DUTYCYCLE_16_9 I2C_CCR_DUTY +/** + * @} + */ + +/** @defgroup I2C_addressing_mode I2C addressing mode + * @{ + */ +#define I2C_ADDRESSINGMODE_7BIT 0x00004000U +#define I2C_ADDRESSINGMODE_10BIT (I2C_OAR1_ADDMODE | 0x00004000U) +/** + * @} + */ + +/** @defgroup I2C_dual_addressing_mode I2C dual addressing mode + * @{ + */ +#define I2C_DUALADDRESS_DISABLE 0x00000000U +#define I2C_DUALADDRESS_ENABLE I2C_OAR2_ENDUAL +/** + * @} + */ + +/** @defgroup I2C_general_call_addressing_mode I2C general call addressing mode + * @{ + */ +#define I2C_GENERALCALL_DISABLE 0x00000000U +#define I2C_GENERALCALL_ENABLE I2C_CR1_ENGC +/** + * @} + */ + +/** @defgroup I2C_nostretch_mode I2C nostretch mode + * @{ + */ +#define I2C_NOSTRETCH_DISABLE 0x00000000U +#define I2C_NOSTRETCH_ENABLE I2C_CR1_NOSTRETCH +/** + * @} + */ + +/** @defgroup I2C_Memory_Address_Size I2C Memory Address Size + * @{ + */ +#define I2C_MEMADD_SIZE_8BIT 0x00000001U +#define I2C_MEMADD_SIZE_16BIT 0x00000010U +/** + * @} + */ + +/** @defgroup I2C_XferDirection_definition I2C XferDirection definition + * @{ + */ +#define I2C_DIRECTION_RECEIVE 0x00000000U +#define I2C_DIRECTION_TRANSMIT 0x00000001U +/** + * @} + */ + +/** @defgroup I2C_XferOptions_definition I2C XferOptions definition + * @{ + */ +#define I2C_FIRST_FRAME 0x00000001U +#define I2C_NEXT_FRAME 0x00000002U +#define I2C_FIRST_AND_LAST_FRAME 0x00000004U +#define I2C_LAST_FRAME 0x00000008U +/** + * @} + */ + +/** @defgroup I2C_Interrupt_configuration_definition I2C Interrupt configuration definition + * @{ + */ +#define I2C_IT_BUF I2C_CR2_ITBUFEN +#define I2C_IT_EVT I2C_CR2_ITEVTEN +#define I2C_IT_ERR I2C_CR2_ITERREN +/** + * @} + */ + +/** @defgroup I2C_Flag_definition I2C Flag definition + * @{ + */ +#define I2C_FLAG_SMBALERT 0x00018000U +#define I2C_FLAG_TIMEOUT 0x00014000U +#define I2C_FLAG_PECERR 0x00011000U +#define I2C_FLAG_OVR 0x00010800U +#define I2C_FLAG_AF 0x00010400U +#define I2C_FLAG_ARLO 0x00010200U +#define I2C_FLAG_BERR 0x00010100U +#define I2C_FLAG_TXE 0x00010080U +#define I2C_FLAG_RXNE 0x00010040U +#define I2C_FLAG_STOPF 0x00010010U +#define I2C_FLAG_ADD10 0x00010008U +#define I2C_FLAG_BTF 0x00010004U +#define I2C_FLAG_ADDR 0x00010002U +#define I2C_FLAG_SB 0x00010001U +#define I2C_FLAG_DUALF 0x00100080U +#define I2C_FLAG_SMBHOST 0x00100040U +#define I2C_FLAG_SMBDEFAULT 0x00100020U +#define I2C_FLAG_GENCALL 0x00100010U +#define I2C_FLAG_TRA 0x00100004U +#define I2C_FLAG_BUSY 0x00100002U +#define I2C_FLAG_MSL 0x00100001U +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/** @defgroup I2C_Exported_Macros I2C Exported Macros + * @{ + */ + +/** @brief Reset I2C handle state + * @param __HANDLE__ specifies the I2C Handle. + * This parameter can be I2C where x: 1, 2, or 3 to select the I2C peripheral. + * @retval None + */ +#define __HAL_I2C_RESET_HANDLE_STATE(__HANDLE__) ((__HANDLE__)->State = HAL_I2C_STATE_RESET) + +/** @brief Enable or disable the specified I2C interrupts. + * @param __HANDLE__ specifies the I2C Handle. + * This parameter can be I2C where x: 1, 2, or 3 to select the I2C peripheral. + * @param __INTERRUPT__ specifies the interrupt source to enable or disable. + * This parameter can be one of the following values: + * @arg I2C_IT_BUF: Buffer interrupt enable + * @arg I2C_IT_EVT: Event interrupt enable + * @arg I2C_IT_ERR: Error interrupt enable + * @retval None + */ +#define __HAL_I2C_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->CR2 |= (__INTERRUPT__)) +#define __HAL_I2C_DISABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->CR2 &= (~(__INTERRUPT__))) + +/** @brief Checks if the specified I2C interrupt source is enabled or disabled. + * @param __HANDLE__ specifies the I2C Handle. + * This parameter can be I2C where x: 1, 2, or 3 to select the I2C peripheral. + * @param __INTERRUPT__ specifies the I2C interrupt source to check. + * This parameter can be one of the following values: + * @arg I2C_IT_BUF: Buffer interrupt enable + * @arg I2C_IT_EVT: Event interrupt enable + * @arg I2C_IT_ERR: Error interrupt enable + * @retval The new state of __INTERRUPT__ (TRUE or FALSE). + */ +#define __HAL_I2C_GET_IT_SOURCE(__HANDLE__, __INTERRUPT__) ((((__HANDLE__)->Instance->CR2 & (__INTERRUPT__)) == (__INTERRUPT__)) ? SET : RESET) + +/** @brief Checks whether the specified I2C flag is set or not. + * @param __HANDLE__ specifies the I2C Handle. + * This parameter can be I2C where x: 1, 2, or 3 to select the I2C peripheral. + * @param __FLAG__ specifies the flag to check. + * This parameter can be one of the following values: + * @arg I2C_FLAG_SMBALERT: SMBus Alert flag + * @arg I2C_FLAG_TIMEOUT: Timeout or Tlow error flag + * @arg I2C_FLAG_PECERR: PEC error in reception flag + * @arg I2C_FLAG_OVR: Overrun/Underrun flag + * @arg I2C_FLAG_AF: Acknowledge failure flag + * @arg I2C_FLAG_ARLO: Arbitration lost flag + * @arg I2C_FLAG_BERR: Bus error flag + * @arg I2C_FLAG_TXE: Data register empty flag + * @arg I2C_FLAG_RXNE: Data register not empty flag + * @arg I2C_FLAG_STOPF: Stop detection flag + * @arg I2C_FLAG_ADD10: 10-bit header sent flag + * @arg I2C_FLAG_BTF: Byte transfer finished flag + * @arg I2C_FLAG_ADDR: Address sent flag + * Address matched flag + * @arg I2C_FLAG_SB: Start bit flag + * @arg I2C_FLAG_DUALF: Dual flag + * @arg I2C_FLAG_SMBHOST: SMBus host header + * @arg I2C_FLAG_SMBDEFAULT: SMBus default header + * @arg I2C_FLAG_GENCALL: General call header flag + * @arg I2C_FLAG_TRA: Transmitter/Receiver flag + * @arg I2C_FLAG_BUSY: Bus busy flag + * @arg I2C_FLAG_MSL: Master/Slave flag + * @retval The new state of __FLAG__ (TRUE or FALSE). + */ +#define __HAL_I2C_GET_FLAG(__HANDLE__, __FLAG__) ((((uint8_t)((__FLAG__) >> 16U)) == 0x01U)?((((__HANDLE__)->Instance->SR1) & ((__FLAG__) & I2C_FLAG_MASK)) == ((__FLAG__) & I2C_FLAG_MASK)): \ + ((((__HANDLE__)->Instance->SR2) & ((__FLAG__) & I2C_FLAG_MASK)) == ((__FLAG__) & I2C_FLAG_MASK))) + +/** @brief Clears the I2C pending flags which are cleared by writing 0 in a specific bit. + * @param __HANDLE__ specifies the I2C Handle. + * This parameter can be I2C where x: 1, 2, or 3 to select the I2C peripheral. + * @param __FLAG__ specifies the flag to clear. + * This parameter can be any combination of the following values: + * @arg I2C_FLAG_SMBALERT: SMBus Alert flag + * @arg I2C_FLAG_TIMEOUT: Timeout or Tlow error flag + * @arg I2C_FLAG_PECERR: PEC error in reception flag + * @arg I2C_FLAG_OVR: Overrun/Underrun flag (Slave mode) + * @arg I2C_FLAG_AF: Acknowledge failure flag + * @arg I2C_FLAG_ARLO: Arbitration lost flag (Master mode) + * @arg I2C_FLAG_BERR: Bus error flag + * @retval None + */ +#define __HAL_I2C_CLEAR_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->Instance->SR1 = ~((__FLAG__) & I2C_FLAG_MASK)) + +/** @brief Clears the I2C ADDR pending flag. + * @param __HANDLE__ specifies the I2C Handle. + * This parameter can be I2C where x: 1, 2, or 3 to select the I2C peripheral. + * @retval None + */ +#define __HAL_I2C_CLEAR_ADDRFLAG(__HANDLE__) \ + do{ \ + __IO uint32_t tmpreg = 0x00U; \ + tmpreg = (__HANDLE__)->Instance->SR1; \ + tmpreg = (__HANDLE__)->Instance->SR2; \ + UNUSED(tmpreg); \ + } while(0) + +/** @brief Clears the I2C STOPF pending flag. + * @param __HANDLE__ specifies the I2C Handle. + * This parameter can be I2C where x: 1, 2, or 3 to select the I2C peripheral. + * @retval None + */ +#define __HAL_I2C_CLEAR_STOPFLAG(__HANDLE__) \ + do{ \ + __IO uint32_t tmpreg = 0x00U; \ + tmpreg = (__HANDLE__)->Instance->SR1; \ + (__HANDLE__)->Instance->CR1 |= I2C_CR1_PE; \ + UNUSED(tmpreg); \ + } while(0) + +/** @brief Enable the I2C peripheral. + * @param __HANDLE__ specifies the I2C Handle. + * This parameter can be I2Cx where x: 1 or 2 to select the I2C peripheral. + * @retval None + */ +#define __HAL_I2C_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->CR1 |= I2C_CR1_PE) + +/** @brief Disable the I2C peripheral. + * @param __HANDLE__ specifies the I2C Handle. + * This parameter can be I2Cx where x: 1 or 2 to select the I2C peripheral. + * @retval None + */ +#define __HAL_I2C_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->CR1 &= ~I2C_CR1_PE) + +/** + * @} + */ + +/* Include I2C HAL Extension module */ +#include "stm32f4xx_hal_i2c_ex.h" + +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup I2C_Exported_Functions + * @{ + */ + +/** @addtogroup I2C_Exported_Functions_Group1 + * @{ + */ +/* Initialization/de-initialization functions **********************************/ +HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c); +HAL_StatusTypeDef HAL_I2C_DeInit (I2C_HandleTypeDef *hi2c); +void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c); +void HAL_I2C_MspDeInit(I2C_HandleTypeDef *hi2c); +/** + * @} + */ + +/** @addtogroup I2C_Exported_Functions_Group2 + * @{ + */ +/* I/O operation functions *****************************************************/ +/******* Blocking mode: Polling */ +HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout); +HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout); +HAL_StatusTypeDef HAL_I2C_Slave_Transmit(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout); +HAL_StatusTypeDef HAL_I2C_Slave_Receive(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout); +HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout); +HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout); +HAL_StatusTypeDef HAL_I2C_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout); + +/******* Non-Blocking mode: Interrupt */ +HAL_StatusTypeDef HAL_I2C_Master_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Master_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Slave_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Slave_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Mem_Write_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Mem_Read_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size); + +HAL_StatusTypeDef HAL_I2C_Master_Sequential_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions); +HAL_StatusTypeDef HAL_I2C_Master_Sequential_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions); +HAL_StatusTypeDef HAL_I2C_Slave_Sequential_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions); +HAL_StatusTypeDef HAL_I2C_Slave_Sequential_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions); +HAL_StatusTypeDef HAL_I2C_Master_Abort_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress); +HAL_StatusTypeDef HAL_I2C_EnableListen_IT(I2C_HandleTypeDef *hi2c); +HAL_StatusTypeDef HAL_I2C_DisableListen_IT(I2C_HandleTypeDef *hi2c); + +/******* Non-Blocking mode: DMA */ +HAL_StatusTypeDef HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Master_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Slave_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Slave_Receive_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Mem_Write_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Mem_Read_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size); + +/******* I2C IRQHandler and Callbacks used in non blocking modes (Interrupt and DMA) */ +void HAL_I2C_EV_IRQHandler(I2C_HandleTypeDef *hi2c); +void HAL_I2C_ER_IRQHandler(I2C_HandleTypeDef *hi2c); +void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c); +void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c); +void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c); +void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c); +void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode); +void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c); +void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c); +void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c); +void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c); +void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c); +/** + * @} + */ + +/** @addtogroup I2C_Exported_Functions_Group3 + * @{ + */ +/* Peripheral State, Mode and Errors functions *********************************/ +HAL_I2C_StateTypeDef HAL_I2C_GetState(I2C_HandleTypeDef *hi2c); +HAL_I2C_ModeTypeDef HAL_I2C_GetMode(I2C_HandleTypeDef *hi2c); +uint32_t HAL_I2C_GetError(I2C_HandleTypeDef *hi2c); + +/** + * @} + */ + +/** + * @} + */ +/* Private types -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private constants ---------------------------------------------------------*/ +/** @defgroup I2C_Private_Constants I2C Private Constants + * @{ + */ +#define I2C_FLAG_MASK 0x0000FFFFU +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/** @defgroup I2C_Private_Macros I2C Private Macros + * @{ + */ + +#define I2C_FREQRANGE(__PCLK__) ((__PCLK__)/1000000U) +#define I2C_RISE_TIME(__FREQRANGE__, __SPEED__) (((__SPEED__) <= 100000U) ? ((__FREQRANGE__) + 1U) : ((((__FREQRANGE__) * 300U) / 1000U) + 1U)) +#define I2C_SPEED_STANDARD(__PCLK__, __SPEED__) (((((__PCLK__)/((__SPEED__) << 1U)) & I2C_CCR_CCR) < 4U)? 4U:((__PCLK__) / ((__SPEED__) << 1U))) +#define I2C_SPEED_FAST(__PCLK__, __SPEED__, __DUTYCYCLE__) (((__DUTYCYCLE__) == I2C_DUTYCYCLE_2)? ((__PCLK__) / ((__SPEED__) * 3U)) : (((__PCLK__) / ((__SPEED__) * 25U)) | I2C_DUTYCYCLE_16_9)) +#define I2C_SPEED(__PCLK__, __SPEED__, __DUTYCYCLE__) (((__SPEED__) <= 100000U)? (I2C_SPEED_STANDARD((__PCLK__), (__SPEED__))) : \ + ((I2C_SPEED_FAST((__PCLK__), (__SPEED__), (__DUTYCYCLE__)) & I2C_CCR_CCR) == 0U)? 1U : \ + ((I2C_SPEED_FAST((__PCLK__), (__SPEED__), (__DUTYCYCLE__))) | I2C_CCR_FS)) + +#define I2C_7BIT_ADD_WRITE(__ADDRESS__) ((uint8_t)((__ADDRESS__) & (~I2C_OAR1_ADD0))) +#define I2C_7BIT_ADD_READ(__ADDRESS__) ((uint8_t)((__ADDRESS__) | I2C_OAR1_ADD0)) + +#define I2C_10BIT_ADDRESS(__ADDRESS__) ((uint8_t)((uint16_t)((__ADDRESS__) & (uint16_t)0x00FF))) +#define I2C_10BIT_HEADER_WRITE(__ADDRESS__) ((uint8_t)((uint16_t)((uint16_t)(((uint16_t)((__ADDRESS__) & (uint16_t)0x0300)) >> 7) | (uint16_t)0x00F0))) +#define I2C_10BIT_HEADER_READ(__ADDRESS__) ((uint8_t)((uint16_t)((uint16_t)(((uint16_t)((__ADDRESS__) & (uint16_t)0x0300)) >> 7) | (uint16_t)(0x00F1)))) + +#define I2C_MEM_ADD_MSB(__ADDRESS__) ((uint8_t)((uint16_t)(((uint16_t)((__ADDRESS__) & (uint16_t)0xFF00)) >> 8))) +#define I2C_MEM_ADD_LSB(__ADDRESS__) ((uint8_t)((uint16_t)((__ADDRESS__) & (uint16_t)0x00FF))) + +/** @defgroup I2C_IS_RTC_Definitions I2C Private macros to check input parameters + * @{ + */ +#define IS_I2C_DUTY_CYCLE(CYCLE) (((CYCLE) == I2C_DUTYCYCLE_2) || \ + ((CYCLE) == I2C_DUTYCYCLE_16_9)) +#define IS_I2C_ADDRESSING_MODE(ADDRESS) (((ADDRESS) == I2C_ADDRESSINGMODE_7BIT) || \ + ((ADDRESS) == I2C_ADDRESSINGMODE_10BIT)) +#define IS_I2C_DUAL_ADDRESS(ADDRESS) (((ADDRESS) == I2C_DUALADDRESS_DISABLE) || \ + ((ADDRESS) == I2C_DUALADDRESS_ENABLE)) +#define IS_I2C_GENERAL_CALL(CALL) (((CALL) == I2C_GENERALCALL_DISABLE) || \ + ((CALL) == I2C_GENERALCALL_ENABLE)) +#define IS_I2C_NO_STRETCH(STRETCH) (((STRETCH) == I2C_NOSTRETCH_DISABLE) || \ + ((STRETCH) == I2C_NOSTRETCH_ENABLE)) +#define IS_I2C_MEMADD_SIZE(SIZE) (((SIZE) == I2C_MEMADD_SIZE_8BIT) || \ + ((SIZE) == I2C_MEMADD_SIZE_16BIT)) +#define IS_I2C_CLOCK_SPEED(SPEED) (((SPEED) > 0U) && ((SPEED) <= 400000U)) +#define IS_I2C_OWN_ADDRESS1(ADDRESS1) (((ADDRESS1) & 0xFFFFFC00U) == 0U) +#define IS_I2C_OWN_ADDRESS2(ADDRESS2) (((ADDRESS2) & 0xFFFFFF01U) == 0U) +#define IS_I2C_TRANSFER_OPTIONS_REQUEST(REQUEST) (((REQUEST) == I2C_FIRST_FRAME) || \ + ((REQUEST) == I2C_NEXT_FRAME) || \ + ((REQUEST) == I2C_FIRST_AND_LAST_FRAME) || \ + ((REQUEST) == I2C_LAST_FRAME)) +/** + * @} + */ + +/** + * @} + */ + +/* Private functions ---------------------------------------------------------*/ +/** @defgroup I2C_Private_Functions I2C Private Functions + * @{ + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + + +#endif /* __STM32F4xx_HAL_I2C_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c_ex.h b/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c_ex.h new file mode 100644 index 00000000..ff47d5cc --- /dev/null +++ b/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c_ex.h @@ -0,0 +1,137 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_i2c_ex.h + * @author MCD Application Team + * @brief Header file of I2C HAL Extension module. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_I2C_EX_H +#define __STM32F4xx_HAL_I2C_EX_H + +#ifdef __cplusplus + extern "C" { +#endif + +#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) ||\ + defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F411xE) || defined(STM32F446xx) ||\ + defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F413xx) || defined(STM32F423xx) +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal_def.h" + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @addtogroup I2CEx + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/** @defgroup I2CEx_Exported_Constants I2C Exported Constants + * @{ + */ + +/** @defgroup I2CEx_Analog_Filter I2C Analog Filter + * @{ + */ +#define I2C_ANALOGFILTER_ENABLE 0x00000000U +#define I2C_ANALOGFILTER_DISABLE I2C_FLTR_ANOFF +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup I2CEx_Exported_Functions + * @{ + */ + +/** @addtogroup I2CEx_Exported_Functions_Group1 + * @{ + */ +/* Peripheral Control functions ************************************************/ +HAL_StatusTypeDef HAL_I2CEx_ConfigAnalogFilter(I2C_HandleTypeDef *hi2c, uint32_t AnalogFilter); +HAL_StatusTypeDef HAL_I2CEx_ConfigDigitalFilter(I2C_HandleTypeDef *hi2c, uint32_t DigitalFilter); +/** + * @} + */ + +/** + * @} + */ +/* Private types -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private constants ---------------------------------------------------------*/ +/** @defgroup I2CEx_Private_Constants I2C Private Constants + * @{ + */ + +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/** @defgroup I2CEx_Private_Macros I2C Private Macros + * @{ + */ +#define IS_I2C_ANALOG_FILTER(FILTER) (((FILTER) == I2C_ANALOGFILTER_ENABLE) || \ + ((FILTER) == I2C_ANALOGFILTER_DISABLE)) +#define IS_I2C_DIGITAL_FILTER(FILTER) ((FILTER) <= 0x0000000FU) +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#endif /* STM32F427xx || STM32F429xx || STM32F437xx || STM32F439xx || STM32F401xC ||\ + STM32F401xE || STM32F411xE || STM32F446xx || STM32F469xx || STM32F479xx ||\ + STM32F413xx || STM32F423xx */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_I2C_EX_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c b/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c new file mode 100644 index 00000000..da185200 --- /dev/null +++ b/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c @@ -0,0 +1,5494 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_i2c.c + * @author MCD Application Team + * @brief I2C HAL module driver. + * This file provides firmware functions to manage the following + * functionalities of the Inter Integrated Circuit (I2C) peripheral: + * + Initialization and de-initialization functions + * + IO operation functions + * + Peripheral State, Mode and Error functions + * + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + The I2C HAL driver can be used as follows: + + (#) Declare a I2C_HandleTypeDef handle structure, for example: + I2C_HandleTypeDef hi2c; + + (#)Initialize the I2C low level resources by implementing the HAL_I2C_MspInit() API: + (##) Enable the I2Cx interface clock + (##) I2C pins configuration + (+++) Enable the clock for the I2C GPIOs + (+++) Configure I2C pins as alternate function open-drain + (##) NVIC configuration if you need to use interrupt process + (+++) Configure the I2Cx interrupt priority + (+++) Enable the NVIC I2C IRQ Channel + (##) DMA Configuration if you need to use DMA process + (+++) Declare a DMA_HandleTypeDef handle structure for the transmit or receive stream + (+++) Enable the DMAx interface clock using + (+++) Configure the DMA handle parameters + (+++) Configure the DMA Tx or Rx Stream + (+++) Associate the initialized DMA handle to the hi2c DMA Tx or Rx handle + (+++) Configure the priority and enable the NVIC for the transfer complete interrupt on + the DMA Tx or Rx Stream + + (#) Configure the Communication Speed, Duty cycle, Addressing mode, Own Address1, + Dual Addressing mode, Own Address2, General call and Nostretch mode in the hi2c Init structure. + + (#) Initialize the I2C registers by calling the HAL_I2C_Init(), configures also the low level Hardware + (GPIO, CLOCK, NVIC...etc) by calling the customized HAL_I2C_MspInit(&hi2c) API. + + (#) To check if target device is ready for communication, use the function HAL_I2C_IsDeviceReady() + + (#) For I2C IO and IO MEM operations, three operation modes are available within this driver : + + *** Polling mode IO operation *** + ================================= + [..] + (+) Transmit in master mode an amount of data in blocking mode using HAL_I2C_Master_Transmit() + (+) Receive in master mode an amount of data in blocking mode using HAL_I2C_Master_Receive() + (+) Transmit in slave mode an amount of data in blocking mode using HAL_I2C_Slave_Transmit() + (+) Receive in slave mode an amount of data in blocking mode using HAL_I2C_Slave_Receive() + + *** Polling mode IO MEM operation *** + ===================================== + [..] + (+) Write an amount of data in blocking mode to a specific memory address using HAL_I2C_Mem_Write() + (+) Read an amount of data in blocking mode from a specific memory address using HAL_I2C_Mem_Read() + + + *** Interrupt mode IO operation *** + =================================== + [..] + (+) Transmit in master mode an amount of data in non blocking mode using HAL_I2C_Master_Transmit_IT() + (+) At transmission end of transfer HAL_I2C_MasterTxCpltCallback is executed and user can + add his own code by customization of function pointer HAL_I2C_MasterTxCpltCallback + (+) Receive in master mode an amount of data in non blocking mode using HAL_I2C_Master_Receive_IT() + (+) At reception end of transfer HAL_I2C_MasterRxCpltCallback is executed and user can + add his own code by customization of function pointer HAL_I2C_MasterRxCpltCallback + (+) Transmit in slave mode an amount of data in non blocking mode using HAL_I2C_Slave_Transmit_IT() + (+) At transmission end of transfer HAL_I2C_SlaveTxCpltCallback is executed and user can + add his own code by customization of function pointer HAL_I2C_SlaveTxCpltCallback + (+) Receive in slave mode an amount of data in non blocking mode using HAL_I2C_Slave_Receive_IT() + (+) At reception end of transfer HAL_I2C_SlaveRxCpltCallback is executed and user can + add his own code by customization of function pointer HAL_I2C_SlaveRxCpltCallback + (+) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and user can + add his own code by customization of function pointer HAL_I2C_ErrorCallback + (+) Abort a master I2C process communication with Interrupt using HAL_I2C_Master_Abort_IT() + (+) End of abort process, HAL_I2C_AbortCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_AbortCpltCallback() + + *** Interrupt mode IO sequential operation *** + ============================================== + [..] + (@) These interfaces allow to manage a sequential transfer with a repeated start condition + when a direction change during transfer + [..] + (+) A specific option field manage the different steps of a sequential transfer + (+) Option field values are defined through @ref I2C_XFEROPTIONS and are listed below: + (++) I2C_FIRST_AND_LAST_FRAME: No sequential usage, functionnal is same as associated interfaces in no sequential mode + (++) I2C_FIRST_FRAME: Sequential usage, this option allow to manage a sequence with start condition, address + and data to transfer without a final stop condition + (++) I2C_NEXT_FRAME: Sequential usage, this option allow to manage a sequence with a restart condition, address + and with new data to transfer if the direction change or manage only the new data to transfer + if no direction change and without a final stop condition in both cases + (++) I2C_LAST_FRAME: Sequential usage, this option allow to manage a sequance with a restart condition, address + and with new data to transfer if the direction change or manage only the new data to transfer + if no direction change and with a final stop condition in both cases + + (+) Differents sequential I2C interfaces are listed below: + (++) Sequential transmit in master I2C mode an amount of data in non-blocking mode using HAL_I2C_Master_Sequential_Transmit_IT() + (+++) At transmission end of current frame transfer, HAL_I2C_MasterTxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_MasterTxCpltCallback() + (++) Sequential receive in master I2C mode an amount of data in non-blocking mode using HAL_I2C_Master_Sequential_Receive_IT() + (+++) At reception end of current frame transfer, HAL_I2C_MasterRxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_MasterRxCpltCallback() + (++) Abort a master I2C process communication with Interrupt using HAL_I2C_Master_Abort_IT() + (+++) End of abort process, HAL_I2C_AbortCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_AbortCpltCallback() + (++) Enable/disable the Address listen mode in slave I2C mode using HAL_I2C_EnableListen_IT() HAL_I2C_DisableListen_IT() + (+++) When address slave I2C match, HAL_I2C_AddrCallback() is executed and user can + add his own code to check the Address Match Code and the transmission direction request by master (Write/Read). + (+++) At Listen mode end HAL_I2C_ListenCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_ListenCpltCallback() + (++) Sequential transmit in slave I2C mode an amount of data in non-blocking mode using HAL_I2C_Slave_Sequential_Transmit_IT() + (+++) At transmission end of current frame transfer, HAL_I2C_SlaveTxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_SlaveTxCpltCallback() + (++) Sequential receive in slave I2C mode an amount of data in non-blocking mode using HAL_I2C_Slave_Sequential_Receive_IT() + (+++) At reception end of current frame transfer, HAL_I2C_SlaveRxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_SlaveRxCpltCallback() + (++) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and user can + add his own code by customization of function pointer HAL_I2C_ErrorCallback() + (++) Abort a master I2C process communication with Interrupt using HAL_I2C_Master_Abort_IT() + (++) End of abort process, HAL_I2C_AbortCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_AbortCpltCallback() + + *** Interrupt mode IO MEM operation *** + ======================================= + [..] + (+) Write an amount of data in no-blocking mode with Interrupt to a specific memory address using + HAL_I2C_Mem_Write_IT() + (+) At MEM end of write transfer HAL_I2C_MemTxCpltCallback is executed and user can + add his own code by customization of function pointer HAL_I2C_MemTxCpltCallback + (+) Read an amount of data in no-blocking mode with Interrupt from a specific memory address using + HAL_I2C_Mem_Read_IT() + (+) At MEM end of read transfer HAL_I2C_MemRxCpltCallback is executed and user can + add his own code by customization of function pointer HAL_I2C_MemRxCpltCallback + (+) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and user can + add his own code by customization of function pointer HAL_I2C_ErrorCallback + + *** DMA mode IO operation *** + ============================== + [..] + (+) Transmit in master mode an amount of data in non blocking mode (DMA) using + HAL_I2C_Master_Transmit_DMA() + (+) At transmission end of transfer HAL_I2C_MasterTxCpltCallback is executed and user can + add his own code by customization of function pointer HAL_I2C_MasterTxCpltCallback + (+) Receive in master mode an amount of data in non blocking mode (DMA) using + HAL_I2C_Master_Receive_DMA() + (+) At reception end of transfer HAL_I2C_MasterRxCpltCallback is executed and user can + add his own code by customization of function pointer HAL_I2C_MasterRxCpltCallback + (+) Transmit in slave mode an amount of data in non blocking mode (DMA) using + HAL_I2C_Slave_Transmit_DMA() + (+) At transmission end of transfer HAL_I2C_SlaveTxCpltCallback is executed and user can + add his own code by customization of function pointer HAL_I2C_SlaveTxCpltCallback + (+) Receive in slave mode an amount of data in non blocking mode (DMA) using + HAL_I2C_Slave_Receive_DMA() + (+) At reception end of transfer HAL_I2C_SlaveRxCpltCallback is executed and user can + add his own code by customization of function pointer HAL_I2C_SlaveRxCpltCallback + (+) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and user can + add his own code by customization of function pointer HAL_I2C_ErrorCallback + (+) Abort a master I2C process communication with Interrupt using HAL_I2C_Master_Abort_IT() + (+) End of abort process, HAL_I2C_AbortCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_AbortCpltCallback() + + *** DMA mode IO MEM operation *** + ================================= + [..] + (+) Write an amount of data in no-blocking mode with DMA to a specific memory address using + HAL_I2C_Mem_Write_DMA() + (+) At MEM end of write transfer HAL_I2C_MemTxCpltCallback is executed and user can + add his own code by customization of function pointer HAL_I2C_MemTxCpltCallback + (+) Read an amount of data in no-blocking mode with DMA from a specific memory address using + HAL_I2C_Mem_Read_DMA() + (+) At MEM end of read transfer HAL_I2C_MemRxCpltCallback is executed and user can + add his own code by customization of function pointer HAL_I2C_MemRxCpltCallback + (+) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and user can + add his own code by customization of function pointer HAL_I2C_ErrorCallback + + + *** I2C HAL driver macros list *** + ================================== + [..] + Below the list of most used macros in I2C HAL driver. + + (+) __HAL_I2C_ENABLE: Enable the I2C peripheral + (+) __HAL_I2C_DISABLE: Disable the I2C peripheral + (+) __HAL_I2C_GET_FLAG : Checks whether the specified I2C flag is set or not + (+) __HAL_I2C_CLEAR_FLAG : Clear the specified I2C pending flag + (+) __HAL_I2C_ENABLE_IT: Enable the specified I2C interrupt + (+) __HAL_I2C_DISABLE_IT: Disable the specified I2C interrupt + + [..] + (@) You can refer to the I2C HAL driver header file for more useful macros + + + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @defgroup I2C I2C + * @brief I2C HAL module driver + * @{ + */ + +#ifdef HAL_I2C_MODULE_ENABLED + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/** @addtogroup I2C_Private_Define + * @{ + */ +#define I2C_TIMEOUT_FLAG 35U /*!< Timeout 35 ms */ +#define I2C_TIMEOUT_BUSY_FLAG 25U /*!< Timeout 25 ms */ +#define I2C_NO_OPTION_FRAME 0xFFFF0000U /*!< XferOptions default value */ + +/* Private define for @ref PreviousState usage */ +#define I2C_STATE_MSK ((uint32_t)((HAL_I2C_STATE_BUSY_TX | HAL_I2C_STATE_BUSY_RX) & (~(uint32_t)HAL_I2C_STATE_READY))) /*!< Mask State define, keep only RX and TX bits */ +#define I2C_STATE_NONE ((uint32_t)(HAL_I2C_MODE_NONE)) /*!< Default Value */ +#define I2C_STATE_MASTER_BUSY_TX ((uint32_t)((HAL_I2C_STATE_BUSY_TX & I2C_STATE_MSK) | HAL_I2C_MODE_MASTER)) /*!< Master Busy TX, combinaison of State LSB and Mode enum */ +#define I2C_STATE_MASTER_BUSY_RX ((uint32_t)((HAL_I2C_STATE_BUSY_RX & I2C_STATE_MSK) | HAL_I2C_MODE_MASTER)) /*!< Master Busy RX, combinaison of State LSB and Mode enum */ +#define I2C_STATE_SLAVE_BUSY_TX ((uint32_t)((HAL_I2C_STATE_BUSY_TX & I2C_STATE_MSK) | HAL_I2C_MODE_SLAVE)) /*!< Slave Busy TX, combinaison of State LSB and Mode enum */ +#define I2C_STATE_SLAVE_BUSY_RX ((uint32_t)((HAL_I2C_STATE_BUSY_RX & I2C_STATE_MSK) | HAL_I2C_MODE_SLAVE)) /*!< Slave Busy RX, combinaison of State LSB and Mode enum */ + +/** + * @} + */ + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/** @addtogroup I2C_Private_Functions + * @{ + */ +/* Private functions to handle DMA transfer */ +static void I2C_DMAXferCplt(DMA_HandleTypeDef *hdma); +static void I2C_DMAError(DMA_HandleTypeDef *hdma); +static void I2C_DMAAbort(DMA_HandleTypeDef *hdma); + +static void I2C_ITError(I2C_HandleTypeDef *hi2c); + +static HAL_StatusTypeDef I2C_MasterRequestWrite(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_MasterRequestRead(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_RequestMemoryWrite(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_RequestMemoryRead(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, FlagStatus Status, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_WaitOnMasterAddressFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_WaitOnTXEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_WaitOnBTFFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_WaitOnRXNEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_WaitOnSTOPFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_IsAcknowledgeFailed(I2C_HandleTypeDef *hi2c); + +/* Private functions for I2C transfer IRQ handler */ +static HAL_StatusTypeDef I2C_MasterTransmit_TXE(I2C_HandleTypeDef *hi2c); +static HAL_StatusTypeDef I2C_MasterTransmit_BTF(I2C_HandleTypeDef *hi2c); +static HAL_StatusTypeDef I2C_MasterReceive_RXNE(I2C_HandleTypeDef *hi2c); +static HAL_StatusTypeDef I2C_MasterReceive_BTF(I2C_HandleTypeDef *hi2c); +static HAL_StatusTypeDef I2C_Master_SB(I2C_HandleTypeDef *hi2c); +static HAL_StatusTypeDef I2C_Master_ADD10(I2C_HandleTypeDef *hi2c); +static HAL_StatusTypeDef I2C_Master_ADDR(I2C_HandleTypeDef *hi2c); + +static HAL_StatusTypeDef I2C_SlaveTransmit_TXE(I2C_HandleTypeDef *hi2c); +static HAL_StatusTypeDef I2C_SlaveTransmit_BTF(I2C_HandleTypeDef *hi2c); +static HAL_StatusTypeDef I2C_SlaveReceive_RXNE(I2C_HandleTypeDef *hi2c); +static HAL_StatusTypeDef I2C_SlaveReceive_BTF(I2C_HandleTypeDef *hi2c); +static HAL_StatusTypeDef I2C_Slave_ADDR(I2C_HandleTypeDef *hi2c); +static HAL_StatusTypeDef I2C_Slave_STOPF(I2C_HandleTypeDef *hi2c); +static HAL_StatusTypeDef I2C_Slave_AF(I2C_HandleTypeDef *hi2c); +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ +/** @defgroup I2C_Exported_Functions I2C Exported Functions + * @{ + */ + +/** @defgroup I2C_Exported_Functions_Group1 Initialization and de-initialization functions + * @brief Initialization and Configuration functions + * +@verbatim + =============================================================================== + ##### Initialization and de-initialization functions ##### + =============================================================================== + [..] This subsection provides a set of functions allowing to initialize and + de-initialize the I2Cx peripheral: + + (+) User must Implement HAL_I2C_MspInit() function in which he configures + all related peripherals resources (CLOCK, GPIO, DMA, IT and NVIC). + + (+) Call the function HAL_I2C_Init() to configure the selected device with + the selected configuration: + (++) Communication Speed + (++) Duty cycle + (++) Addressing mode + (++) Own Address 1 + (++) Dual Addressing mode + (++) Own Address 2 + (++) General call mode + (++) Nostretch mode + + (+) Call the function HAL_I2C_DeInit() to restore the default configuration + of the selected I2Cx peripheral. + +@endverbatim + * @{ + */ + +/** + * @brief Initializes the I2C according to the specified parameters + * in the I2C_InitTypeDef and create the associated handle. + * @param hi2c pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c) +{ + uint32_t freqrange = 0U; + uint32_t pclk1 = 0U; + + /* Check the I2C handle allocation */ + if(hi2c == NULL) + { + return HAL_ERROR; + } + + /* Check the parameters */ + assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance)); + assert_param(IS_I2C_CLOCK_SPEED(hi2c->Init.ClockSpeed)); + assert_param(IS_I2C_DUTY_CYCLE(hi2c->Init.DutyCycle)); + assert_param(IS_I2C_OWN_ADDRESS1(hi2c->Init.OwnAddress1)); + assert_param(IS_I2C_ADDRESSING_MODE(hi2c->Init.AddressingMode)); + assert_param(IS_I2C_DUAL_ADDRESS(hi2c->Init.DualAddressMode)); + assert_param(IS_I2C_OWN_ADDRESS2(hi2c->Init.OwnAddress2)); + assert_param(IS_I2C_GENERAL_CALL(hi2c->Init.GeneralCallMode)); + assert_param(IS_I2C_NO_STRETCH(hi2c->Init.NoStretchMode)); + + if(hi2c->State == HAL_I2C_STATE_RESET) + { + /* Allocate lock resource and initialize it */ + hi2c->Lock = HAL_UNLOCKED; + /* Init the low level hardware : GPIO, CLOCK, NVIC */ + HAL_I2C_MspInit(hi2c); + } + + hi2c->State = HAL_I2C_STATE_BUSY; + + /* Disable the selected I2C peripheral */ + __HAL_I2C_DISABLE(hi2c); + + /* Get PCLK1 frequency */ + pclk1 = HAL_RCC_GetPCLK1Freq(); + + /* Calculate frequency range */ + freqrange = I2C_FREQRANGE(pclk1); + + /*---------------------------- I2Cx CR2 Configuration ----------------------*/ + /* Configure I2Cx: Frequency range */ + hi2c->Instance->CR2 = freqrange; + + /*---------------------------- I2Cx TRISE Configuration --------------------*/ + /* Configure I2Cx: Rise Time */ + hi2c->Instance->TRISE = I2C_RISE_TIME(freqrange, hi2c->Init.ClockSpeed); + + /*---------------------------- I2Cx CCR Configuration ----------------------*/ + /* Configure I2Cx: Speed */ + hi2c->Instance->CCR = I2C_SPEED(pclk1, hi2c->Init.ClockSpeed, hi2c->Init.DutyCycle); + + /*---------------------------- I2Cx CR1 Configuration ----------------------*/ + /* Configure I2Cx: Generalcall and NoStretch mode */ + hi2c->Instance->CR1 = (hi2c->Init.GeneralCallMode | hi2c->Init.NoStretchMode); + + /*---------------------------- I2Cx OAR1 Configuration ---------------------*/ + /* Configure I2Cx: Own Address1 and addressing mode */ + hi2c->Instance->OAR1 = (hi2c->Init.AddressingMode | hi2c->Init.OwnAddress1); + + /*---------------------------- I2Cx OAR2 Configuration ---------------------*/ + /* Configure I2Cx: Dual mode and Own Address2 */ + hi2c->Instance->OAR2 = (hi2c->Init.DualAddressMode | hi2c->Init.OwnAddress2); + + /* Enable the selected I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->Mode = HAL_I2C_MODE_NONE; + + return HAL_OK; +} + +/** + * @brief DeInitializes the I2C peripheral. + * @param hi2c pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_DeInit(I2C_HandleTypeDef *hi2c) +{ + /* Check the I2C handle allocation */ + if(hi2c == NULL) + { + return HAL_ERROR; + } + + /* Check the parameters */ + assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance)); + + hi2c->State = HAL_I2C_STATE_BUSY; + + /* Disable the I2C Peripheral Clock */ + __HAL_I2C_DISABLE(hi2c); + + /* DeInit the low level hardware: GPIO, CLOCK, NVIC */ + HAL_I2C_MspDeInit(hi2c); + + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + hi2c->State = HAL_I2C_STATE_RESET; + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Release Lock */ + __HAL_UNLOCK(hi2c); + + return HAL_OK; +} + +/** + * @brief I2C MSP Init. + * @param hi2c pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval None + */ + __weak void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_I2C_MspInit could be implemented in the user file + */ +} + +/** + * @brief I2C MSP DeInit + * @param hi2c pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval None + */ + __weak void HAL_I2C_MspDeInit(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_I2C_MspDeInit could be implemented in the user file + */ +} + +/** + * @} + */ + +/** @defgroup I2C_Exported_Functions_Group2 IO operation functions + * @brief Data transfers functions + * +@verbatim + =============================================================================== + ##### IO operation functions ##### + =============================================================================== + [..] + This subsection provides a set of functions allowing to manage the I2C data + transfers. + + (#) There are two modes of transfer: + (++) Blocking mode : The communication is performed in the polling mode. + The status of all data processing is returned by the same function + after finishing transfer. + (++) No-Blocking mode : The communication is performed using Interrupts + or DMA. These functions return the status of the transfer startup. + The end of the data processing will be indicated through the + dedicated I2C IRQ when using Interrupt mode or the DMA IRQ when + using DMA mode. + + (#) Blocking mode functions are : + (++) HAL_I2C_Master_Transmit() + (++) HAL_I2C_Master_Receive() + (++) HAL_I2C_Slave_Transmit() + (++) HAL_I2C_Slave_Receive() + (++) HAL_I2C_Mem_Write() + (++) HAL_I2C_Mem_Read() + (++) HAL_I2C_IsDeviceReady() + + (#) No-Blocking mode functions with Interrupt are : + (++) HAL_I2C_Master_Transmit_IT() + (++) HAL_I2C_Master_Receive_IT() + (++) HAL_I2C_Slave_Transmit_IT() + (++) HAL_I2C_Slave_Receive_IT() + (++) HAL_I2C_Master_Sequential_Transmit_IT() + (++) HAL_I2C_Master_Sequential_Receive_IT() + (++) HAL_I2C_Slave_Sequential_Transmit_IT() + (++) HAL_I2C_Slave_Sequential_Receive_IT() + (++) HAL_I2C_Mem_Write_IT() + (++) HAL_I2C_Mem_Read_IT() + + (#) No-Blocking mode functions with DMA are : + (++) HAL_I2C_Master_Transmit_DMA() + (++) HAL_I2C_Master_Receive_DMA() + (++) HAL_I2C_Slave_Transmit_DMA() + (++) HAL_I2C_Slave_Receive_DMA() + (++) HAL_I2C_Mem_Write_DMA() + (++) HAL_I2C_Mem_Read_DMA() + + (#) A set of Transfer Complete Callbacks are provided in non Blocking mode: + (++) HAL_I2C_MemTxCpltCallback() + (++) HAL_I2C_MemRxCpltCallback() + (++) HAL_I2C_MasterTxCpltCallback() + (++) HAL_I2C_MasterRxCpltCallback() + (++) HAL_I2C_SlaveTxCpltCallback() + (++) HAL_I2C_SlaveRxCpltCallback() + (++) HAL_I2C_ErrorCallback() + (++) HAL_I2C_AbortCpltCallback() + +@endverbatim + * @{ + */ + +/** + * @brief Transmits in master mode an amount of data in blocking mode. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param Timeout Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout) +{ + uint32_t tickstart = 0x00U; + + /* Init tickstart for timeout management*/ + tickstart = HAL_GetTick(); + + if(hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) + { + return HAL_BUSY; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->XferSize = hi2c->XferCount; + + /* Send Slave Address */ + if(I2C_MasterRequestWrite(hi2c, DevAddress, Timeout, tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + return HAL_ERROR; + } + else + { + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + return HAL_TIMEOUT; + } + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + while(hi2c->XferSize > 0U) + { + /* Wait until TXE flag is set */ + if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + /* Write data to DR */ + hi2c->Instance->DR = (*hi2c->pBuffPtr++); + hi2c->XferCount--; + hi2c->XferSize--; + + if((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) && (hi2c->XferSize != 0U)) + { + /* Write data to DR */ + hi2c->Instance->DR = (*hi2c->pBuffPtr++); + hi2c->XferCount--; + hi2c->XferSize--; + } + + /* Wait until BTF flag is set */ + if(I2C_WaitOnBTFFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + } + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Receives in master mode an amount of data in blocking mode. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param Timeout Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout) +{ + uint32_t tickstart = 0x00U; + + /* Init tickstart for timeout management*/ + tickstart = HAL_GetTick(); + + if(hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) + { + return HAL_BUSY; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->XferSize = hi2c->XferCount; + + /* Send Slave Address */ + if(I2C_MasterRequestRead(hi2c, DevAddress, Timeout, tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + return HAL_ERROR; + } + else + { + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + return HAL_TIMEOUT; + } + } + + if(hi2c->XferSize == 0U) + { + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + } + else if(hi2c->XferSize == 1U) + { + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + } + else if(hi2c->XferSize == 2U) + { + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + /* Enable Pos */ + hi2c->Instance->CR1 |= I2C_CR1_POS; + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + else + { + /* Enable Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + + while(hi2c->XferSize > 0U) + { + if(hi2c->XferSize <= 3U) + { + /* One byte */ + if(hi2c->XferSize == 1U) + { + /* Wait until RXNE flag is set */ + if(I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_TIMEOUT) + { + return HAL_TIMEOUT; + } + else + { + return HAL_ERROR; + } + } + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + } + /* Two bytes */ + else if(hi2c->XferSize == 2U) + { + /* Wait until BTF flag is set */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + } + /* 3 Last bytes */ + else + { + /* Wait until BTF flag is set */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + + /* Wait until BTF flag is set */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + } + } + else + { + /* Wait until RXNE flag is set */ + if(I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_TIMEOUT) + { + return HAL_TIMEOUT; + } + else + { + return HAL_ERROR; + } + } + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + + if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) + { + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + } + } + } + + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Transmits in slave mode an amount of data in blocking mode. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param Timeout Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Transmit(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout) +{ + uint32_t tickstart = 0x00U; + + /* Init tickstart for timeout management*/ + tickstart = HAL_GetTick(); + + if(hi2c->State == HAL_I2C_STATE_READY) + { + if((pData == NULL) || (Size == 0U)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->XferSize = hi2c->XferCount; + + /* Enable Address Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Wait until ADDR flag is set */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* If 10bit addressing mode is selected */ + if(hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_10BIT) + { + /* Wait until ADDR flag is set */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + + while(hi2c->XferSize > 0U) + { + /* Wait until TXE flag is set */ + if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + /* Disable Address Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + /* Write data to DR */ + hi2c->Instance->DR = (*hi2c->pBuffPtr++); + hi2c->XferCount--; + hi2c->XferSize--; + + if((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) && (hi2c->XferSize != 0U)) + { + /* Write data to DR */ + hi2c->Instance->DR = (*hi2c->pBuffPtr++); + hi2c->XferCount--; + hi2c->XferSize--; + } + } + + /* Wait until AF flag is set */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_AF, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + /* Clear AF flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + + /* Disable Address Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Receive in slave mode an amount of data in blocking mode + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param Timeout Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Receive(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout) +{ + uint32_t tickstart = 0x00U; + + /* Init tickstart for timeout management*/ + tickstart = HAL_GetTick(); + + if(hi2c->State == HAL_I2C_STATE_READY) + { + if((pData == NULL) || (Size == 0)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->XferSize = hi2c->XferCount; + + /* Enable Address Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Wait until ADDR flag is set */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + while(hi2c->XferSize > 0U) + { + /* Wait until RXNE flag is set */ + if(I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + /* Disable Address Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + if(hi2c->ErrorCode == HAL_I2C_ERROR_TIMEOUT) + { + return HAL_TIMEOUT; + } + else + { + return HAL_ERROR; + } + } + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + + if((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) && (Size != 0U)) + { + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + } + } + + /* Wait until STOP flag is set */ + if(I2C_WaitOnSTOPFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + /* Disable Address Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + /* Clear STOP flag */ + __HAL_I2C_CLEAR_STOPFLAG(hi2c); + + /* Disable Address Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Transmit in master mode an amount of data in non-blocking mode with Interrupt + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + + if(hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); + do + { + if(count-- == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->XferSize = hi2c->XferCount; + hi2c->Devaddress = DevAddress; + + /* Generate Start */ + hi2c->Instance->CR1 |= I2C_CR1_START; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Receive in master mode an amount of data in non-blocking mode with Interrupt + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + + if(hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); + do + { + if(count-- == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->XferSize = hi2c->XferCount; + hi2c->Devaddress = DevAddress; + + /* Enable Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Generate Start */ + hi2c->Instance->CR1 |= I2C_CR1_START; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Sequential transmit in master mode an amount of data in non-blocking mode with Interrupt + * @note This interface allow to manage repeated start condition when a direction change during transfer + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param XferOptions Options of Transfer, value of @ref I2C_XferOptions_definition + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Sequential_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions) +{ + __IO uint32_t Prev_State = 0x00U; + __IO uint32_t count = 0x00U; + + /* Check the parameters */ + assert_param(IS_I2C_TRANSFER_OPTIONS_REQUEST(XferOptions)); + + if(hi2c->State == HAL_I2C_STATE_READY) + { + /* Check Busy Flag only if FIRST call of Master interface */ + if((XferOptions == I2C_FIRST_AND_LAST_FRAME) || (XferOptions == I2C_FIRST_FRAME)) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); + do + { + if(count-- == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = XferOptions; + hi2c->XferSize = hi2c->XferCount; + hi2c->Devaddress = DevAddress; + + Prev_State = hi2c->PreviousState; + + /* Generate Start */ + if((Prev_State == I2C_STATE_MASTER_BUSY_RX) || (Prev_State == I2C_STATE_NONE)) + { + /* Generate Start condition if first transfer */ + if((XferOptions == I2C_FIRST_AND_LAST_FRAME) || (XferOptions == I2C_FIRST_FRAME)) + { + /* Generate Start */ + hi2c->Instance->CR1 |= I2C_CR1_START; + } + else + { + /* Generate ReStart */ + hi2c->Instance->CR1 |= I2C_CR1_START; + } + } + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Sequential receive in master mode an amount of data in non-blocking mode with Interrupt + * @note This interface allow to manage repeated start condition when a direction change during transfer + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param XferOptions Options of Transfer, value of @ref I2C_XferOptions_definition + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Sequential_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions) +{ + __IO uint32_t count = 0U; + + /* Check the parameters */ + assert_param(IS_I2C_TRANSFER_OPTIONS_REQUEST(XferOptions)); + + if(hi2c->State == HAL_I2C_STATE_READY) + { + /* Check Busy Flag only if FIRST call of Master interface */ + if((XferOptions == I2C_FIRST_AND_LAST_FRAME) || (XferOptions == I2C_FIRST_FRAME)) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); + do + { + if(count-- == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = XferOptions; + hi2c->XferSize = hi2c->XferCount; + hi2c->Devaddress = DevAddress; + + if((hi2c->PreviousState == I2C_STATE_MASTER_BUSY_TX) || (hi2c->PreviousState == I2C_STATE_NONE)) + { + /* Generate Start condition if first transfer */ + if((XferOptions == I2C_FIRST_AND_LAST_FRAME) || (XferOptions == I2C_FIRST_FRAME) || (XferOptions == I2C_NO_OPTION_FRAME)) + { + /* Enable Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Generate Start */ + hi2c->Instance->CR1 |= I2C_CR1_START; + } + else if(hi2c->PreviousState == I2C_STATE_MASTER_BUSY_TX) + { + /* Enable Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Generate ReStart */ + hi2c->Instance->CR1 |= I2C_CR1_START; + } + } + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Transmit in slave mode an amount of data in non-blocking mode with Interrupt + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + + if(hi2c->State == HAL_I2C_STATE_READY) + { + if((pData == NULL) || (Size == 0U)) + { + return HAL_ERROR; + } + + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); + do + { + if(count-- == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->XferSize = hi2c->XferCount; + + /* Enable Address Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Receive in slave mode an amount of data in non-blocking mode with Interrupt + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + + if(hi2c->State == HAL_I2C_STATE_READY) + { + if((pData == NULL) || (Size == 0U)) + { + return HAL_ERROR; + } + + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); + do + { + if(count-- == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferSize = Size; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + + /* Enable Address Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Sequential transmit in slave mode an amount of data in no-blocking mode with Interrupt + * @note This interface allow to manage repeated start condition when a direction change during transfer + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param XferOptions Options of Transfer, value of @ref I2C_XferOptions_definition + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Sequential_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions) +{ + /* Check the parameters */ + assert_param(IS_I2C_TRANSFER_OPTIONS_REQUEST(XferOptions)); + + if(hi2c->State == HAL_I2C_STATE_LISTEN) + { + if((pData == NULL) || (Size == 0U)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_TX_LISTEN; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = XferOptions; + hi2c->XferSize = hi2c->XferCount; + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Sequential receive in slave mode an amount of data in non-blocking mode with Interrupt + * @note This interface allow to manage repeated start condition when a direction change during transfer + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param XferOptions Options of Transfer, value of @ref I2C_XferOptions_definition + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Sequential_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions) +{ + /* Check the parameters */ + assert_param(IS_I2C_TRANSFER_OPTIONS_REQUEST(XferOptions)); + + if(hi2c->State == HAL_I2C_STATE_LISTEN) + { + if((pData == NULL) || (Size == 0U)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_RX_LISTEN; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = XferOptions; + hi2c->XferSize = hi2c->XferCount; + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Enable the Address listen mode with Interrupt. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_EnableListen_IT(I2C_HandleTypeDef *hi2c) +{ + if(hi2c->State == HAL_I2C_STATE_READY) + { + hi2c->State = HAL_I2C_STATE_LISTEN; + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Enable Address Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Enable EVT and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Disable the Address listen mode with Interrupt. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_DisableListen_IT(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of tmp to prevent undefined behavior of volatile usage */ + uint32_t tmp; + + /* Disable Address listen mode only if a transfer is not ongoing */ + if(hi2c->State == HAL_I2C_STATE_LISTEN) + { + tmp = (uint32_t)(hi2c->State) & I2C_STATE_MSK; + hi2c->PreviousState = tmp | (uint32_t)(hi2c->Mode); + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Disable Address Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + /* Disable EVT and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Transmit in master mode an amount of data in non-blocking mode with DMA + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + + if(hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); + do + { + if(count-- == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->XferSize = hi2c->XferCount; + hi2c->Devaddress = DevAddress; + + if(hi2c->XferSize > 0U) + { + /* Set the I2C DMA transfer complete callback */ + hi2c->hdmatx->XferCpltCallback = I2C_DMAXferCplt; + + /* Set the DMA error callback */ + hi2c->hdmatx->XferErrorCallback = I2C_DMAError; + + /* Set the unused DMA callbacks to NULL */ + hi2c->hdmatx->XferHalfCpltCallback = NULL; + hi2c->hdmatx->XferM1CpltCallback = NULL; + hi2c->hdmatx->XferM1HalfCpltCallback = NULL; + hi2c->hdmatx->XferAbortCallback = NULL; + + /* Enable the DMA Stream */ + HAL_DMA_Start_IT(hi2c->hdmatx, (uint32_t)hi2c->pBuffPtr, (uint32_t)&hi2c->Instance->DR, hi2c->XferSize); + + /* Enable Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Generate Start */ + hi2c->Instance->CR1 |= I2C_CR1_START; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + /* Enable DMA Request */ + hi2c->Instance->CR2 |= I2C_CR2_DMAEN; + } + else + { + /* Enable Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Generate Start */ + hi2c->Instance->CR1 |= I2C_CR1_START; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + } + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Receive in master mode an amount of data in non-blocking mode with DMA + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + + if(hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); + do + { + if(count-- == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->XferSize = hi2c->XferCount; + hi2c->Devaddress = DevAddress; + + if(hi2c->XferSize > 0U) + { + /* Set the I2C DMA transfer complete callback */ + hi2c->hdmarx->XferCpltCallback = I2C_DMAXferCplt; + + /* Set the DMA error callback */ + hi2c->hdmarx->XferErrorCallback = I2C_DMAError; + + /* Set the unused DMA callbacks to NULL */ + hi2c->hdmarx->XferHalfCpltCallback = NULL; + hi2c->hdmarx->XferM1CpltCallback = NULL; + hi2c->hdmarx->XferM1HalfCpltCallback = NULL; + hi2c->hdmarx->XferAbortCallback = NULL; + + /* Enable the DMA Stream */ + HAL_DMA_Start_IT(hi2c->hdmarx, (uint32_t)&hi2c->Instance->DR, (uint32_t)hi2c->pBuffPtr, hi2c->XferSize); + + /* Enable Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Generate Start */ + hi2c->Instance->CR1 |= I2C_CR1_START; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + /* Enable DMA Request */ + hi2c->Instance->CR2 |= I2C_CR2_DMAEN; + } + else + { + /* Enable Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Generate Start */ + hi2c->Instance->CR1 |= I2C_CR1_START; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + } + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Abort a master I2C process communication with Interrupt. + * @note This abort can be called only if state is ready + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Abort_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(DevAddress); + + /* Abort Master transfer during Receive or Transmit process */ + if(hi2c->Mode == HAL_I2C_MODE_MASTER) + { + /* Process Locked */ + __HAL_LOCK(hi2c); + + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_ABORT; + + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + + hi2c->XferCount = 0U; + + /* Disable EVT, BUF and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Call the corresponding callback to inform upper layer of End of Transfer */ + I2C_ITError(hi2c); + + return HAL_OK; + } + else + { + /* Wrong usage of abort function */ + /* This function should be used only in case of abort monitored by master device */ + return HAL_ERROR; + } +} + +/** + * @brief Transmit in slave mode an amount of data in non-blocking mode with DMA + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + + if(hi2c->State == HAL_I2C_STATE_READY) + { + if((pData == NULL) || (Size == 0U)) + { + return HAL_ERROR; + } + + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); + do + { + if(count-- == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->XferSize = hi2c->XferCount; + + /* Set the I2C DMA transfer complete callback */ + hi2c->hdmatx->XferCpltCallback = I2C_DMAXferCplt; + + /* Set the DMA error callback */ + hi2c->hdmatx->XferErrorCallback = I2C_DMAError; + + /* Set the unused DMA callbacks to NULL */ + hi2c->hdmatx->XferHalfCpltCallback = NULL; + hi2c->hdmatx->XferM1CpltCallback = NULL; + hi2c->hdmatx->XferM1HalfCpltCallback = NULL; + hi2c->hdmatx->XferAbortCallback = NULL; + + /* Enable the DMA Stream */ + HAL_DMA_Start_IT(hi2c->hdmatx, (uint32_t)hi2c->pBuffPtr, (uint32_t)&hi2c->Instance->DR, hi2c->XferSize); + + /* Enable Address Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + /* Enable EVT and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + /* Enable DMA Request */ + hi2c->Instance->CR2 |= I2C_CR2_DMAEN; + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Receive in slave mode an amount of data in non-blocking mode with DMA + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Receive_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + + if(hi2c->State == HAL_I2C_STATE_READY) + { + if((pData == NULL) || (Size == 0U)) + { + return HAL_ERROR; + } + + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); + do + { + if(count-- == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->XferSize = hi2c->XferCount; + + /* Set the I2C DMA transfer complete callback */ + hi2c->hdmarx->XferCpltCallback = I2C_DMAXferCplt; + + /* Set the DMA error callback */ + hi2c->hdmarx->XferErrorCallback = I2C_DMAError; + + /* Set the unused DMA callbacks to NULL */ + hi2c->hdmarx->XferHalfCpltCallback = NULL; + hi2c->hdmarx->XferM1CpltCallback = NULL; + hi2c->hdmarx->XferM1HalfCpltCallback = NULL; + hi2c->hdmarx->XferAbortCallback = NULL; + + /* Enable the DMA Stream */ + HAL_DMA_Start_IT(hi2c->hdmarx, (uint32_t)&hi2c->Instance->DR, (uint32_t)hi2c->pBuffPtr, hi2c->XferSize); + + /* Enable Address Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + /* Enable EVT and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + /* Enable DMA Request */ + hi2c->Instance->CR2 |= I2C_CR2_DMAEN; + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} +/** + * @brief Write an amount of data in blocking mode to a specific memory address + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address + * @param MemAddress Internal memory address + * @param MemAddSize Size of internal memory address + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param Timeout Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout) +{ + uint32_t tickstart = 0x00U; + + /* Init tickstart for timeout management*/ + tickstart = HAL_GetTick(); + + /* Check the parameters */ + assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); + + if(hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) + { + return HAL_BUSY; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_MEM; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->XferSize = hi2c->XferCount; + + /* Send Slave Address and Memory Address */ + if(I2C_RequestMemoryWrite(hi2c, DevAddress, MemAddress, MemAddSize, Timeout, tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + return HAL_ERROR; + } + else + { + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + return HAL_TIMEOUT; + } + } + + while(hi2c->XferSize > 0U) + { + /* Wait until TXE flag is set */ + if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + /* Write data to DR */ + hi2c->Instance->DR = (*hi2c->pBuffPtr++); + hi2c->XferSize--; + hi2c->XferCount--; + + if((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) && (hi2c->XferSize != 0U)) + { + /* Write data to DR */ + hi2c->Instance->DR = (*hi2c->pBuffPtr++); + hi2c->XferSize--; + hi2c->XferCount--; + } + } + + /* Wait until BTF flag is set */ + if(I2C_WaitOnBTFFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Read an amount of data in blocking mode from a specific memory address + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address + * @param MemAddress Internal memory address + * @param MemAddSize Size of internal memory address + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param Timeout Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout) +{ + uint32_t tickstart = 0x00U; + + /* Init tickstart for timeout management*/ + tickstart = HAL_GetTick(); + + /* Check the parameters */ + assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); + + if(hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) + { + return HAL_BUSY; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_MEM; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->XferSize = hi2c->XferCount; + + /* Send Slave Address and Memory Address */ + if(I2C_RequestMemoryRead(hi2c, DevAddress, MemAddress, MemAddSize, Timeout, tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + return HAL_ERROR; + } + else + { + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + return HAL_TIMEOUT; + } + } + + if(hi2c->XferSize == 0U) + { + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + } + else if(hi2c->XferSize == 1U) + { + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + } + else if(hi2c->XferSize == 2U) + { + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + /* Enable Pos */ + hi2c->Instance->CR1 |= I2C_CR1_POS; + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + else + { + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + + while(hi2c->XferSize > 0U) + { + if(hi2c->XferSize <= 3U) + { + /* One byte */ + if(hi2c->XferSize== 1U) + { + /* Wait until RXNE flag is set */ + if(I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_TIMEOUT) + { + return HAL_TIMEOUT; + } + else + { + return HAL_ERROR; + } + } + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + } + /* Two bytes */ + else if(hi2c->XferSize == 2U) + { + /* Wait until BTF flag is set */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + } + /* 3 Last bytes */ + else + { + /* Wait until BTF flag is set */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + + /* Wait until BTF flag is set */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + } + } + else + { + /* Wait until RXNE flag is set */ + if(I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_TIMEOUT) + { + return HAL_TIMEOUT; + } + else + { + return HAL_ERROR; + } + } + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + + if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) + { + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferSize--; + hi2c->XferCount--; + } + } + } + + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Write an amount of data in non-blocking mode with Interrupt to a specific memory address + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address + * @param MemAddress Internal memory address + * @param MemAddSize Size of internal memory address + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Mem_Write_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + + /* Check the parameters */ + assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); + + if(hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); + do + { + if(count-- == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_MEM; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferSize = Size; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->Devaddress = DevAddress; + hi2c->Memaddress = MemAddress; + hi2c->MemaddSize = MemAddSize; + hi2c->EventCount = 0U; + + /* Generate Start */ + hi2c->Instance->CR1 |= I2C_CR1_START; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Read an amount of data in non-blocking mode with Interrupt from a specific memory address + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address + * @param MemAddress Internal memory address + * @param MemAddSize Size of internal memory address + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Mem_Read_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + + /* Check the parameters */ + assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); + + if(hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); + do + { + if(count-- == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_MEM; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferSize = Size; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->Devaddress = DevAddress; + hi2c->Memaddress = MemAddress; + hi2c->MemaddSize = MemAddSize; + hi2c->EventCount = 0U; + + /* Enable Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Generate Start */ + hi2c->Instance->CR1 |= I2C_CR1_START; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + if(hi2c->XferSize > 0U) + { + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + } + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Write an amount of data in non-blocking mode with DMA to a specific memory address + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address + * @param MemAddress Internal memory address + * @param MemAddSize Size of internal memory address + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Mem_Write_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + + uint32_t tickstart = 0x00U; + + /* Init tickstart for timeout management*/ + tickstart = HAL_GetTick(); + + /* Check the parameters */ + assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); + + if(hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); + do + { + if(count-- == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_MEM; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferSize = Size; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + + if(hi2c->XferSize > 0U) + { + /* Set the I2C DMA transfer complete callback */ + hi2c->hdmatx->XferCpltCallback = I2C_DMAXferCplt; + + /* Set the DMA error callback */ + hi2c->hdmatx->XferErrorCallback = I2C_DMAError; + + /* Set the unused DMA callbacks to NULL */ + hi2c->hdmatx->XferHalfCpltCallback = NULL; + hi2c->hdmatx->XferM1CpltCallback = NULL; + hi2c->hdmatx->XferM1HalfCpltCallback = NULL; + hi2c->hdmatx->XferAbortCallback = NULL; + + /* Enable the DMA Stream */ + HAL_DMA_Start_IT(hi2c->hdmatx, (uint32_t)hi2c->pBuffPtr, (uint32_t)&hi2c->Instance->DR, hi2c->XferSize); + + /* Send Slave Address and Memory Address */ + if(I2C_RequestMemoryWrite(hi2c, DevAddress, MemAddress, MemAddSize, I2C_TIMEOUT_FLAG, tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + return HAL_ERROR; + } + else + { + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + return HAL_TIMEOUT; + } + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + /* Enable ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_ERR); + + /* Enable DMA Request */ + hi2c->Instance->CR2 |= I2C_CR2_DMAEN; + } + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Reads an amount of data in non-blocking mode with DMA from a specific memory address. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address + * @param MemAddress Internal memory address + * @param MemAddSize Size of internal memory address + * @param pData Pointer to data buffer + * @param Size Amount of data to be read + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Mem_Read_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size) +{ + uint32_t tickstart = 0x00U; + __IO uint32_t count = 0U; + + /* Init tickstart for timeout management*/ + tickstart = HAL_GetTick(); + + /* Check the parameters */ + assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); + + if(hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock /25U /1000U); + do + { + if(count-- == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_MEM; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->XferSize = hi2c->XferCount; + + if(hi2c->XferSize > 0U) + { + /* Set the I2C DMA transfer complete callback */ + hi2c->hdmarx->XferCpltCallback = I2C_DMAXferCplt; + + /* Set the DMA error callback */ + hi2c->hdmarx->XferErrorCallback = I2C_DMAError; + + /* Set the unused DMA callbacks to NULL */ + hi2c->hdmarx->XferHalfCpltCallback = NULL; + hi2c->hdmarx->XferM1CpltCallback = NULL; + hi2c->hdmarx->XferM1HalfCpltCallback = NULL; + hi2c->hdmarx->XferAbortCallback = NULL; + + /* Enable the DMA Stream */ + HAL_DMA_Start_IT(hi2c->hdmarx, (uint32_t)&hi2c->Instance->DR, (uint32_t)hi2c->pBuffPtr, hi2c->XferSize); + + /* Send Slave Address and Memory Address */ + if(I2C_RequestMemoryRead(hi2c, DevAddress, MemAddress, MemAddSize, I2C_TIMEOUT_FLAG, tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + return HAL_ERROR; + } + else + { + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + return HAL_TIMEOUT; + } + } + + if(Size == 1U) + { + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + } + else + { + /* Enable Last DMA bit */ + hi2c->Instance->CR2 |= I2C_CR2_LAST; + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + /* Enable ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_ERR); + + /* Enable DMA Request */ + hi2c->Instance->CR2 |= I2C_CR2_DMAEN; + } + else + { + /* Send Slave Address and Memory Address */ + if(I2C_RequestMemoryRead(hi2c, DevAddress, MemAddress, MemAddSize, I2C_TIMEOUT_FLAG, tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + return HAL_ERROR; + } + else + { + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + return HAL_TIMEOUT; + } + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + + hi2c->State = HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + } + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Checks if target device is ready for communication. + * @note This function is used with Memory devices + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address + * @param Trials Number of trials + * @param Timeout Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout) +{ + uint32_t tickstart = 0U, tmp1 = 0U, tmp2 = 0U, tmp3 = 0U, I2C_Trials = 1U; + + /* Get tick */ + tickstart = HAL_GetTick(); + + if(hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) + { + return HAL_BUSY; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + hi2c->State = HAL_I2C_STATE_BUSY; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + + do + { + /* Generate Start */ + hi2c->Instance->CR1 |= I2C_CR1_START; + + /* Wait until SB flag is set */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + /* Send slave address */ + hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(DevAddress); + + /* Wait until ADDR or AF flag are set */ + /* Get tick */ + tickstart = HAL_GetTick(); + + tmp1 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR); + tmp2 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF); + tmp3 = hi2c->State; + while((tmp1 == RESET) && (tmp2 == RESET) && (tmp3 != HAL_I2C_STATE_TIMEOUT)) + { + if((Timeout == 0U)||((HAL_GetTick() - tickstart ) > Timeout)) + { + hi2c->State = HAL_I2C_STATE_TIMEOUT; + } + tmp1 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR); + tmp2 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF); + tmp3 = hi2c->State; + } + + hi2c->State = HAL_I2C_STATE_READY; + + /* Check if the ADDR flag has been set */ + if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR) == SET) + { + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + + /* Clear ADDR Flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Wait until BUSY flag is reset */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + hi2c->State = HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_OK; + } + else + { + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + + /* Clear AF Flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + + /* Wait until BUSY flag is reset */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + } + }while(I2C_Trials++ < Trials); + + hi2c->State = HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief This function handles I2C event interrupt request. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +void HAL_I2C_EV_IRQHandler(I2C_HandleTypeDef *hi2c) +{ + uint32_t sr2itflags = READ_REG(hi2c->Instance->SR2); + uint32_t sr1itflags = READ_REG(hi2c->Instance->SR1); + uint32_t itsources = READ_REG(hi2c->Instance->CR2); + + uint32_t CurrentMode = hi2c->Mode; + + /* Master or Memory mode selected */ + if((CurrentMode == HAL_I2C_MODE_MASTER) || (CurrentMode == HAL_I2C_MODE_MEM)) + { + /* SB Set ----------------------------------------------------------------*/ + if(((sr1itflags & I2C_FLAG_SB) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) + { + I2C_Master_SB(hi2c); + } + /* ADD10 Set -------------------------------------------------------------*/ + else if(((sr1itflags & I2C_FLAG_ADD10) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) + { + I2C_Master_ADD10(hi2c); + } + /* ADDR Set --------------------------------------------------------------*/ + else if(((sr1itflags & I2C_FLAG_ADDR) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) + { + I2C_Master_ADDR(hi2c); + } + + /* I2C in mode Transmitter -----------------------------------------------*/ + if((sr2itflags & I2C_FLAG_TRA) != RESET) + { + /* TXE set and BTF reset -----------------------------------------------*/ + if(((sr1itflags & I2C_FLAG_TXE) != RESET) && ((itsources & I2C_IT_BUF) != RESET) && ((sr1itflags & I2C_FLAG_BTF) == RESET)) + { + I2C_MasterTransmit_TXE(hi2c); + } + /* BTF set -------------------------------------------------------------*/ + else if(((sr1itflags & I2C_FLAG_BTF) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) + { + I2C_MasterTransmit_BTF(hi2c); + } + } + /* I2C in mode Receiver --------------------------------------------------*/ + else + { + /* RXNE set and BTF reset -----------------------------------------------*/ + if(((sr1itflags & I2C_FLAG_RXNE) != RESET) && ((itsources & I2C_IT_BUF) != RESET) && ((sr1itflags & I2C_FLAG_BTF) == RESET)) + { + I2C_MasterReceive_RXNE(hi2c); + } + /* BTF set -------------------------------------------------------------*/ + else if(((sr1itflags & I2C_FLAG_BTF) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) + { + I2C_MasterReceive_BTF(hi2c); + } + } + } + /* Slave mode selected */ + else + { + /* ADDR set --------------------------------------------------------------*/ + if(((sr1itflags & I2C_FLAG_ADDR) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) + { + I2C_Slave_ADDR(hi2c); + } + /* STOPF set --------------------------------------------------------------*/ + else if(((sr1itflags & I2C_FLAG_STOPF) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) + { + I2C_Slave_STOPF(hi2c); + } + /* I2C in mode Transmitter -----------------------------------------------*/ + else if((sr2itflags & I2C_FLAG_TRA) != RESET) + { + /* TXE set and BTF reset -----------------------------------------------*/ + if(((sr1itflags & I2C_FLAG_TXE) != RESET) && ((itsources & I2C_IT_BUF) != RESET) && ((sr1itflags & I2C_FLAG_BTF) == RESET)) + { + I2C_SlaveTransmit_TXE(hi2c); + } + /* BTF set -------------------------------------------------------------*/ + else if(((sr1itflags & I2C_FLAG_BTF) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) + { + I2C_SlaveTransmit_BTF(hi2c); + } + } + /* I2C in mode Receiver --------------------------------------------------*/ + else + { + /* RXNE set and BTF reset ----------------------------------------------*/ + if(((sr1itflags & I2C_FLAG_RXNE) != RESET) && ((itsources & I2C_IT_BUF) != RESET) && ((sr1itflags & I2C_FLAG_BTF) == RESET)) + { + I2C_SlaveReceive_RXNE(hi2c); + } + /* BTF set -------------------------------------------------------------*/ + else if(((sr1itflags & I2C_FLAG_BTF) != RESET) && ((itsources & I2C_IT_EVT) != RESET)) + { + I2C_SlaveReceive_BTF(hi2c); + } + } + } +} + +/** + * @brief This function handles I2C error interrupt request. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +void HAL_I2C_ER_IRQHandler(I2C_HandleTypeDef *hi2c) +{ + uint32_t tmp1 = 0U, tmp2 = 0U, tmp3 = 0U, tmp4 = 0U; + uint32_t sr1itflags = READ_REG(hi2c->Instance->SR1); + uint32_t itsources = READ_REG(hi2c->Instance->CR2); + + /* I2C Bus error interrupt occurred ----------------------------------------*/ + if(((sr1itflags & I2C_FLAG_BERR) != RESET) && ((itsources & I2C_IT_ERR) != RESET)) + { + hi2c->ErrorCode |= HAL_I2C_ERROR_BERR; + + /* Clear BERR flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_BERR); + } + + /* I2C Arbitration Loss error interrupt occurred ---------------------------*/ + if(((sr1itflags & I2C_FLAG_ARLO) != RESET) && ((itsources & I2C_IT_ERR) != RESET)) + { + hi2c->ErrorCode |= HAL_I2C_ERROR_ARLO; + + /* Clear ARLO flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ARLO); + } + + /* I2C Acknowledge failure error interrupt occurred ------------------------*/ + if(((sr1itflags & I2C_FLAG_AF) != RESET) && ((itsources & I2C_IT_ERR) != RESET)) + { + tmp1 = hi2c->Mode; + tmp2 = hi2c->XferCount; + tmp3 = hi2c->State; + tmp4 = hi2c->PreviousState; + if((tmp1 == HAL_I2C_MODE_SLAVE) && (tmp2 == 0U) && \ + ((tmp3 == HAL_I2C_STATE_BUSY_TX) || (tmp3 == HAL_I2C_STATE_BUSY_TX_LISTEN) || \ + ((tmp3 == HAL_I2C_STATE_LISTEN) && (tmp4 == I2C_STATE_SLAVE_BUSY_TX)))) + { + I2C_Slave_AF(hi2c); + } + else + { + hi2c->ErrorCode |= HAL_I2C_ERROR_AF; + + /* Do not generate a STOP in case of Slave receive non acknowledge during transfer (mean not at the end of transfer) */ + if(hi2c->Mode == HAL_I2C_MODE_MASTER) + { + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1,I2C_CR1_STOP); + } + + /* Clear AF flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + } + } + + /* I2C Over-Run/Under-Run interrupt occurred -------------------------------*/ + if(((sr1itflags & I2C_FLAG_OVR) != RESET) && ((itsources & I2C_IT_ERR) != RESET)) + { + hi2c->ErrorCode |= HAL_I2C_ERROR_OVR; + /* Clear OVR flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_OVR); + } + + /* Call the Error Callback in case of Error detected -----------------------*/ + if(hi2c->ErrorCode != HAL_I2C_ERROR_NONE) + { + I2C_ITError(hi2c); + } +} + +/** + * @brief Master Tx Transfer completed callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_MasterTxCpltCallback can be implemented in the user file + */ +} + +/** + * @brief Master Rx Transfer completed callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_MasterRxCpltCallback can be implemented in the user file + */ +} + +/** @brief Slave Tx Transfer completed callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_SlaveTxCpltCallback can be implemented in the user file + */ +} + +/** + * @brief Slave Rx Transfer completed callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_SlaveRxCpltCallback can be implemented in the user file + */ +} + +/** + * @brief Slave Address Match callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param TransferDirection Master request Transfer Direction (Write/Read), value of @ref I2C_XferOptions_definition + * @param AddrMatchCode Address Match Code + * @retval None + */ +__weak void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + UNUSED(TransferDirection); + UNUSED(AddrMatchCode); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_AddrCallback can be implemented in the user file + */ +} + +/** + * @brief Listen Complete callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_ListenCpltCallback can be implemented in the user file + */ +} + +/** + * @brief Memory Tx Transfer completed callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_MemTxCpltCallback can be implemented in the user file + */ +} + +/** + * @brief Memory Rx Transfer completed callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_MemRxCpltCallback can be implemented in the user file + */ +} + +/** + * @brief I2C error callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_ErrorCallback can be implemented in the user file + */ +} + +/** + * @brief I2C abort callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_AbortCpltCallback could be implemented in the user file + */ +} + +/** + * @} + */ + +/** @defgroup I2C_Exported_Functions_Group3 Peripheral State, Mode and Error functions + * @brief Peripheral State and Errors functions + * +@verbatim + =============================================================================== + ##### Peripheral State, Mode and Error functions ##### + =============================================================================== + [..] + This subsection permits to get in run-time the status of the peripheral + and the data flow. + +@endverbatim + * @{ + */ + +/** + * @brief Return the I2C handle state. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval HAL state + */ +HAL_I2C_StateTypeDef HAL_I2C_GetState(I2C_HandleTypeDef *hi2c) +{ + /* Return I2C handle state */ + return hi2c->State; +} + +/** + * @brief Return the I2C Master, Slave, Memory or no mode. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL mode + */ +HAL_I2C_ModeTypeDef HAL_I2C_GetMode(I2C_HandleTypeDef *hi2c) +{ + return hi2c->Mode; +} + +/** + * @brief Return the I2C error code + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval I2C Error Code + */ +uint32_t HAL_I2C_GetError(I2C_HandleTypeDef *hi2c) +{ + return hi2c->ErrorCode; +} + +/** + * @} + */ + +/** + * @brief Handle TXE flag for Master + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_MasterTransmit_TXE(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ + uint32_t CurrentState = hi2c->State; + uint32_t CurrentMode = hi2c->Mode; + uint32_t CurrentXferOptions = hi2c->XferOptions; + + if((hi2c->XferSize == 0U) && (CurrentState == HAL_I2C_STATE_BUSY_TX)) + { + /* Call TxCpltCallback() directly if no stop mode is set */ + if((CurrentXferOptions != I2C_FIRST_AND_LAST_FRAME) && (CurrentXferOptions != I2C_LAST_FRAME) && (CurrentXferOptions != I2C_NO_OPTION_FRAME)) + { + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + hi2c->PreviousState = I2C_STATE_MASTER_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + + HAL_I2C_MasterTxCpltCallback(hi2c); + } + else /* Generate Stop condition then Call TxCpltCallback() */ + { + /* Disable EVT, BUF and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + + if(hi2c->Mode == HAL_I2C_MODE_MEM) + { + hi2c->Mode = HAL_I2C_MODE_NONE; + HAL_I2C_MemTxCpltCallback(hi2c); + } + else + { + hi2c->Mode = HAL_I2C_MODE_NONE; + HAL_I2C_MasterTxCpltCallback(hi2c); + } + } + } + else if((CurrentState == HAL_I2C_STATE_BUSY_TX) || \ + ((CurrentMode == HAL_I2C_MODE_MEM) && (CurrentState == HAL_I2C_STATE_BUSY_RX))) + { + if(hi2c->XferCount == 0U) + { + /* Disable BUF interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); + } + else + { + if(hi2c->Mode == HAL_I2C_MODE_MEM) + { + if(hi2c->EventCount == 0) + { + /* If Memory address size is 8Bit */ + if(hi2c->MemaddSize == I2C_MEMADD_SIZE_8BIT) + { + /* Send Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_LSB(hi2c->Memaddress); + + hi2c->EventCount += 2; + } + /* If Memory address size is 16Bit */ + else + { + /* Send MSB of Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_MSB(hi2c->Memaddress); + + hi2c->EventCount++; + } + } + else if(hi2c->EventCount == 1) + { + /* Send LSB of Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_LSB(hi2c->Memaddress); + + hi2c->EventCount++; + } + else if(hi2c->EventCount == 2) + { + if(hi2c->State == HAL_I2C_STATE_BUSY_RX) + { + /* Generate Restart */ + hi2c->Instance->CR1 |= I2C_CR1_START; + } + else if(hi2c->State == HAL_I2C_STATE_BUSY_TX) + { + /* Write data to DR */ + hi2c->Instance->DR = (*hi2c->pBuffPtr++); + hi2c->XferCount--; + } + } + } + else + { + /* Write data to DR */ + hi2c->Instance->DR = (*hi2c->pBuffPtr++); + hi2c->XferCount--; + } + } + } + return HAL_OK; +} + +/** + * @brief Handle BTF flag for Master transmitter + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_MasterTransmit_BTF(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ + uint32_t CurrentXferOptions = hi2c->XferOptions; + + if(hi2c->State == HAL_I2C_STATE_BUSY_TX) + { + if(hi2c->XferCount != 0U) + { + /* Write data to DR */ + hi2c->Instance->DR = (*hi2c->pBuffPtr++); + hi2c->XferCount--; + } + else + { + /* Call TxCpltCallback() directly if no stop mode is set */ + if((CurrentXferOptions != I2C_FIRST_AND_LAST_FRAME) && (CurrentXferOptions != I2C_LAST_FRAME) && (CurrentXferOptions != I2C_NO_OPTION_FRAME)) + { + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + hi2c->PreviousState = I2C_STATE_MASTER_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + + HAL_I2C_MasterTxCpltCallback(hi2c); + } + else /* Generate Stop condition then Call TxCpltCallback() */ + { + /* Disable EVT, BUF and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + + if(hi2c->Mode == HAL_I2C_MODE_MEM) + { + hi2c->Mode = HAL_I2C_MODE_NONE; + + HAL_I2C_MemTxCpltCallback(hi2c); + } + else + { + hi2c->Mode = HAL_I2C_MODE_NONE; + + HAL_I2C_MasterTxCpltCallback(hi2c); + } + } + } + } + return HAL_OK; +} + +/** + * @brief Handle RXNE flag for Master + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_MasterReceive_RXNE(I2C_HandleTypeDef *hi2c) +{ + if(hi2c->State == HAL_I2C_STATE_BUSY_RX) + { + uint32_t tmp = 0U; + + tmp = hi2c->XferCount; + if(tmp > 3U) + { + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferCount--; + + if(hi2c->XferCount == 3) + { + /* Disable BUF interrupt, this help to treat correctly the last 4 bytes + on BTF subroutine */ + /* Disable BUF interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); + } + } + else if((tmp == 1U) || (tmp == 0U)) + { + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + /* Disable EVT, BUF and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferCount--; + + hi2c->State = HAL_I2C_STATE_READY; + hi2c->PreviousState = I2C_STATE_NONE; + + if(hi2c->Mode == HAL_I2C_MODE_MEM) + { + hi2c->Mode = HAL_I2C_MODE_NONE; + HAL_I2C_MemRxCpltCallback(hi2c); + } + else + { + hi2c->Mode = HAL_I2C_MODE_NONE; + HAL_I2C_MasterRxCpltCallback(hi2c); + } + } + } + return HAL_OK; +} + +/** + * @brief Handle BTF flag for Master receiver + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_MasterReceive_BTF(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ + uint32_t CurrentXferOptions = hi2c->XferOptions; + + if(hi2c->XferCount == 4U) + { + /* Disable BUF interrupt, this help to treat correctly the last 2 bytes + on BTF subroutine if there is a reception delay between N-1 and N byte */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferCount--; + } + else if(hi2c->XferCount == 3U) + { + /* Disable BUF interrupt, this help to treat correctly the last 2 bytes + on BTF subroutine if there is a reception delay between N-1 and N byte */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); + + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferCount--; + } + else if(hi2c->XferCount == 2U) + { + /* Prepare next transfer or stop current transfer */ + if((CurrentXferOptions == I2C_NEXT_FRAME) || (CurrentXferOptions == I2C_FIRST_FRAME)) + { + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + /* Generate ReStart */ + hi2c->Instance->CR1 |= I2C_CR1_START; + } + else + { + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + } + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferCount--; + + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferCount--; + + /* Disable EVT and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + hi2c->State = HAL_I2C_STATE_READY; + hi2c->PreviousState = I2C_STATE_NONE; + + if(hi2c->Mode == HAL_I2C_MODE_MEM) + { + hi2c->Mode = HAL_I2C_MODE_NONE; + + HAL_I2C_MemRxCpltCallback(hi2c); + } + else + { + hi2c->Mode = HAL_I2C_MODE_NONE; + + HAL_I2C_MasterRxCpltCallback(hi2c); + } + } + else + { + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferCount--; + } + return HAL_OK; +} + +/** + * @brief Handle SB flag for Master + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_Master_SB(I2C_HandleTypeDef *hi2c) +{ + if(hi2c->Mode == HAL_I2C_MODE_MEM) + { + if(hi2c->EventCount == 0U) + { + /* Send slave address */ + hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(hi2c->Devaddress); + } + else + { + hi2c->Instance->DR = I2C_7BIT_ADD_READ(hi2c->Devaddress); + } + } + else + { + if(hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_7BIT) + { + /* Send slave 7 Bits address */ + if(hi2c->State == HAL_I2C_STATE_BUSY_TX) + { + hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(hi2c->Devaddress); + } + else + { + hi2c->Instance->DR = I2C_7BIT_ADD_READ(hi2c->Devaddress); + } + } + else + { + if(hi2c->EventCount == 0U) + { + /* Send header of slave address */ + hi2c->Instance->DR = I2C_10BIT_HEADER_WRITE(hi2c->Devaddress); + } + else if(hi2c->EventCount == 1U) + { + /* Send header of slave address */ + hi2c->Instance->DR = I2C_10BIT_HEADER_READ(hi2c->Devaddress); + } + } + } + + return HAL_OK; +} + +/** + * @brief Handle ADD10 flag for Master + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_Master_ADD10(I2C_HandleTypeDef *hi2c) +{ + /* Send slave address */ + hi2c->Instance->DR = I2C_10BIT_ADDRESS(hi2c->Devaddress); + + return HAL_OK; +} + +/** + * @brief Handle ADDR flag for Master + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_Master_ADDR(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ + uint32_t CurrentMode = hi2c->Mode; + uint32_t CurrentXferOptions = hi2c->XferOptions; + uint32_t Prev_State = hi2c->PreviousState; + + if(hi2c->State == HAL_I2C_STATE_BUSY_RX) + { + if((hi2c->EventCount == 0U) && (CurrentMode == HAL_I2C_MODE_MEM)) + { + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + else if((hi2c->EventCount == 0U) && (hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_10BIT)) + { + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Restart */ + hi2c->Instance->CR1 |= I2C_CR1_START; + + hi2c->EventCount++; + } + else + { + if(hi2c->XferCount == 0U) + { + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + } + else if(hi2c->XferCount == 1U) + { + if(CurrentXferOptions == I2C_NO_OPTION_FRAME) + { + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + if((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) + { + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + else + { + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + } + } + /* Prepare next transfer or stop current transfer */ + else if((CurrentXferOptions != I2C_FIRST_AND_LAST_FRAME) && (CurrentXferOptions != I2C_LAST_FRAME) \ + && (Prev_State != I2C_STATE_MASTER_BUSY_RX)) + { + if(hi2c->XferOptions != I2C_NEXT_FRAME) + { + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + } + else + { + /* Enable Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + else + { + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + } + } + else if(hi2c->XferCount == 2U) + { + if(hi2c->XferOptions != I2C_NEXT_FRAME) + { + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + /* Enable Pos */ + hi2c->Instance->CR1 |= I2C_CR1_POS; + } + else + { + /* Enable Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + } + + if((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) + { + /* Enable Last DMA bit */ + hi2c->Instance->CR2 |= I2C_CR2_LAST; + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + else + { + /* Enable Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + if((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) + { + /* Enable Last DMA bit */ + hi2c->Instance->CR2 |= I2C_CR2_LAST; + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + + /* Reset Event counter */ + hi2c->EventCount = 0U; + } + } + else + { + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + + return HAL_OK; +} + +/** + * @brief Handle TXE flag for Slave + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_SlaveTransmit_TXE(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ + uint32_t CurrentState = hi2c->State; + + if(hi2c->XferCount != 0U) + { + /* Write data to DR */ + hi2c->Instance->DR = (*hi2c->pBuffPtr++); + hi2c->XferCount--; + + if((hi2c->XferCount == 0U) && (CurrentState == HAL_I2C_STATE_BUSY_TX_LISTEN)) + { + /* Last Byte is received, disable Interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); + + /* Set state at HAL_I2C_STATE_LISTEN */ + hi2c->PreviousState = I2C_STATE_SLAVE_BUSY_TX; + hi2c->State = HAL_I2C_STATE_LISTEN; + + /* Call the Tx complete callback to inform upper layer of the end of receive process */ + HAL_I2C_SlaveTxCpltCallback(hi2c); + } + } + return HAL_OK; +} + +/** + * @brief Handle BTF flag for Slave transmitter + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_SlaveTransmit_BTF(I2C_HandleTypeDef *hi2c) +{ + if(hi2c->XferCount != 0U) + { + /* Write data to DR */ + hi2c->Instance->DR = (*hi2c->pBuffPtr++); + hi2c->XferCount--; + } + return HAL_OK; +} + +/** + * @brief Handle RXNE flag for Slave + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_SlaveReceive_RXNE(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ + uint32_t CurrentState = hi2c->State; + + if(hi2c->XferCount != 0U) + { + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferCount--; + + if((hi2c->XferCount == 0U) && (CurrentState == HAL_I2C_STATE_BUSY_RX_LISTEN)) + { + /* Last Byte is received, disable Interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); + + /* Set state at HAL_I2C_STATE_LISTEN */ + hi2c->PreviousState = I2C_STATE_SLAVE_BUSY_RX; + hi2c->State = HAL_I2C_STATE_LISTEN; + + /* Call the Rx complete callback to inform upper layer of the end of receive process */ + HAL_I2C_SlaveRxCpltCallback(hi2c); + } + } + return HAL_OK; +} + +/** + * @brief Handle BTF flag for Slave receiver + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_SlaveReceive_BTF(I2C_HandleTypeDef *hi2c) +{ + if(hi2c->XferCount != 0U) + { + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferCount--; + } + return HAL_OK; +} + +/** + * @brief Handle ADD flag for Slave + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_Slave_ADDR(I2C_HandleTypeDef *hi2c) +{ + uint8_t TransferDirection = I2C_DIRECTION_RECEIVE; + uint16_t SlaveAddrCode = 0U; + + /* Transfer Direction requested by Master */ + if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TRA) == RESET) + { + TransferDirection = I2C_DIRECTION_TRANSMIT; + } + + if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_DUALF) == RESET) + { + SlaveAddrCode = hi2c->Init.OwnAddress1; + } + else + { + SlaveAddrCode = hi2c->Init.OwnAddress2; + } + + /* Call Slave Addr callback */ + HAL_I2C_AddrCallback(hi2c, TransferDirection, SlaveAddrCode); + + return HAL_OK; +} + +/** + * @brief Handle STOPF flag for Slave + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_Slave_STOPF(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ + uint32_t CurrentState = hi2c->State; + + /* Disable EVT, BUF and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Clear STOPF flag */ + __HAL_I2C_CLEAR_STOPFLAG(hi2c); + + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + /* If a DMA is ongoing, Update handle size context */ + if((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) + { + if((hi2c->State == HAL_I2C_STATE_BUSY_RX) || (hi2c->State == HAL_I2C_STATE_BUSY_RX_LISTEN)) + { + hi2c->XferCount = __HAL_DMA_GET_COUNTER(hi2c->hdmarx); + } + else + { + hi2c->XferCount = __HAL_DMA_GET_COUNTER(hi2c->hdmatx); + } + } + + /* All data are not transferred, so set error code accordingly */ + if(hi2c->XferCount != 0U) + { + /* Store Last receive data if any */ + if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) + { + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferCount--; + } + + /* Store Last receive data if any */ + if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET) + { + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + hi2c->XferCount--; + } + + /* Set ErrorCode corresponding to a Non-Acknowledge */ + //hi2c->ErrorCode |= HAL_I2C_ERROR_AF; + } + + if(hi2c->ErrorCode != HAL_I2C_ERROR_NONE) + { + /* Call the corresponding callback to inform upper layer of End of Transfer */ + I2C_ITError(hi2c); + } + else + { + if((CurrentState == HAL_I2C_STATE_LISTEN ) || (CurrentState == HAL_I2C_STATE_BUSY_RX_LISTEN) || \ + (CurrentState == HAL_I2C_STATE_BUSY_TX_LISTEN)) + { + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Call the Listen Complete callback, to inform upper layer of the end of Listen usecase */ + HAL_I2C_ListenCpltCallback(hi2c); + } + else + { + if((hi2c->PreviousState == I2C_STATE_SLAVE_BUSY_RX) || (CurrentState == HAL_I2C_STATE_BUSY_RX)) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + HAL_I2C_SlaveRxCpltCallback(hi2c); + } + } + } + return HAL_OK; +} + +/** + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_Slave_AF(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ + uint32_t CurrentState = hi2c->State; + uint32_t CurrentXferOptions = hi2c->XferOptions; + + if(((CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_LAST_FRAME)) && \ + (CurrentState == HAL_I2C_STATE_LISTEN)) + { + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + + /* Disable EVT, BUF and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Clear AF flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Call the Listen Complete callback, to inform upper layer of the end of Listen usecase */ + HAL_I2C_ListenCpltCallback(hi2c); + } + else if(CurrentState == HAL_I2C_STATE_BUSY_TX) + { + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->PreviousState = I2C_STATE_SLAVE_BUSY_TX; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Disable EVT, BUF and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Clear AF flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + HAL_I2C_SlaveTxCpltCallback(hi2c); + } + else + { + /* Clear AF flag only */ + /* State Listen, but XferOptions == FIRST or NEXT */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + } + + return HAL_OK; +} + +/** + * @brief I2C interrupts error process + * @param hi2c I2C handle. + * @retval None + */ +static void I2C_ITError(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ + uint32_t CurrentState = hi2c->State; + + if((CurrentState == HAL_I2C_STATE_BUSY_TX_LISTEN) || (CurrentState == HAL_I2C_STATE_BUSY_RX_LISTEN)) + { + /* keep HAL_I2C_STATE_LISTEN */ + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_LISTEN; + } + else + { + /* If state is an abort treatment on going, don't change state */ + /* This change will be do later */ + if((hi2c->State != HAL_I2C_STATE_ABORT) && ((hi2c->Instance->CR2 & I2C_CR2_DMAEN) != I2C_CR2_DMAEN)) + { + hi2c->State = HAL_I2C_STATE_READY; + } + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->Mode = HAL_I2C_MODE_NONE; + } + + /* Disable Pos bit in I2C CR1 when error occurred in Master/Mem Receive IT Process */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + + /* Abort DMA transfer */ + if((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) + { + hi2c->Instance->CR2 &= ~I2C_CR2_DMAEN; + + if(hi2c->hdmatx->State != HAL_DMA_STATE_READY) + { + /* Set the DMA Abort callback : + will lead to call HAL_I2C_ErrorCallback() at end of DMA abort procedure */ + hi2c->hdmatx->XferAbortCallback = I2C_DMAAbort; + + if(HAL_DMA_Abort_IT(hi2c->hdmatx) != HAL_OK) + { + /* Disable I2C peripheral to prevent dummy data in buffer */ + __HAL_I2C_DISABLE(hi2c); + + hi2c->State = HAL_I2C_STATE_READY; + + /* Call Directly XferAbortCallback function in case of error */ + hi2c->hdmatx->XferAbortCallback(hi2c->hdmatx); + } + } + else + { + /* Set the DMA Abort callback : + will lead to call HAL_I2C_ErrorCallback() at end of DMA abort procedure */ + hi2c->hdmarx->XferAbortCallback = I2C_DMAAbort; + + if(HAL_DMA_Abort_IT(hi2c->hdmarx) != HAL_OK) + { + /* Store Last receive data if any */ + if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET) + { + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + } + + /* Disable I2C peripheral to prevent dummy data in buffer */ + __HAL_I2C_DISABLE(hi2c); + + hi2c->State = HAL_I2C_STATE_READY; + + /* Call Directly hi2c->hdmarx->XferAbortCallback function in case of error */ + hi2c->hdmarx->XferAbortCallback(hi2c->hdmarx); + } + } + } + else if(hi2c->State == HAL_I2C_STATE_ABORT) + { + hi2c->State = HAL_I2C_STATE_READY; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Store Last receive data if any */ + if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET) + { + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + } + + /* Disable I2C peripheral to prevent dummy data in buffer */ + __HAL_I2C_DISABLE(hi2c); + + /* Call the corresponding callback to inform upper layer of End of Transfer */ + HAL_I2C_AbortCpltCallback(hi2c); + } + else + { + /* Store Last receive data if any */ + if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET) + { + /* Read data from DR */ + (*hi2c->pBuffPtr++) = hi2c->Instance->DR; + } + + /* Call user error callback */ + HAL_I2C_ErrorCallback(hi2c); + } + /* STOP Flag is not set after a NACK reception */ + /* So may inform upper layer that listen phase is stopped */ + /* during NACK error treatment */ + if((hi2c->State == HAL_I2C_STATE_LISTEN) && ((hi2c->ErrorCode & HAL_I2C_ERROR_AF) == HAL_I2C_ERROR_AF)) + { + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Call the Listen Complete callback, to inform upper layer of the end of Listen usecase */ + HAL_I2C_ListenCpltCallback(hi2c); + } +} + +/** + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @param DevAddress Target device address The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_MasterRequestWrite(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Timeout, uint32_t Tickstart) +{ + /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ + uint32_t CurrentXferOptions = hi2c->XferOptions; + + /* Generate Start condition if first transfer */ + if((CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_FIRST_FRAME) || (CurrentXferOptions == I2C_NO_OPTION_FRAME)) + { + /* Generate Start */ + hi2c->Instance->CR1 |= I2C_CR1_START; + } + else if(hi2c->PreviousState == I2C_STATE_MASTER_BUSY_RX) + { + /* Generate ReStart */ + hi2c->Instance->CR1 |= I2C_CR1_START; + } + + /* Wait until SB flag is set */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + if(hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_7BIT) + { + /* Send slave address */ + hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(DevAddress); + } + else + { + /* Send header of slave address */ + hi2c->Instance->DR = I2C_10BIT_HEADER_WRITE(DevAddress); + + /* Wait until ADD10 flag is set */ + if(I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADD10, Timeout, Tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + /* Send slave address */ + hi2c->Instance->DR = I2C_10BIT_ADDRESS(DevAddress); + } + + /* Wait until ADDR flag is set */ + if(I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + return HAL_OK; +} + +/** + * @brief Master sends target device address for read request. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @param DevAddress Target device address The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_MasterRequestRead(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Timeout, uint32_t Tickstart) +{ + /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ + uint32_t CurrentXferOptions = hi2c->XferOptions; + + /* Enable Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Generate Start condition if first transfer */ + if((CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_FIRST_FRAME) || (CurrentXferOptions == I2C_NO_OPTION_FRAME)) + { + /* Generate Start */ + hi2c->Instance->CR1 |= I2C_CR1_START; + } + else if(hi2c->PreviousState == I2C_STATE_MASTER_BUSY_TX) + { + /* Generate ReStart */ + hi2c->Instance->CR1 |= I2C_CR1_START; + } + + /* Wait until SB flag is set */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + if(hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_7BIT) + { + /* Send slave address */ + hi2c->Instance->DR = I2C_7BIT_ADD_READ(DevAddress); + } + else + { + /* Send header of slave address */ + hi2c->Instance->DR = I2C_10BIT_HEADER_WRITE(DevAddress); + + /* Wait until ADD10 flag is set */ + if(I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADD10, Timeout, Tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + /* Send slave address */ + hi2c->Instance->DR = I2C_10BIT_ADDRESS(DevAddress); + + /* Wait until ADDR flag is set */ + if(I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Restart */ + hi2c->Instance->CR1 |= I2C_CR1_START; + + /* Wait until SB flag is set */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + /* Send header of slave address */ + hi2c->Instance->DR = I2C_10BIT_HEADER_READ(DevAddress); + } + + /* Wait until ADDR flag is set */ + if(I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + return HAL_OK; +} + +/** + * @brief Master sends target device address followed by internal memory address for write request. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @param DevAddress Target device address + * @param MemAddress Internal memory address + * @param MemAddSize Size of internal memory address + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_RequestMemoryWrite(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout, uint32_t Tickstart) +{ + /* Generate Start */ + hi2c->Instance->CR1 |= I2C_CR1_START; + + /* Wait until SB flag is set */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + /* Send slave address */ + hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(DevAddress); + + /* Wait until ADDR flag is set */ + if(I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Wait until TXE flag is set */ + if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + /* If Memory address size is 8Bit */ + if(MemAddSize == I2C_MEMADD_SIZE_8BIT) + { + /* Send Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_LSB(MemAddress); + } + /* If Memory address size is 16Bit */ + else + { + /* Send MSB of Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_MSB(MemAddress); + + /* Wait until TXE flag is set */ + if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + /* Send LSB of Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_LSB(MemAddress); + } + + return HAL_OK; +} + +/** + * @brief Master sends target device address followed by internal memory address for read request. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @param DevAddress Target device address + * @param MemAddress Internal memory address + * @param MemAddSize Size of internal memory address + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_RequestMemoryRead(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout, uint32_t Tickstart) +{ + /* Enable Acknowledge */ + hi2c->Instance->CR1 |= I2C_CR1_ACK; + + /* Generate Start */ + hi2c->Instance->CR1 |= I2C_CR1_START; + + /* Wait until SB flag is set */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + /* Send slave address */ + hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(DevAddress); + + /* Wait until ADDR flag is set */ + if(I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Wait until TXE flag is set */ + if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + /* If Memory address size is 8Bit */ + if(MemAddSize == I2C_MEMADD_SIZE_8BIT) + { + /* Send Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_LSB(MemAddress); + } + /* If Memory address size is 16Bit */ + else + { + /* Send MSB of Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_MSB(MemAddress); + + /* Wait until TXE flag is set */ + if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + /* Send LSB of Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_LSB(MemAddress); + } + + /* Wait until TXE flag is set */ + if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + /* Generate Restart */ + hi2c->Instance->CR1 |= I2C_CR1_START; + + /* Wait until SB flag is set */ + if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) + { + return HAL_TIMEOUT; + } + + /* Send slave address */ + hi2c->Instance->DR = I2C_7BIT_ADD_READ(DevAddress); + + /* Wait until ADDR flag is set */ + if(I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) + { + if(hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + return HAL_ERROR; + } + else + { + return HAL_TIMEOUT; + } + } + + return HAL_OK; +} + +/** + * @brief DMA I2C process complete callback. + * @param hdma DMA handle + * @retval None + */ +static void I2C_DMAXferCplt(DMA_HandleTypeDef *hdma) +{ + I2C_HandleTypeDef* hi2c = (I2C_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent; + + /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ + uint32_t CurrentState = hi2c->State; + uint32_t CurrentMode = hi2c->Mode; + + if((CurrentState == HAL_I2C_STATE_BUSY_TX) || ((CurrentState == HAL_I2C_STATE_BUSY_RX) && (CurrentMode == HAL_I2C_MODE_SLAVE))) + { + /* Disable DMA Request */ + hi2c->Instance->CR2 &= ~I2C_CR2_DMAEN; + + hi2c->XferCount = 0U; + + /* Enable EVT and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + } + else + { + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + + /* Disable Last DMA */ + hi2c->Instance->CR2 &= ~I2C_CR2_LAST; + + /* Disable DMA Request */ + hi2c->Instance->CR2 &= ~I2C_CR2_DMAEN; + + hi2c->XferCount = 0U; + + /* Check if Errors has been detected during transfer */ + if(hi2c->ErrorCode != HAL_I2C_ERROR_NONE) + { + HAL_I2C_ErrorCallback(hi2c); + } + else + { + hi2c->State = HAL_I2C_STATE_READY; + + if(hi2c->Mode == HAL_I2C_MODE_MEM) + { + hi2c->Mode = HAL_I2C_MODE_NONE; + + HAL_I2C_MemRxCpltCallback(hi2c); + } + else + { + hi2c->Mode = HAL_I2C_MODE_NONE; + + HAL_I2C_MasterRxCpltCallback(hi2c); + } + } + } +} + +/** + * @brief DMA I2C communication error callback. + * @param hdma DMA handle + * @retval None + */ +static void I2C_DMAError(DMA_HandleTypeDef *hdma) +{ + I2C_HandleTypeDef* hi2c = (I2C_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent; + + /* Ignore DMA FIFO error */ + if(HAL_DMA_GetError(hdma) != HAL_DMA_ERROR_FE) + { + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + hi2c->XferCount = 0U; + + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA; + + HAL_I2C_ErrorCallback(hi2c); + } +} + +/** + * @brief DMA I2C communication abort callback + * (To be called at end of DMA Abort procedure). + * @param hdma DMA handle. + * @retval None + */ +static void I2C_DMAAbort(DMA_HandleTypeDef *hdma) +{ + I2C_HandleTypeDef* hi2c = ( I2C_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; + + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + hi2c->XferCount = 0U; + + /* Reset XferAbortCallback */ + hi2c->hdmatx->XferAbortCallback = NULL; + hi2c->hdmarx->XferAbortCallback = NULL; + + /* Check if come from abort from user */ + if(hi2c->State == HAL_I2C_STATE_ABORT) + { + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Disable I2C peripheral to prevent dummy data in buffer */ + __HAL_I2C_DISABLE(hi2c); + + /* Call the corresponding callback to inform upper layer of End of Transfer */ + HAL_I2C_AbortCpltCallback(hi2c); + } + else + { + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Disable I2C peripheral to prevent dummy data in buffer */ + __HAL_I2C_DISABLE(hi2c); + + /* Call the corresponding callback to inform upper layer of End of Transfer */ + HAL_I2C_ErrorCallback(hi2c); + } +} + +/** + * @brief This function handles I2C Communication Timeout. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @param Flag specifies the I2C flag to check. + * @param Status The new Flag status (SET or RESET). + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, FlagStatus Status, uint32_t Timeout, uint32_t Tickstart) +{ + /* Wait until flag is set */ + while((__HAL_I2C_GET_FLAG(hi2c, Flag) ? SET : RESET) == Status) + { + /* Check for the Timeout */ + if(Timeout != HAL_MAX_DELAY) + { + if((Timeout == 0U)||((HAL_GetTick() - Tickstart ) > Timeout)) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + } + + return HAL_OK; +} + +/** + * @brief This function handles I2C Communication Timeout for Master addressing phase. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @param Flag specifies the I2C flag to check. + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_WaitOnMasterAddressFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, uint32_t Timeout, uint32_t Tickstart) +{ + while(__HAL_I2C_GET_FLAG(hi2c, Flag) == RESET) + { + if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) + { + /* Generate Stop */ + hi2c->Instance->CR1 |= I2C_CR1_STOP; + + /* Clear AF Flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + + hi2c->ErrorCode = HAL_I2C_ERROR_AF; + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + + /* Check for the Timeout */ + if(Timeout != HAL_MAX_DELAY) + { + if((Timeout == 0U)||((HAL_GetTick() - Tickstart ) > Timeout)) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + } + return HAL_OK; +} + +/** + * @brief This function handles I2C Communication Timeout for specific usage of TXE flag. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_WaitOnTXEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) +{ + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET) + { + /* Check if a NACK is detected */ + if(I2C_IsAcknowledgeFailed(hi2c) != HAL_OK) + { + return HAL_ERROR; + } + + /* Check for the Timeout */ + if(Timeout != HAL_MAX_DELAY) + { + if((Timeout == 0U) || ((HAL_GetTick()-Tickstart) > Timeout)) + { + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + } + return HAL_OK; +} + +/** + * @brief This function handles I2C Communication Timeout for specific usage of BTF flag. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_WaitOnBTFFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) +{ + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == RESET) + { + /* Check if a NACK is detected */ + if(I2C_IsAcknowledgeFailed(hi2c) != HAL_OK) + { + return HAL_ERROR; + } + + /* Check for the Timeout */ + if(Timeout != HAL_MAX_DELAY) + { + if((Timeout == 0U) || ((HAL_GetTick()-Tickstart) > Timeout)) + { + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + } + return HAL_OK; +} + +/** + * @brief This function handles I2C Communication Timeout for specific usage of STOP flag. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_WaitOnSTOPFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) +{ + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == RESET) + { + /* Check if a NACK is detected */ + if(I2C_IsAcknowledgeFailed(hi2c) != HAL_OK) + { + return HAL_ERROR; + } + + /* Check for the Timeout */ + if((Timeout == 0U) || ((HAL_GetTick()-Tickstart) > Timeout)) + { + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + return HAL_OK; +} + +/** + * @brief This function handles I2C Communication Timeout for specific usage of RXNE flag. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_WaitOnRXNEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) +{ + + while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == RESET) + { + /* Check if a STOPF is detected */ + if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET) + { + /* Clear STOP Flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); + + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + + /* Check for the Timeout */ + if((Timeout == 0U) || ((HAL_GetTick()-Tickstart) > Timeout)) + { + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_TIMEOUT; + } + } + return HAL_OK; +} + +/** + * @brief This function handles Acknowledge failed detection during an I2C Communication. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_IsAcknowledgeFailed(I2C_HandleTypeDef *hi2c) +{ + if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) + { + /* Clear NACKF Flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + + hi2c->ErrorCode = HAL_I2C_ERROR_AF; + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State= HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + return HAL_OK; +} +/** + * @} + */ + +#endif /* HAL_I2C_MODULE_ENABLED */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c b/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c new file mode 100644 index 00000000..de8f1602 --- /dev/null +++ b/Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c @@ -0,0 +1,204 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_i2c_ex.c + * @author MCD Application Team + * @brief I2C Extension HAL module driver. + * This file provides firmware functions to manage the following + * functionalities of I2C extension peripheral: + * + Extension features functions + * + @verbatim + ============================================================================== + ##### I2C peripheral extension features ##### + ============================================================================== + + [..] Comparing to other previous devices, the I2C interface for STM32F427xx/437xx/ + 429xx/439xx devices contains the following additional features : + + (+) Possibility to disable or enable Analog Noise Filter + (+) Use of a configured Digital Noise Filter + + ##### How to use this driver ##### + ============================================================================== + [..] This driver provides functions to configure Noise Filter + (#) Configure I2C Analog noise filter using the function HAL_I2C_AnalogFilter_Config() + (#) Configure I2C Digital noise filter using the function HAL_I2C_DigitalFilter_Config() + + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @defgroup I2CEx I2CEx + * @brief I2C HAL module driver + * @{ + */ + +#ifdef HAL_I2C_MODULE_ENABLED + +#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) ||\ + defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F411xE) || defined(STM32F446xx) ||\ + defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F413xx) || defined(STM32F423xx) +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Exported functions --------------------------------------------------------*/ +/** @defgroup I2CEx_Exported_Functions I2C Exported Functions + * @{ + */ + + +/** @defgroup I2CEx_Exported_Functions_Group1 Extension features functions + * @brief Extension features functions + * +@verbatim + =============================================================================== + ##### Extension features functions ##### + =============================================================================== + [..] This section provides functions allowing to: + (+) Configure Noise Filters + +@endverbatim + * @{ + */ + +/** + * @brief Configures I2C Analog noise filter. + * @param hi2c pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2Cx peripheral. + * @param AnalogFilter new state of the Analog filter. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2CEx_ConfigAnalogFilter(I2C_HandleTypeDef *hi2c, uint32_t AnalogFilter) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance)); + assert_param(IS_I2C_ANALOG_FILTER(AnalogFilter)); + + if(hi2c->State == HAL_I2C_STATE_READY) + { + hi2c->State = HAL_I2C_STATE_BUSY; + + /* Disable the selected I2C peripheral */ + __HAL_I2C_DISABLE(hi2c); + + /* Reset I2Cx ANOFF bit */ + hi2c->Instance->FLTR &= ~(I2C_FLTR_ANOFF); + + /* Disable the analog filter */ + hi2c->Instance->FLTR |= AnalogFilter; + + __HAL_I2C_ENABLE(hi2c); + + hi2c->State = HAL_I2C_STATE_READY; + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Configures I2C Digital noise filter. + * @param hi2c pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2Cx peripheral. + * @param DigitalFilter Coefficient of digital noise filter between 0x00 and 0x0F. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2CEx_ConfigDigitalFilter(I2C_HandleTypeDef *hi2c, uint32_t DigitalFilter) +{ + uint16_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance)); + assert_param(IS_I2C_DIGITAL_FILTER(DigitalFilter)); + + if(hi2c->State == HAL_I2C_STATE_READY) + { + hi2c->State = HAL_I2C_STATE_BUSY; + + /* Disable the selected I2C peripheral */ + __HAL_I2C_DISABLE(hi2c); + + /* Get the old register value */ + tmpreg = hi2c->Instance->FLTR; + + /* Reset I2Cx DNF bit [3:0] */ + tmpreg &= ~(I2C_FLTR_DNF); + + /* Set I2Cx DNF coefficient */ + tmpreg |= DigitalFilter; + + /* Store the new register value */ + hi2c->Instance->FLTR = tmpreg; + + __HAL_I2C_ENABLE(hi2c); + + hi2c->State = HAL_I2C_STATE_READY; + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @} + */ + +/** + * @} + */ +#endif /* STM32F427xx || STM32F429xx || STM32F437xx || STM32F439xx || STM32F401xC ||\ + STM32F401xE || STM32F446xx || STM32F469xx || STM32F479xx || STM32F413xx ||\ + STM32F423xx */ + +#endif /* HAL_I2C_MODULE_ENABLED */ +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Firmware/Board/v3/Inc/i2c.h b/Firmware/Board/v3/Inc/i2c.h new file mode 100644 index 00000000..f449b88a --- /dev/null +++ b/Firmware/Board/v3/Inc/i2c.h @@ -0,0 +1,91 @@ +/** + ****************************************************************************** + * File Name : I2C.h + * Description : This file provides code for the configuration + * of the I2C instances. + ****************************************************************************** + * This notice applies to any and all portions of this file + * that are not between comment pairs USER CODE BEGIN and + * USER CODE END. Other portions of this file, whether + * inserted by the user or by software development tools + * are owned by their respective copyright owners. + * + * Copyright (c) 2018 STMicroelectronics International N.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted, provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of STMicroelectronics nor the names of other + * contributors to this software may be used to endorse or promote products + * derived from this software without specific written permission. + * 4. This software, including modifications and/or derivative works of this + * software, must execute solely and exclusively on microcontroller or + * microprocessor devices manufactured by or for STMicroelectronics. + * 5. Redistribution and use of this software other than as permitted under + * this license is void and will automatically terminate your rights under + * this license. + * + * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY + * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT + * SHALL STMICROELECTRONICS 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. + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __i2c_H +#define __i2c_H +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern I2C_HandleTypeDef hi2c1; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +extern void _Error_Handler(char *, int); + +void MX_I2C1_Init(uint8_t addr); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif +#endif /*__ i2c_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Firmware/Board/v3/Inc/main.h b/Firmware/Board/v3/Inc/main.h index 25d37a98..0a307122 100644 --- a/Firmware/Board/v3/Inc/main.h +++ b/Firmware/Board/v3/Inc/main.h @@ -54,6 +54,7 @@ /* Includes ------------------------------------------------------------------*/ /* USER CODE BEGIN Includes */ +#include "stm32f4xx_hal.h" #if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 1 \ || HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 2 diff --git a/Firmware/Board/v3/Inc/stm32f4xx_hal_conf.h b/Firmware/Board/v3/Inc/stm32f4xx_hal_conf.h index d0f48f56..b3ef59aa 100644 --- a/Firmware/Board/v3/Inc/stm32f4xx_hal_conf.h +++ b/Firmware/Board/v3/Inc/stm32f4xx_hal_conf.h @@ -65,7 +65,7 @@ /* #define HAL_SRAM_MODULE_ENABLED */ /* #define HAL_SDRAM_MODULE_ENABLED */ /* #define HAL_HASH_MODULE_ENABLED */ -/* #define HAL_I2C_MODULE_ENABLED */ +#define HAL_I2C_MODULE_ENABLED /* #define HAL_I2S_MODULE_ENABLED */ /* #define HAL_IWDG_MODULE_ENABLED */ /* #define HAL_LTDC_MODULE_ENABLED */ diff --git a/Firmware/Board/v3/Inc/usbd_cdc_if.h b/Firmware/Board/v3/Inc/usbd_cdc_if.h index c15e8b91..ed1d6705 100644 --- a/Firmware/Board/v3/Inc/usbd_cdc_if.h +++ b/Firmware/Board/v3/Inc/usbd_cdc_if.h @@ -132,7 +132,7 @@ extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS; * @{ */ -uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len); +uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len, uint8_t endpoint_pair); /* USER CODE BEGIN EXPORTED_FUNCTIONS */ /* USER CODE END EXPORTED_FUNCTIONS */ diff --git a/Firmware/Board/v3/Inc/usbd_conf.h b/Firmware/Board/v3/Inc/usbd_conf.h index bf276186..fe7867dd 100644 --- a/Firmware/Board/v3/Inc/usbd_conf.h +++ b/Firmware/Board/v3/Inc/usbd_conf.h @@ -89,6 +89,7 @@ * @brief Defines for configuration of the Usb device. * @{ */ +#define MS_VendorCode 'P' /*---------- -----------*/ #define USBD_MAX_NUM_INTERFACES 1 @@ -97,7 +98,7 @@ /*---------- -----------*/ #define USBD_MAX_STR_DESC_SIZ 512 /*---------- -----------*/ -#define USBD_SUPPORT_USER_STRING 0 +#define USBD_SUPPORT_USER_STRING 1 /*---------- -----------*/ #define USBD_DEBUG_LEVEL 0 /*---------- -----------*/ diff --git a/Firmware/Board/v3/Inc/usbd_desc.h b/Firmware/Board/v3/Inc/usbd_desc.h index d791d3d4..2a74de31 100644 --- a/Firmware/Board/v3/Inc/usbd_desc.h +++ b/Firmware/Board/v3/Inc/usbd_desc.h @@ -133,6 +133,8 @@ extern USBD_DescriptorsTypeDef FS_Desc; /* USER CODE BEGIN EXPORTED_FUNCTIONS */ +uint8_t * USBD_UsrStrDescriptor(struct _USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length); + /* USER CODE END EXPORTED_FUNCTIONS */ /** diff --git a/Firmware/Board/v3/Makefile b/Firmware/Board/v3/Makefile index edac2cb1..11a23ae6 100644 --- a/Firmware/Board/v3/Makefile +++ b/Firmware/Board/v3/Makefile @@ -58,7 +58,10 @@ Middlewares/Third_Party/FreeRTOS/Source/timers.c \ Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c \ Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c \ Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c \ -Middlewares/Third_Party/FreeRTOS/Source/event_groups.c +Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \ +Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c \ +Src/i2c.c \ +Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c ASM_SOURCES = \ startup_stm32f405xx.s diff --git a/Firmware/Board/v3/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc/usbd_cdc.h b/Firmware/Board/v3/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc/usbd_cdc.h index d937b2e8..3bb73c6e 100644 --- a/Firmware/Board/v3/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc/usbd_cdc.h +++ b/Firmware/Board/v3/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc/usbd_cdc.h @@ -52,13 +52,15 @@ #define CDC_IN_EP 0x81 /* EP1 for data IN */ #define CDC_OUT_EP 0x01 /* EP1 for data OUT */ #define CDC_CMD_EP 0x82 /* EP2 for CDC commands */ +#define ODRIVE_IN_EP 0x83 /* EP3 IN: ODrive device TX endpoint */ +#define ODRIVE_OUT_EP 0x03 /* EP3 OUT: ODrive device RX endpoint */ /* CDC Endpoints parameters: you can fine tune these values depending on the needed baudrates and performance. */ -#define CDC_DATA_HS_MAX_PACKET_SIZE 512 /* Endpoint IN & OUT Packet size */ +#define CDC_DATA_HS_MAX_PACKET_SIZE 64 /* Endpoint IN & OUT Packet size */ #define CDC_DATA_FS_MAX_PACKET_SIZE 64 /* Endpoint IN & OUT Packet size */ #define CDC_CMD_PACKET_SIZE 8 /* Control Endpoint Packet size */ -#define USB_CDC_CONFIG_DESC_SIZ 67 +#define USB_CDC_CONFIG_DESC_SIZ (67 + 39) #define CDC_DATA_HS_IN_PACKET_SIZE CDC_DATA_HS_MAX_PACKET_SIZE #define CDC_DATA_HS_OUT_PACKET_SIZE CDC_DATA_HS_MAX_PACKET_SIZE @@ -103,7 +105,7 @@ typedef struct _USBD_CDC_Itf int8_t (* Init) (void); int8_t (* DeInit) (void); int8_t (* Control) (uint8_t, uint8_t * , uint16_t); - int8_t (* Receive) (uint8_t *, uint32_t *); + int8_t (* Receive) (uint8_t *, uint32_t *, uint8_t); }USBD_CDC_ItfTypeDef; @@ -156,9 +158,9 @@ uint8_t USBD_CDC_SetTxBuffer (USBD_HandleTypeDef *pdev, uint8_t USBD_CDC_SetRxBuffer (USBD_HandleTypeDef *pdev, uint8_t *pbuff); -uint8_t USBD_CDC_ReceivePacket (USBD_HandleTypeDef *pdev); +uint8_t USBD_CDC_ReceivePacket (USBD_HandleTypeDef *pdev, uint8_t endpoint_pair); -uint8_t USBD_CDC_TransmitPacket (USBD_HandleTypeDef *pdev); +uint8_t USBD_CDC_TransmitPacket (USBD_HandleTypeDef *pdev, uint8_t endpoint_pair); /** * @} */ diff --git a/Firmware/Board/v3/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c b/Firmware/Board/v3/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c index 24465641..2bc01513 100644 --- a/Firmware/Board/v3/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c +++ b/Firmware/Board/v3/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c @@ -132,6 +132,9 @@ static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc (uint16_t *length); uint8_t *USBD_CDC_GetDeviceQualifierDescriptor (uint16_t *length); +static uint8_t USBD_WinUSBComm_SetupVendor(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); +//static uint8_t * USBD_GetUsrStrDescriptor(struct _USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length); + /* USB Standard Device Descriptor */ __ALIGN_BEGIN static uint8_t USBD_CDC_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END = { @@ -173,24 +176,37 @@ USBD_ClassTypeDef USBD_CDC = USBD_CDC_GetFSCfgDesc, USBD_CDC_GetOtherSpeedCfgDesc, USBD_CDC_GetDeviceQualifierDescriptor, + USBD_UsrStrDescriptor }; /* USB CDC device Configuration Descriptor */ -__ALIGN_BEGIN uint8_t USBD_CDC_CfgHSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END = +__ALIGN_BEGIN uint8_t USBD_CDC_CfgDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END = { /*Configuration Descriptor*/ 0x09, /* bLength: Configuration Descriptor size */ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ USB_CDC_CONFIG_DESC_SIZ, /* wTotalLength:no of returned bytes */ 0x00, - 0x02, /* bNumInterfaces: 2 interface */ + 0x03, /* bNumInterfaces: 3 interfaces (2 for CDC, 1 custom) */ 0x01, /* bConfigurationValue: Configuration value */ 0x00, /* iConfiguration: Index of string descriptor describing the configuration */ 0xC0, /* bmAttributes: self powered */ 0x32, /* MaxPower 0 mA */ + + /////////////////////////////////////////////////////////////////////////////// + + /* Interface Association Descriptor: CDC device (virtual com port) */ + 0x08, /* bLength: IAD size */ + 0x0B, /* bDescriptorType: Interface Association Descriptor */ + 0x00, /* bFirstInterface */ + 0x02, /* bInterfaceCount */ + 0x02, /* bFunctionClass: Communication Interface Class */ + 0x02, /* bFunctionSubClass: Abstract Control Model */ + 0x01, /* bFunctionProtocol: Common AT commands */ + 0x00, /* iFunction */ /*---------------------------------------------------------------------------*/ - + /*Interface Descriptor */ 0x09, /* bLength: Interface Descriptor size */ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */ @@ -202,7 +218,7 @@ __ALIGN_BEGIN uint8_t USBD_CDC_CfgHSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END = 0x02, /* bInterfaceSubClass: Abstract Control Model */ 0x01, /* bInterfaceProtocol: Common AT commands */ 0x00, /* iInterface: */ - + /*Header Functional Descriptor*/ 0x05, /* bLength: Endpoint Descriptor size */ 0x24, /* bDescriptorType: CS_INTERFACE */ @@ -229,7 +245,7 @@ __ALIGN_BEGIN uint8_t USBD_CDC_CfgHSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END = 0x06, /* bDescriptorSubtype: Union func desc */ 0x00, /* bMasterInterface: Communication class interface */ 0x01, /* bSlaveInterface0: Data Class Interface */ - + /*Endpoint 2 Descriptor*/ 0x07, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ @@ -267,196 +283,52 @@ __ALIGN_BEGIN uint8_t USBD_CDC_CfgHSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END = 0x02, /* bmAttributes: Bulk */ LOBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), /* wMaxPacketSize: */ HIBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), - 0x00 /* bInterval: ignore for Bulk transfer */ -} ; + 0x00, /* bInterval: ignore for Bulk transfer */ + /////////////////////////////////////////////////////////////////////////////// + + /* Interface Association Descriptor: custom device */ + 0x08, /* bLength: IAD size */ + 0x0B, /* bDescriptorType: Interface Association Descriptor */ + 0x02, /* bFirstInterface */ + 0x01, /* bInterfaceCount */ + 0x00, /* bFunctionClass: Communication Interface Class */ + 0x00, /* bFunctionSubClass: Abstract Control Model */ + 0x00, /* bFunctionProtocol: Common AT commands */ + 0x06, /* iFunction */ -/* USB CDC device Configuration Descriptor */ -__ALIGN_BEGIN uint8_t USBD_CDC_CfgFSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END = -{ - /*Configuration Descriptor*/ - 0x09, /* bLength: Configuration Descriptor size */ - USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ - USB_CDC_CONFIG_DESC_SIZ, /* wTotalLength:no of returned bytes */ - 0x00, - 0x02, /* bNumInterfaces: 2 interface */ - 0x01, /* bConfigurationValue: Configuration value */ - 0x00, /* iConfiguration: Index of string descriptor describing the configuration */ - 0xC0, /* bmAttributes: self powered */ - 0x32, /* MaxPower 0 mA */ - - /*---------------------------------------------------------------------------*/ - - /*Interface Descriptor */ - 0x09, /* bLength: Interface Descriptor size */ - USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */ - /* Interface descriptor type */ - 0x00, /* bInterfaceNumber: Number of Interface */ - 0x00, /* bAlternateSetting: Alternate setting */ - 0x01, /* bNumEndpoints: One endpoints used */ - 0x02, /* bInterfaceClass: Communication Interface Class */ - 0x02, /* bInterfaceSubClass: Abstract Control Model */ - 0x01, /* bInterfaceProtocol: Common AT commands */ - 0x00, /* iInterface: */ - - /*Header Functional Descriptor*/ - 0x05, /* bLength: Endpoint Descriptor size */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x00, /* bDescriptorSubtype: Header Func Desc */ - 0x10, /* bcdCDC: spec release number */ - 0x01, - - /*Call Management Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x01, /* bDescriptorSubtype: Call Management Func Desc */ - 0x00, /* bmCapabilities: D0+D1 */ - 0x01, /* bDataInterface: 1 */ - - /*ACM Functional Descriptor*/ - 0x04, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ - 0x02, /* bmCapabilities */ - - /*Union Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x06, /* bDescriptorSubtype: Union func desc */ - 0x00, /* bMasterInterface: Communication class interface */ - 0x01, /* bSlaveInterface0: Data Class Interface */ - - /*Endpoint 2 Descriptor*/ - 0x07, /* bLength: Endpoint Descriptor size */ - USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ - CDC_CMD_EP, /* bEndpointAddress */ - 0x03, /* bmAttributes: Interrupt */ - LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */ - HIBYTE(CDC_CMD_PACKET_SIZE), - 0x10, /* bInterval: */ /*---------------------------------------------------------------------------*/ /*Data class interface descriptor*/ 0x09, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */ - 0x01, /* bInterfaceNumber: Number of Interface */ + 0x02, /* bInterfaceNumber: Number of Interface */ 0x00, /* bAlternateSetting: Alternate setting */ 0x02, /* bNumEndpoints: Two endpoints used */ - 0x0A, /* bInterfaceClass: CDC */ - 0x00, /* bInterfaceSubClass: */ + 0x00, /* bInterfaceClass: vendor specific */ + 0x01, /* bInterfaceSubClass: ODrive Communication */ 0x00, /* bInterfaceProtocol: */ 0x00, /* iInterface: */ /*Endpoint OUT Descriptor*/ 0x07, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ - CDC_OUT_EP, /* bEndpointAddress */ + ODRIVE_OUT_EP, /* bEndpointAddress */ 0x02, /* bmAttributes: Bulk */ - LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */ - HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), + LOBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), /* wMaxPacketSize: */ + HIBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), 0x00, /* bInterval: ignore for Bulk transfer */ /*Endpoint IN Descriptor*/ 0x07, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ - CDC_IN_EP, /* bEndpointAddress */ + ODRIVE_IN_EP, /* bEndpointAddress */ 0x02, /* bmAttributes: Bulk */ - LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */ - HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), - 0x00 /* bInterval: ignore for Bulk transfer */ + LOBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), /* wMaxPacketSize: */ + HIBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), + 0x00, /* bInterval: ignore for Bulk transfer */ } ; -__ALIGN_BEGIN uint8_t USBD_CDC_OtherSpeedCfgDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END = -{ - 0x09, /* bLength: Configuation Descriptor size */ - USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION, - USB_CDC_CONFIG_DESC_SIZ, - 0x00, - 0x02, /* bNumInterfaces: 2 interfaces */ - 0x01, /* bConfigurationValue: */ - 0x04, /* iConfiguration: */ - 0xC0, /* bmAttributes: */ - 0x32, /* MaxPower 100 mA */ - - /*Interface Descriptor */ - 0x09, /* bLength: Interface Descriptor size */ - USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */ - /* Interface descriptor type */ - 0x00, /* bInterfaceNumber: Number of Interface */ - 0x00, /* bAlternateSetting: Alternate setting */ - 0x01, /* bNumEndpoints: One endpoints used */ - 0x02, /* bInterfaceClass: Communication Interface Class */ - 0x02, /* bInterfaceSubClass: Abstract Control Model */ - 0x01, /* bInterfaceProtocol: Common AT commands */ - 0x00, /* iInterface: */ - - /*Header Functional Descriptor*/ - 0x05, /* bLength: Endpoint Descriptor size */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x00, /* bDescriptorSubtype: Header Func Desc */ - 0x10, /* bcdCDC: spec release number */ - 0x01, - - /*Call Management Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x01, /* bDescriptorSubtype: Call Management Func Desc */ - 0x00, /* bmCapabilities: D0+D1 */ - 0x01, /* bDataInterface: 1 */ - - /*ACM Functional Descriptor*/ - 0x04, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ - 0x02, /* bmCapabilities */ - - /*Union Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x06, /* bDescriptorSubtype: Union func desc */ - 0x00, /* bMasterInterface: Communication class interface */ - 0x01, /* bSlaveInterface0: Data Class Interface */ - - /*Endpoint 2 Descriptor*/ - 0x07, /* bLength: Endpoint Descriptor size */ - USB_DESC_TYPE_ENDPOINT , /* bDescriptorType: Endpoint */ - CDC_CMD_EP, /* bEndpointAddress */ - 0x03, /* bmAttributes: Interrupt */ - LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */ - HIBYTE(CDC_CMD_PACKET_SIZE), - 0xFF, /* bInterval: */ - - /*---------------------------------------------------------------------------*/ - - /*Data class interface descriptor*/ - 0x09, /* bLength: Endpoint Descriptor size */ - USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */ - 0x01, /* bInterfaceNumber: Number of Interface */ - 0x00, /* bAlternateSetting: Alternate setting */ - 0x02, /* bNumEndpoints: Two endpoints used */ - 0x0A, /* bInterfaceClass: CDC */ - 0x00, /* bInterfaceSubClass: */ - 0x00, /* bInterfaceProtocol: */ - 0x00, /* iInterface: */ - - /*Endpoint OUT Descriptor*/ - 0x07, /* bLength: Endpoint Descriptor size */ - USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ - CDC_OUT_EP, /* bEndpointAddress */ - 0x02, /* bmAttributes: Bulk */ - 0x40, /* wMaxPacketSize: */ - 0x00, - 0x00, /* bInterval: ignore for Bulk transfer */ - - /*Endpoint IN Descriptor*/ - 0x07, /* bLength: Endpoint Descriptor size */ - USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ - CDC_IN_EP, /* bEndpointAddress */ - 0x02, /* bmAttributes: Bulk */ - 0x40, /* wMaxPacketSize: */ - 0x00, - 0x00 /* bInterval */ -}; /** * @} @@ -508,6 +380,19 @@ static uint8_t USBD_CDC_Init (USBD_HandleTypeDef *pdev, USBD_EP_TYPE_BULK, CDC_DATA_FS_OUT_PACKET_SIZE); } + + /* Open ODrive IN endpoint */ + USBD_LL_OpenEP(pdev, + ODRIVE_IN_EP, + USBD_EP_TYPE_BULK, + pdev->dev_speed == USBD_SPEED_HIGH ? CDC_DATA_HS_IN_PACKET_SIZE : CDC_DATA_FS_IN_PACKET_SIZE); + + /* Open ODrive OUT endpoint */ + USBD_LL_OpenEP(pdev, + ODRIVE_OUT_EP, + USBD_EP_TYPE_BULK, + pdev->dev_speed == USBD_SPEED_HIGH ? CDC_DATA_HS_OUT_PACKET_SIZE : CDC_DATA_FS_OUT_PACKET_SIZE); + /* Open Command IN EP */ USBD_LL_OpenEP(pdev, CDC_CMD_EP, @@ -549,7 +434,11 @@ static uint8_t USBD_CDC_Init (USBD_HandleTypeDef *pdev, CDC_DATA_FS_OUT_PACKET_SIZE); } - + /* Prepare ODrive Out endpoint to receive next packet */ + USBD_LL_PrepareReceive(pdev, + ODRIVE_OUT_EP, + hcdc->RxBuffer, + CDC_DATA_FS_OUT_PACKET_SIZE); } return ret; } @@ -566,17 +455,25 @@ static uint8_t USBD_CDC_DeInit (USBD_HandleTypeDef *pdev, { uint8_t ret = 0; - /* Open EP IN */ + /* Close EP IN */ USBD_LL_CloseEP(pdev, CDC_IN_EP); - /* Open EP OUT */ + /* Close EP OUT */ USBD_LL_CloseEP(pdev, CDC_OUT_EP); - /* Open Command IN EP */ + /* Close Command IN EP */ USBD_LL_CloseEP(pdev, CDC_CMD_EP); + + /* Close EP IN */ + USBD_LL_CloseEP(pdev, + ODRIVE_IN_EP); + + /* Close EP OUT */ + USBD_LL_CloseEP(pdev, + ODRIVE_OUT_EP); /* DeInit physical Interface components */ @@ -648,6 +545,9 @@ static uint8_t USBD_CDC_Setup (USBD_HandleTypeDef *pdev, case USB_REQ_SET_INTERFACE : break; } + + case USB_REQ_TYPE_VENDOR: + return USBD_WinUSBComm_SetupVendor(pdev, req); default: break; @@ -697,7 +597,7 @@ static uint8_t USBD_CDC_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum) NAKed till the end of the application Xfer */ if(pdev->pClassData != NULL) { - ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Receive(hcdc->RxBuffer, &hcdc->RxLength); + ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Receive(hcdc->RxBuffer, &hcdc->RxLength, epnum); return USBD_OK; } @@ -740,8 +640,8 @@ static uint8_t USBD_CDC_EP0_RxReady (USBD_HandleTypeDef *pdev) */ static uint8_t *USBD_CDC_GetFSCfgDesc (uint16_t *length) { - *length = sizeof (USBD_CDC_CfgFSDesc); - return USBD_CDC_CfgFSDesc; + *length = sizeof (USBD_CDC_CfgDesc); + return USBD_CDC_CfgDesc; } /** @@ -753,8 +653,8 @@ static uint8_t *USBD_CDC_GetFSCfgDesc (uint16_t *length) */ static uint8_t *USBD_CDC_GetHSCfgDesc (uint16_t *length) { - *length = sizeof (USBD_CDC_CfgHSDesc); - return USBD_CDC_CfgHSDesc; + *length = sizeof (USBD_CDC_CfgDesc); + return USBD_CDC_CfgDesc; } /** @@ -766,8 +666,8 @@ static uint8_t *USBD_CDC_GetHSCfgDesc (uint16_t *length) */ static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc (uint16_t *length) { - *length = sizeof (USBD_CDC_OtherSpeedCfgDesc); - return USBD_CDC_OtherSpeedCfgDesc; + *length = sizeof (USBD_CDC_CfgDesc); + return USBD_CDC_CfgDesc; } /** @@ -844,7 +744,7 @@ uint8_t USBD_CDC_SetRxBuffer (USBD_HandleTypeDef *pdev, * @param epnum: endpoint number * @retval status */ -uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev) +uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev, uint8_t endpoint_pair) { USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData; @@ -855,11 +755,19 @@ uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev) /* Tx Transfer in progress */ hcdc->TxState = 1; - /* Transmit next packet */ - USBD_LL_Transmit(pdev, - CDC_IN_EP, - hcdc->TxBuffer, - hcdc->TxLength); + //endpoint_pair = 1; + if (endpoint_pair == 1) { + /* Transmit next packet */ + USBD_LL_Transmit(pdev, + CDC_IN_EP, + hcdc->TxBuffer, + hcdc->TxLength); + } else if (endpoint_pair == 3) { + USBD_LL_Transmit(pdev, + ODRIVE_IN_EP, + hcdc->TxBuffer, + hcdc->TxLength); + } return USBD_OK; } @@ -881,29 +789,30 @@ uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev) * @param pdev: device instance * @retval status */ -uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev) +uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev, uint8_t endpoint_pair) { USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData; /* Suspend or Resume USB Out process */ if(pdev->pClassData != NULL) { - if(pdev->dev_speed == USBD_SPEED_HIGH ) + if (endpoint_pair == CDC_OUT_EP) { /* Prepare Out endpoint to receive next packet */ USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, hcdc->RxBuffer, - CDC_DATA_HS_OUT_PACKET_SIZE); + pdev->dev_speed == USBD_SPEED_HIGH ? CDC_DATA_HS_OUT_PACKET_SIZE : CDC_DATA_FS_OUT_PACKET_SIZE); } - else + else if (endpoint_pair == ODRIVE_OUT_EP) { - /* Prepare Out endpoint to receive next packet */ + /* Prepare ODrive Out endpoint to receive next packet */ USBD_LL_PrepareReceive(pdev, - CDC_OUT_EP, + ODRIVE_OUT_EP, hcdc->RxBuffer, - CDC_DATA_FS_OUT_PACKET_SIZE); + pdev->dev_speed == USBD_SPEED_HIGH ? CDC_DATA_HS_OUT_PACKET_SIZE : CDC_DATA_FS_OUT_PACKET_SIZE); } + return USBD_OK; } else @@ -911,6 +820,184 @@ uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev) return USBD_FAIL; } } + + +/* WinUSB support ------------------------------------------------------------*/ +/* +* This section tells Windows that it should automatically load the WinUSB driver +* for the device (more specifically, interface 2 because it's a composite device). +* This allows for driverless communication with the device. +*/ + +#define NUM_INTERFACES 1 + +#if NUM_INTERFACES == 2 +#define USB_WINUSBCOMM_COMPAT_ID_OS_DESC_SIZ (16 + 24 + 24) +#else +#define USB_WINUSBCOMM_COMPAT_ID_OS_DESC_SIZ (16 + 24) +#endif + + +// This associates winusb driver with the device +__ALIGN_BEGIN uint8_t USBD_WinUSBComm_Extended_Compat_ID_OS_Desc[USB_WINUSBCOMM_COMPAT_ID_OS_DESC_SIZ] __ALIGN_END = +{ + // +-- Offset in descriptor + // | +-- Size + // v v + USB_WINUSBCOMM_COMPAT_ID_OS_DESC_SIZ, 0, 0, 0, // 0 dwLength 4 DWORD The length, in bytes, of the complete extended compat ID descriptor + 0x00, 0x01, // 4 bcdVersion 2 BCD The descriptor’s version number, in binary coded decimal (BCD) format + 0x04, 0x00, // 6 wIndex 2 WORD An index that identifies the particular OS feature descriptor + NUM_INTERFACES, // 8 bCount 1 BYTE The number of custom property sections + 0, 0, 0, 0, 0, 0, 0, // 9 RESERVED 7 BYTEs Reserved + // ===================== + // 16 + + // +-- Offset from function section start + // | +-- Size + // v v + 2, // 0 bFirstInterfaceNumber 1 BYTE The interface or function number + 0, // 1 RESERVED 1 BYTE Reserved + 0x57, 0x49, 0x4E, 0x55, 0x53, 0x42, 0x00, 0x00, // 2 compatibleID 8 BYTEs The function’s compatible ID ("WINUSB") + 0, 0, 0, 0, 0, 0, 0, 0, // 10 subCompatibleID 8 BYTEs The function’s subcompatible ID + 0, 0, 0, 0, 0, 0, // 18 RESERVED 6 BYTEs Reserved + // ================================= + // 24 +#if NUM_INTERFACES == 2 + // +-- Offset from function section start + // | +-- Size + // v v + 2, // 0 bFirstInterfaceNumber 1 BYTE The interface or function number + 0, // 1 RESERVED 1 BYTE Reserved + 0x57, 0x49, 0x4E, 0x55, 0x53, 0x42, 0x00, 0x00, // 2 compatibleID 8 BYTEs The function’s compatible ID ("WINUSB") + 0, 0, 0, 0, 0, 0, 0, 0, // 10 subCompatibleID 8 BYTEs The function’s subcompatible ID + 0, 0, 0, 0, 0, 0, // 18 RESERVED 6 BYTEs Reserved + // ================================= + // 24 +#endif +}; + + +// Properties are added to: +// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\VID_xxxx&PID_xxxx\sssssssss\Device Parameters +// Use USBDeview or similar to uninstall + +__ALIGN_BEGIN uint8_t USBD_WinUSBComm_Extended_Properties_OS_Desc[0xB6] __ALIGN_END = +{ + 0xB6, 0x00, 0x00, 0x00, // 0 dwLength 4 DWORD The length, in bytes, of the complete extended properties descriptor + 0x00, 0x01, // 4 bcdVersion 2 BCD The descriptor’s version number, in binary coded decimal (BCD) format + 0x05, 0x00, // 6 wIndex 2 WORD The index for extended properties OS descriptors + 0x02, 0x00, // 8 wCount 2 WORD The number of custom property sections that follow the header section + // ==================== + // 10 +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + 0x84, 0x00, 0x00, 0x00, // 0 dwSize 4 DWORD The size of this custom properties section + 0x01, 0x00, 0x00, 0x00, // 4 dwPropertyDataType 4 DWORD Property data format + 0x28, 0x00, // 8 wPropertyNameLength 2 DWORD Property name length + // ======================================== + // 10 + // 10 bPropertyName PNL WCHAR[] The property name + 'D',0, 'e',0, 'v',0, 'i',0, 'c',0, 'e',0, 'I',0, 'n',0, + 't',0, 'e',0, 'r',0, 'f',0, 'a',0, 'c',0, 'e',0, 'G',0, + 'U',0, 'I',0, 'D',0, 0,0, + // ======================================== + // 40 (0x28) + + 0x4E, 0x00, 0x00, 0x00, // 10 + PNL dwPropertyDataLength 4 DWORD Length of the buffer holding the property data + // ======================================== + // 4 + // 14 + PNL bPropertyData PDL Format-dependent Property data + '{',0, 'E',0, 'A',0, '0',0, 'B',0, 'D',0, '5',0, 'C',0, + '3',0, '-',0, '5',0, '0',0, 'F',0, '3',0, '-',0, '4',0, + '8',0, '8',0, '8',0, '-',0, '8',0, '4',0, 'B',0, '4',0, + '-',0, '7',0, '4',0, 'E',0, '5',0, '0',0, 'E',0, '1',0, + '6',0, '4',0, '9',0, 'D',0, 'B',0, '}',0, 0 ,0, + // ======================================== + // 78 (0x4E) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + 0x3E, 0x00, 0x00, 0x00, // 0 dwSize 0x00000030 (62 bytes) + 0x01, 0x00, 0x00, 0x00, // 4 dwPropertyDataType 0x00000001 (Unicode string) + 0x0C, 0x00, // 8 wPropertyNameLength 0x000C (12 bytes) + // ======================================== + // 10 + 'L',0, 'a',0, 'b',0, 'e',0, 'l',0, 0,0, + // 10 bPropertyName “Label” + // ======================================== + // 12 + 0x24, 0x00, 0x00, 0x00, // 22 dwPropertyDataLength 0x00000016 (36 bytes) + // ======================================== + // 4 + 'O',0, 'D',0, 'r',0, 'i',0, 'v',0, 'e',0, 0,0 + // 26 bPropertyData “ODrive” + // ======================================== + // 14 + +}; + + + +static uint8_t USBD_WinUSBComm_GetMSExtendedCompatIDOSDescriptor (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) +{ + switch (req->wIndex) + { + case 0x04: + USBD_CtlSendData (pdev, USBD_WinUSBComm_Extended_Compat_ID_OS_Desc, req->wLength); + break; + default: + USBD_CtlError(pdev , req); + return USBD_FAIL; + } + return USBD_OK; +} +static uint8_t USBD_WinUSBComm_GetMSExtendedPropertiesOSDescriptor (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) +{ + uint8_t byInterfaceIndex = (uint8_t)req->wValue; + if ( req->wIndex != 0x05 ) + { + USBD_CtlError(pdev , req); + return USBD_FAIL; + } + switch ( byInterfaceIndex ) + { + case 0: +#if NUM_INTERFACES == 2 + case 1: +#endif + USBD_CtlSendData (pdev, USBD_WinUSBComm_Extended_Properties_OS_Desc, req->wLength); + break; + default: + USBD_CtlError(pdev , req); + return USBD_FAIL; + } + return USBD_OK; +} +static uint8_t USBD_WinUSBComm_SetupVendorDevice(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) +{ + USBD_CtlError(pdev , req); + return USBD_FAIL; +} +static uint8_t USBD_WinUSBComm_SetupVendorInterface(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) +{ + USBD_CtlError(pdev , req); + // TODO: check if this is important + return USBD_FAIL; +} +static uint8_t USBD_WinUSBComm_SetupVendor(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) +{ + switch ( req->bmRequest & USB_REQ_RECIPIENT_MASK ) + { + case USB_REQ_RECIPIENT_DEVICE: + return ( MS_VendorCode == req->bRequest ) ? USBD_WinUSBComm_GetMSExtendedCompatIDOSDescriptor(pdev, req) : USBD_WinUSBComm_SetupVendorDevice(pdev, req); + case USB_REQ_RECIPIENT_INTERFACE: + return ( MS_VendorCode == req->bRequest ) ? USBD_WinUSBComm_GetMSExtendedPropertiesOSDescriptor(pdev, req) : USBD_WinUSBComm_SetupVendorInterface(pdev, req); + case USB_REQ_RECIPIENT_ENDPOINT: + // fall through + default: + break; + } + USBD_CtlError(pdev , req); + return USBD_FAIL; +} + /** * @} */ diff --git a/Firmware/Board/v3/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h b/Firmware/Board/v3/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h index 8fbe81e4..f259b51d 100644 --- a/Firmware/Board/v3/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h +++ b/Firmware/Board/v3/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h @@ -68,7 +68,9 @@ #define USBD_IDX_PRODUCT_STR 0x02 #define USBD_IDX_SERIAL_STR 0x03 #define USBD_IDX_CONFIG_STR 0x04 -#define USBD_IDX_INTERFACE_STR 0x05 +#define USBD_IDX_INTERFACE_STR 0x05 +#define USBD_IDX_ODRIVE_INTF_STR 0x06 +#define USBD_IDX_MICROSOFT_DESC_STR 0xEE #define USB_REQ_TYPE_STANDARD 0x00 #define USB_REQ_TYPE_CLASS 0x20 diff --git a/Firmware/Board/v3/Odrive.ioc b/Firmware/Board/v3/Odrive.ioc index 314833f0..84db04ed 100644 --- a/Firmware/Board/v3/Odrive.ioc +++ b/Firmware/Board/v3/Odrive.ioc @@ -115,10 +115,11 @@ Dma.UART4_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataA FREERTOS.FootprintOK=true FREERTOS.INCLUDE_uxTaskGetStackHighWaterMark=1 FREERTOS.INCLUDE_vTaskDelayUntil=1 -FREERTOS.IPParameters=Tasks01,INCLUDE_vTaskDelayUntil,configTOTAL_HEAP_SIZE,FootprintOK,configCHECK_FOR_STACK_OVERFLOW,INCLUDE_uxTaskGetStackHighWaterMark +FREERTOS.IPParameters=Tasks01,INCLUDE_vTaskDelayUntil,configTOTAL_HEAP_SIZE,FootprintOK,configCHECK_FOR_STACK_OVERFLOW,INCLUDE_uxTaskGetStackHighWaterMark,configUSE_IDLE_HOOK FREERTOS.Tasks01=defaultTask,0,256,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL FREERTOS.configCHECK_FOR_STACK_OVERFLOW=1 FREERTOS.configTOTAL_HEAP_SIZE=65536 +FREERTOS.configUSE_IDLE_HOOK=1 File.Version=6 KeepUserPlacement=true Mcu.Family=STM32F4 @@ -219,7 +220,9 @@ NVIC.PendSV_IRQn=true\:15\:0\:false\:false\:false\:true\:true NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:false\:false\:true NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:true\:true +NVIC.TIM1_UP_TIM10_IRQn=true\:0\:0\:false\:false\:false\:false\:true NVIC.TIM8_TRG_COM_TIM14_IRQn=true\:0\:0\:false\:false\:true\:false\:false +NVIC.TIM8_UP_TIM13_IRQn=true\:0\:0\:false\:false\:false\:false\:true NVIC.TimeBase=TIM8_TRG_COM_TIM14_IRQn NVIC.TimeBaseIP=TIM14 NVIC.UART4_IRQn=true\:5\:0\:false\:false\:true\:true\:true @@ -343,10 +346,12 @@ PB6.Signal=S_TIM4_CH1 PB7.GPIOParameters=GPIO_Label PB7.GPIO_Label=M1_ENC_B PB7.Signal=S_TIM4_CH2 -PB8.Mode=Master -PB8.Signal=CAN1_RX -PB9.Mode=Master -PB9.Signal=CAN1_TX +PB8.Locked=true +PB8.Signal=SharedStack_PB8 +PB8.Stacked=true +PB9.Locked=true +PB9.Signal=SharedStack_PB9 +PB9.Stacked=true PC0.GPIOParameters=GPIO_Label PC0.GPIO_Label=M0_IB PC0.Signal=ADCx_IN10 @@ -444,7 +449,7 @@ ProjectManager.StackSize=0x800 ProjectManager.TargetToolchain=Makefile ProjectManager.ToolChainLocation= ProjectManager.UnderRoot=false -ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-MX_DMA_Init-DMA-false-HAL-true,3-MX_ADC1_Init-ADC1-false-HAL-true,4-MX_ADC2_Init-ADC2-false-HAL-true,5-MX_CAN1_Init-CAN1-false-HAL-true,6-MX_TIM1_Init-TIM1-false-HAL-true,7-MX_TIM8_Init-TIM8-false-HAL-true,8-MX_TIM3_Init-TIM3-false-HAL-true,9-MX_TIM4_Init-TIM4-false-HAL-true,10-MX_SPI3_Init-SPI3-false-HAL-true,11-MX_ADC3_Init-ADC3-false-HAL-true,12-SystemClock_Config-RCC-false-HAL-true,13-MX_TIM2_Init-TIM2-false-HAL-true,14-MX_USB_DEVICE_Init-USB_DEVICE-false-HAL-true,15-MX_UART4_Init-UART4-false-HAL-true +ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-MX_DMA_Init-DMA-false-HAL-true,3-MX_ADC1_Init-ADC1-false-HAL-true,4-MX_ADC2_Init-ADC2-false-HAL-true,5-MX_TIM1_Init-TIM1-false-HAL-true,6-MX_TIM8_Init-TIM8-false-HAL-true,7-MX_TIM3_Init-TIM3-false-HAL-true,8-MX_TIM4_Init-TIM4-false-HAL-true,9-MX_SPI3_Init-SPI3-false-HAL-true,10-MX_ADC3_Init-ADC3-false-HAL-true,11-SystemClock_Config-RCC-false-HAL-true,12-MX_TIM2_Init-TIM2-false-HAL-true,13-MX_USB_DEVICE_Init-USB_DEVICE-false-HAL-true,14-MX_UART4_Init-UART4-false-HAL-true,15-MX_CAN1_Init-CAN1-false-HAL-true RCC.48MHZClocksFreq_Value=48000000 RCC.AHBFreq_Value=168000000 RCC.APB1CLKDivider=RCC_HCLK_DIV4 @@ -537,6 +542,12 @@ SH.SharedStack_PA0.ConfNb=2 SH.SharedStack_PA1.0=GPIO_Input+0 SH.SharedStack_PA1.1=UART4_RX,Asynchronous SH.SharedStack_PA1.ConfNb=2 +SH.SharedStack_PB8.0=CAN1_RX,Master +SH.SharedStack_PB8.1=I2C1_SCL +SH.SharedStack_PB8.ConfNb=2 +SH.SharedStack_PB9.0=CAN1_TX,Master +SH.SharedStack_PB9.1=I2C1_SDA +SH.SharedStack_PB9.ConfNb=2 SPI3.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16 SPI3.CLKPhase=SPI_PHASE_2EDGE SPI3.CalculateBaudRate=2.625 MBits/s diff --git a/Firmware/Board/v3/Src/freertos.c b/Firmware/Board/v3/Src/freertos.c index f1d46642..524cd6cb 100644 --- a/Firmware/Board/v3/Src/freertos.c +++ b/Firmware/Board/v3/Src/freertos.c @@ -86,8 +86,24 @@ void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */ /* USER CODE END FunctionPrototypes */ /* Hook prototypes */ +void vApplicationIdleHook(void); void vApplicationStackOverflowHook(xTaskHandle xTask, signed char *pcTaskName); +/* USER CODE BEGIN 2 */ +__weak void vApplicationIdleHook( void ) +{ + /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set + to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle + task. It is essential that code added to this hook function never attempts + to block in any way (for example, call xQueueReceive() with a block time + specified, or call vTaskDelay()). If the application makes use of the + vTaskDelete() API function (as this demo application does) then it is also + important that vApplicationIdleHook() is permitted to return to its calling + function, because it is the responsibility of the idle task to clean up + memory allocated by the kernel to any task that has since been deleted. */ +} +/* USER CODE END 2 */ + /* USER CODE BEGIN 4 */ __weak void vApplicationStackOverflowHook(xTaskHandle xTask, signed char *pcTaskName) { diff --git a/Firmware/Board/v3/Src/i2c.c b/Firmware/Board/v3/Src/i2c.c new file mode 100644 index 00000000..bae77f12 --- /dev/null +++ b/Firmware/Board/v3/Src/i2c.c @@ -0,0 +1,198 @@ +/** + ****************************************************************************** + * File Name : I2C.c + * Description : This file provides code for the configuration + * of the I2C instances. + ****************************************************************************** + * This notice applies to any and all portions of this file + * that are not between comment pairs USER CODE BEGIN and + * USER CODE END. Other portions of this file, whether + * inserted by the user or by software development tools + * are owned by their respective copyright owners. + * + * Copyright (c) 2018 STMicroelectronics International N.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted, provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of STMicroelectronics nor the names of other + * contributors to this software may be used to endorse or promote products + * derived from this software without specific written permission. + * 4. This software, including modifications and/or derivative works of this + * software, must execute solely and exclusively on microcontroller or + * microprocessor devices manufactured by or for STMicroelectronics. + * 5. Redistribution and use of this software other than as permitted under + * this license is void and will automatically terminate your rights under + * this license. + * + * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY + * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT + * SHALL STMICROELECTRONICS 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "i2c.h" + +#include "gpio.h" +#include "dma.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +I2C_HandleTypeDef hi2c1; +DMA_HandleTypeDef hdma_i2c1_rx; +DMA_HandleTypeDef hdma_i2c1_tx; + +/* I2C1 init function */ +void MX_I2C1_Init(uint8_t addr) +{ + + hi2c1.Instance = I2C1; + hi2c1.Init.ClockSpeed = 100000; + hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; + hi2c1.Init.OwnAddress1 = addr << 1; + hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + hi2c1.Init.OwnAddress2 = 0; + hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; + hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + if (HAL_I2C_Init(&hi2c1) != HAL_OK) + { + _Error_Handler(__FILE__, __LINE__); + } + +} + +void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle) +{ + + GPIO_InitTypeDef GPIO_InitStruct; + if(i2cHandle->Instance==I2C1) + { + /* USER CODE BEGIN I2C1_MspInit 0 */ + + /* USER CODE END I2C1_MspInit 0 */ + + /**I2C1 GPIO Configuration + PB8 ------> I2C1_SCL + PB9 ------> I2C1_SDA + */ + GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9; + GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /* I2C1 clock enable */ + __HAL_RCC_I2C1_CLK_ENABLE(); + + /* I2C1 DMA Init */ + /* I2C1_RX Init */ + hdma_i2c1_rx.Instance = DMA1_Stream0; + hdma_i2c1_rx.Init.Channel = DMA_CHANNEL_1; + hdma_i2c1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_i2c1_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_i2c1_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_i2c1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_i2c1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_i2c1_rx.Init.Mode = DMA_CIRCULAR; + hdma_i2c1_rx.Init.Priority = DMA_PRIORITY_LOW; + hdma_i2c1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + if (HAL_DMA_Init(&hdma_i2c1_rx) != HAL_OK) + { + _Error_Handler(__FILE__, __LINE__); + } + + __HAL_LINKDMA(i2cHandle,hdmarx,hdma_i2c1_rx); + + /* I2C1_TX Init */ + hdma_i2c1_tx.Instance = DMA1_Stream6; + hdma_i2c1_tx.Init.Channel = DMA_CHANNEL_1; + hdma_i2c1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_i2c1_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_i2c1_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_i2c1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_i2c1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_i2c1_tx.Init.Mode = DMA_NORMAL; + hdma_i2c1_tx.Init.Priority = DMA_PRIORITY_LOW; + hdma_i2c1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + if (HAL_DMA_Init(&hdma_i2c1_tx) != HAL_OK) + { + _Error_Handler(__FILE__, __LINE__); + } + + __HAL_LINKDMA(i2cHandle,hdmatx,hdma_i2c1_tx); + + /* I2C1 interrupt Init */ + HAL_NVIC_SetPriority(I2C1_EV_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(I2C1_EV_IRQn); + HAL_NVIC_SetPriority(I2C1_ER_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(I2C1_ER_IRQn); + /* USER CODE BEGIN I2C1_MspInit 1 */ + + /* USER CODE END I2C1_MspInit 1 */ + } +} + +void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle) +{ + + if(i2cHandle->Instance==I2C1) + { + /* USER CODE BEGIN I2C1_MspDeInit 0 */ + + /* USER CODE END I2C1_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_I2C1_CLK_DISABLE(); + + /**I2C1 GPIO Configuration + PB8 ------> I2C1_SCL + PB9 ------> I2C1_SDA + */ + HAL_GPIO_DeInit(GPIOB, GPIO_PIN_8|GPIO_PIN_9); + + /* I2C1 DMA DeInit */ + HAL_DMA_DeInit(i2cHandle->hdmarx); + HAL_DMA_DeInit(i2cHandle->hdmatx); + + /* I2C1 interrupt Deinit */ + HAL_NVIC_DisableIRQ(I2C1_EV_IRQn); + HAL_NVIC_DisableIRQ(I2C1_ER_IRQn); + /* USER CODE BEGIN I2C1_MspDeInit 1 */ + + /* USER CODE END I2C1_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Firmware/Board/v3/Src/main.c b/Firmware/Board/v3/Src/main.c index 98b64d31..efaeef10 100644 --- a/Firmware/Board/v3/Src/main.c +++ b/Firmware/Board/v3/Src/main.c @@ -61,6 +61,7 @@ /* USER CODE BEGIN Includes */ #include #include "freertos_vars.h" +#include "i2c.h" /* USER CODE END Includes */ /* Private variables ---------------------------------------------------------*/ diff --git a/Firmware/Board/v3/Src/stm32f4xx_it.c b/Firmware/Board/v3/Src/stm32f4xx_it.c index 1a650abc..1ef20c8c 100644 --- a/Firmware/Board/v3/Src/stm32f4xx_it.c +++ b/Firmware/Board/v3/Src/stm32f4xx_it.c @@ -46,6 +46,10 @@ void ADC_IRQ_Dispatch(ADC_HandleTypeDef* hadc, ADC_handler_t callback); // TODO: move somewhere else void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected); void vbus_sense_adc_cb(ADC_HandleTypeDef* hadc, bool injected); +void tim_update_cb(TIM_HandleTypeDef* htim); + +extern TIM_HandleTypeDef htim1; +extern I2C_HandleTypeDef hi2c1; /* USER CODE END 0 */ @@ -308,6 +312,40 @@ void ADC_IRQ_Dispatch(ADC_HandleTypeDef* hadc, ADC_handler_t callback) { } } +/** +* @brief This function handles TIM1 update interrupt and TIM10 global interrupt. +*/ +void TIM1_UP_TIM10_IRQHandler(void) +{ + __HAL_TIM_CLEAR_IT(&htim1, TIM_IT_UPDATE); + tim_update_cb(&htim1); +} + +/** +* @brief This function handles TIM8 update interrupt and TIM13 global interrupt. +*/ +void TIM8_UP_TIM13_IRQHandler(void) +{ + __HAL_TIM_CLEAR_IT(&htim8, TIM_IT_UPDATE); + tim_update_cb(&htim8); +} + + +/** +* @brief This function handles I2C1 event interrupt. +*/ +void I2C1_EV_IRQHandler(void) +{ + HAL_I2C_EV_IRQHandler(&hi2c1); +} + +/** +* @brief This function handles I2C1 error interrupt. +*/ +void I2C1_ER_IRQHandler(void) +{ + HAL_I2C_ER_IRQHandler(&hi2c1); +} /** * @brief This function handles EXTI line0 interrupt. @@ -368,7 +406,5 @@ void EXTI15_10_IRQHandler(void) HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_15); } - - /* USER CODE END 1 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Firmware/Board/v3/Src/tim.c b/Firmware/Board/v3/Src/tim.c index 5a63b6df..f1cb0c07 100644 --- a/Firmware/Board/v3/Src/tim.c +++ b/Firmware/Board/v3/Src/tim.c @@ -346,6 +346,10 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) /* USER CODE END TIM1_MspInit 0 */ /* TIM1 clock enable */ __HAL_RCC_TIM1_CLK_ENABLE(); + + /* TIM1 interrupt Init */ + HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn); /* USER CODE BEGIN TIM1_MspInit 1 */ /* USER CODE END TIM1_MspInit 1 */ @@ -375,6 +379,8 @@ void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* tim_pwmHandle) __HAL_RCC_TIM8_CLK_ENABLE(); /* TIM8 interrupt Init */ + HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn); HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn); /* USER CODE BEGIN TIM8_MspInit 1 */ @@ -542,6 +548,9 @@ void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle) /* USER CODE END TIM1_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_TIM1_CLK_DISABLE(); + + /* TIM1 interrupt Deinit */ + HAL_NVIC_DisableIRQ(TIM1_UP_TIM10_IRQn); /* USER CODE BEGIN TIM1_MspDeInit 1 */ /* USER CODE END TIM1_MspDeInit 1 */ @@ -571,6 +580,7 @@ void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef* tim_pwmHandle) __HAL_RCC_TIM8_CLK_DISABLE(); /* TIM8 interrupt Deinit */ + HAL_NVIC_DisableIRQ(TIM8_UP_TIM13_IRQn); HAL_NVIC_DisableIRQ(TIM8_TRG_COM_TIM14_IRQn); /* USER CODE BEGIN TIM8_MspDeInit 1 */ diff --git a/Firmware/Board/v3/Src/usbd_cdc_if.c b/Firmware/Board/v3/Src/usbd_cdc_if.c index 1a9c43c4..77e70b2c 100644 --- a/Firmware/Board/v3/Src/usbd_cdc_if.c +++ b/Firmware/Board/v3/Src/usbd_cdc_if.c @@ -151,7 +151,7 @@ extern USBD_HandleTypeDef hUsbDeviceFS; static int8_t CDC_Init_FS(void); static int8_t CDC_DeInit_FS(void); static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length); -static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len); +static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len, uint8_t endpoint_pair); /* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */ /* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */ @@ -287,10 +287,10 @@ static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length) * @param Len: Number of data received (in bytes) * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL */ -static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) +static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len, uint8_t endpoint_pair) { /* USER CODE BEGIN 6 */ - usb_process_packet(Buf, *Len); + usb_process_packet(Buf, *Len, endpoint_pair); return (USBD_OK); /* USER CODE END 6 */ @@ -307,7 +307,7 @@ static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) * @param Len: Number of data to be sent (in bytes) * @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY */ -uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) +uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len, uint8_t endpoint_pair) { uint8_t result = USBD_OK; /* USER CODE BEGIN 7 */ @@ -323,7 +323,7 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) memcpy(UserTxBufferFS, Buf, Len); // Update Len USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, Len); - result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); + result = USBD_CDC_TransmitPacket(&hUsbDeviceFS, endpoint_pair); /* USER CODE END 7 */ return result; } diff --git a/Firmware/Board/v3/Src/usbd_conf.c b/Firmware/Board/v3/Src/usbd_conf.c index f3eb88a9..2d66d4a1 100644 --- a/Firmware/Board/v3/Src/usbd_conf.c +++ b/Firmware/Board/v3/Src/usbd_conf.c @@ -154,6 +154,23 @@ void HAL_PCD_MspDeInit(PCD_HandleTypeDef* pcdHandle) */ void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) { + USBD_StatusTypeDef ret = USBD_OK; + USBD_HandleTypeDef *pdev = hpcd->pData; + USBD_SetupReqTypedef *req = &pdev->request; + USBD_ParseSetupRequest(req, (uint8_t *)hpcd->Setup); + if ( ( USB_REQ_TYPE_VENDOR == (req->bmRequest & USB_REQ_TYPE_MASK) ) && ( MS_VendorCode == req->bRequest ) ) + { + pdev->ep0_state = USBD_EP0_SETUP; + pdev->ep0_data_len = pdev->request.wLength; + + ret = pdev->pClass->Setup(pdev, req); + + if( (req->wLength == 0) && (ret == USBD_OK) ) + { + USBD_CtlSendStatus(pdev); + } + return; + } USBD_LL_SetupStage((USBD_HandleTypeDef*)hpcd->pData, (uint8_t *)hpcd->Setup); } @@ -312,7 +329,7 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev) pdev->pData = &hpcd_USB_OTG_FS; hpcd_USB_OTG_FS.Instance = USB_OTG_FS; - hpcd_USB_OTG_FS.Init.dev_endpoints = 4; + hpcd_USB_OTG_FS.Init.dev_endpoints = 6; hpcd_USB_OTG_FS.Init.speed = PCD_SPEED_FULL; hpcd_USB_OTG_FS.Init.dma_enable = DISABLE; hpcd_USB_OTG_FS.Init.ep0_mps = DEP0CTL_MPS_64; @@ -329,7 +346,8 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev) HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_FS, 0x80); HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 0, 0x40); - HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 1, 0x80); + HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 1, 0x40); // CDC IN endpoint + HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 3, 0x40); // ODrive IN endpoint } return USBD_OK; } diff --git a/Firmware/Board/v3/Src/usbd_desc.c b/Firmware/Board/v3/Src/usbd_desc.c index 856d05e2..d213f64a 100644 --- a/Firmware/Board/v3/Src/usbd_desc.c +++ b/Firmware/Board/v3/Src/usbd_desc.c @@ -97,7 +97,8 @@ #define USBD_PID_FS 0x0D32 #define USBD_PRODUCT_XSTR(s) USBD_PRODUCT_STR(s) #define USBD_PRODUCT_STR(s) #s -#define USBD_PRODUCT_STRING_FS ODrive version HW_VERSION_MAJOR.HW_VERSION_MINOR +#define USBD_PRODUCT_STRING_FS ODrive HW_VERSION_MAJOR.HW_VERSION_MINOR CDC Interface +#define NATIVE_STRING ODrive HW_VERSION_MAJOR.HW_VERSION_MINOR Native Interface #define USBD_SERIALNUMBER_STRING_FS "000000000001" #define USBD_CONFIGURATION_STRING_FS "CDC Config" #define USBD_INTERFACE_STRING_FS "CDC Interface" @@ -114,6 +115,50 @@ /* USER CODE BEGIN 0 */ +// MS OS String descriptor to tell Windows that it may query for other descriptors +// It's a standard string descriptor. +// Windows will only query for OS descriptors once! +// Delete the information about already queried devices in registry by deleting: +// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\usbflags\VVVVPPPPRRRR +__ALIGN_BEGIN uint8_t USBD_MS_OS_StringDescriptor[] __ALIGN_END = +{ + 0x12, // bLength 1 0x12 Length of the descriptor + 0x03, // bDescriptorType 1 0x03 Descriptor type + // qwSignature 14 ‘MSFT100’ Signature field + 0x4D, 0x00, // 'M' + 0x53, 0x00, // 'S' + 0x46, 0x00, // 'F' + 0x54, 0x00, // 'T' + 0x31, 0x00, // '1' + 0x30, 0x00, // '0' + 0x30, 0x00, // '0' + MS_VendorCode, // bMS_VendorCode 1 Vendor-specific Vendor code + 0x00 // bPad 1 0x00 Pad field +}; + +// redefined further down +__ALIGN_BEGIN uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END; +/** +* @brief UsrStrDescriptor +* return non standard string descriptor +* @param pdev: device instance +* @param index : descriptor index (0xEE for MS OS String Descriptor) +* @param length : pointer data length +* @retval pointer to descriptor buffer +*/ +uint8_t * USBD_UsrStrDescriptor(struct _USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length) +{ + *length = 0; + if (USBD_IDX_MICROSOFT_DESC_STR == index) { + *length = sizeof (USBD_MS_OS_StringDescriptor); + return USBD_MS_OS_StringDescriptor; + } else if (USBD_IDX_ODRIVE_INTF_STR == index) { + USBD_GetString((uint8_t *)USBD_PRODUCT_XSTR(NATIVE_STRING), USBD_StrDesc, length); + return USBD_StrDesc; + } + return NULL; +} + /* USER CODE END 0 */ /** @defgroup USBD_DESC_Private_Macros USBD_DESC_Private_Macros @@ -189,16 +234,17 @@ __ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = 0x00, /*bcdUSB */ #endif /* (USBD_LPM_ENABLED == 1) */ 0x02, - 0x02, /*bDeviceClass*/ + // Notify OS that this is a composite device + 0xEF, /*bDeviceClass*/ 0x02, /*bDeviceSubClass*/ - 0x00, /*bDeviceProtocol*/ + 0x01, /*bDeviceProtocol*/ USB_MAX_EP0_SIZE, /*bMaxPacketSize*/ LOBYTE(USBD_VID), /*idVendor*/ HIBYTE(USBD_VID), /*idVendor*/ LOBYTE(USBD_PID_FS), /*idProduct*/ HIBYTE(USBD_PID_FS), /*idProduct*/ 0x00, /*bcdDevice rel. 2.00*/ - 0x02, + 0x03, /* bNumInterfaces */ USBD_IDX_MFC_STR, /*Index of manufacturer string*/ USBD_IDX_PRODUCT_STR, /*Index of product string*/ USBD_IDX_SERIAL_STR, /*Index of serial number string*/ diff --git a/Firmware/CHANGELOG.md b/Firmware/CHANGELOG.md index 44075136..8ad796ce 100644 --- a/Firmware/CHANGELOG.md +++ b/Firmware/CHANGELOG.md @@ -11,7 +11,10 @@ Please add a note of your changes below this heading if you make a Pull Request. * System stats (e.g. stack usage) are exposed under `.system_stats` ### Changed -* The DFU script now verifies the flash after writing +* DFU script updates + * Verify the flash after writing + * Automatically download firmware from GitHub releases if no file is provided + * Retain configuration during firmware updates * Refactor python tools * The scripts `explore_odrive.py`, `liveplotter.py`, `drv_status.py` and `rate_test.py` have been merged into one single `odrivetool` script. Running this script without any arguments provides the shell that `explore_odrive.py` used to provide. * The command line options of `odrivetool` have changed compared to the original `explore_odrive.py`. See `odrivetool --help` for more details. @@ -19,11 +22,15 @@ Please add a note of your changes below this heading if you make a Pull Request. * No need to restart the `odrivetool` shell when devices get disconnected and reconnected * ODrive accesses from within python tools are now thread-safe. That means you can read from the same remote property from multiple threads concurrently. * The liveplotter (`odrivetool liveplotter`, formerly `liveplotter.py`) does no longer steal focus and closes as expected + * Add commands `odrivetool backup-config` and `odrivetool restore-config` * (experimental: start liveplotter from `odrivetool` shell by typing `start_liveplotter(lambda: odrv0.motor0.encoder.encoder_state)`) * `make write_otp` command to burn the board version onto the ODrive's one-time programmable memory. If you have an ODrive v3.4 or older, you can run this once for a better firmware update user experience in the future. Run the command without any options for more details. Once set, the board version is exposed through the `hw_version_[...]` properties. * bake Git-derived firmware version into firmware binary. The firmware version is exposed through the `fw_version_[...]` properties. * Set thread priority of USB pump thread above protocol thread * GPIO3 not sensitive to edges by default +* The device now appears as a composite device on USB. One subdevice is still a CDC device (virtual COM port), the other subdevice is a vendor specific class. This should resolve several issues that were caused by conflicting kernel drivers or OS services. +* Add WinUSB descriptors. This will tell Windows >= 8 to automatically load winusb.sys for the ODrive (only for the vendor specific subdevice). This makes it possible to use the ODrive from userspace via WinUSB with zero configuration. The Python tool currently still uses libusb so Zadig is still required. +* Add a configuration to enable the ASCII protocol on USB at runtime. This will only enable the ASCII protocol on the USB CDC subdevice, not the vendor specific subdevice so the python tools will still be able to talk to the ODrive. ### Fixed * Enums now transported with correct underlying type on native protocol diff --git a/Firmware/MotorControl/axis.cpp b/Firmware/MotorControl/axis.cpp index 7ddce582..3efd8f8d 100644 --- a/Firmware/MotorControl/axis.cpp +++ b/Firmware/MotorControl/axis.cpp @@ -38,6 +38,7 @@ void Axis::setup() { static void run_state_machine_loop_wrapper(void* ctx) { reinterpret_cast(ctx)->run_state_machine_loop(); + reinterpret_cast(ctx)->thread_id_valid_ = false; } // @brief Starts run_state_machine_loop in a new thread @@ -92,16 +93,34 @@ void Axis::set_step_dir_enabled(bool enable) { } } -// @brief Returns true if everything is ok. -// Sets error and returns false otherwise. +// @brief Do axis level checks and call subcomponent do_checks +// Returns true if everything is ok. bool Axis::do_checks() { - if (!motor_.do_checks()) - return error_ |= ERROR_MOTOR_FAILED, false; + if (!brake_resistor_armed) + error_ |= ERROR_BRAKE_RESISTOR_DISARMED; + if ((current_state_ != AXIS_STATE_IDLE) && (motor_.armed_state_ == Motor::ARMED_STATE_DISARMED)) + // motor got disarmed in something other than the idle loop + error_ |= ERROR_MOTOR_DISARMED; if (!(vbus_voltage >= board_config.dc_bus_undervoltage_trip_level)) - return error_ |= ERROR_DC_BUS_UNDER_VOLTAGE, false; + error_ |= ERROR_DC_BUS_UNDER_VOLTAGE; if (!(vbus_voltage <= board_config.dc_bus_overvoltage_trip_level)) - return error_ |= ERROR_DC_BUS_OVER_VOLTAGE, false; - return true; + error_ |= ERROR_DC_BUS_OVER_VOLTAGE; + + // Sub-components should use set_error which will propegate to this error_ + motor_.do_checks(); + encoder_.do_checks(); + // sensorless_estimator_.do_checks(); + // controller_.do_checks(); + + return error_ == ERROR_NONE; +} + +// @brief Update all esitmators +bool Axis::do_updates() { + // Sub-components should use set_error which will propegate to this error_ + encoder_.update(); + sensorless_estimator_.update(); + return error_ == ERROR_NONE; } bool Axis::run_sensorless_spin_up() { @@ -115,7 +134,7 @@ bool Axis::run_sensorless_spin_up() { return error_ |= ERROR_MOTOR_FAILED, false; return x < 1.0f; }); - if (error_ != ERROR_NO_ERROR) + if (error_ != ERROR_NONE) return false; // Late Spin-up: accelerate @@ -129,49 +148,41 @@ bool Axis::run_sensorless_spin_up() { return error_ |= ERROR_MOTOR_FAILED, false; return vel < config_.spin_up_target_vel; }); - return error_ == ERROR_NO_ERROR; + return error_ == ERROR_NONE; } // Note run_sensorless_control_loop and run_closed_loop_control_loop are very similar and differ only in where we get the estimate from. bool Axis::run_sensorless_control_loop() { set_step_dir_enabled(config_.enable_step_dir); run_control_loop([this](){ - float pos_estimate, vel_estimate, phase, current_setpoint; - if (controller_.config_.control_mode >= CTRL_MODE_POSITION_CONTROL) return error_ |= ERROR_POS_CTRL_DURING_SENSORLESS, false; - // We update the encoder just in case someone needs the output for testing - encoder_.update(nullptr, nullptr, nullptr); - if (!sensorless_estimator_.update(&pos_estimate, &vel_estimate, &phase)) - return error_ |= ERROR_SENSORLESS_ESTIMATOR_FAILED, false; - if (!controller_.update(pos_estimate, vel_estimate, ¤t_setpoint)) + // Note that all estimators are updated in the loop prefix in run_control_loop + float current_setpoint; + if (!controller_.update(sensorless_estimator_.pll_pos_, sensorless_estimator_.pll_vel_, ¤t_setpoint)) return error_ |= ERROR_CONTROLLER_FAILED, false; - if (!motor_.update(current_setpoint, phase)) - return error_ |= ERROR_MOTOR_FAILED, false; + if (!motor_.update(current_setpoint, sensorless_estimator_.phase_)) + return false; // set_error should update axis.error_ return true; }); set_step_dir_enabled(false); - return error_ == ERROR_NO_ERROR; + return error_ == ERROR_NONE; } bool Axis::run_closed_loop_control_loop() { set_step_dir_enabled(config_.enable_step_dir); run_control_loop([this](){ - float pos_estimate, vel_estimate, phase, current_setpoint; - - // We update the sensorless estimator just in case someone needs the output for testing - sensorless_estimator_.update(nullptr, nullptr, nullptr); - if (!encoder_.update(&pos_estimate, &vel_estimate, &phase)) - return error_ |= ERROR_ENCODER_FAILED, false; - if (!controller_.update(pos_estimate, vel_estimate, ¤t_setpoint)) - return error_ |= ERROR_CONTROLLER_FAILED, false; - if (!motor_.update(current_setpoint, phase)) - return error_ |= ERROR_MOTOR_FAILED, false; + // Note that all estimators are updated in the loop prefix in run_control_loop + float current_setpoint; + if (!controller_.update(encoder_.pos_estimate_, encoder_.pll_vel_, ¤t_setpoint)) + return error_ |= ERROR_CONTROLLER_FAILED, false; //TODO: Make controller.set_error + if (!motor_.update(current_setpoint, encoder_.phase_)) + return false; // set_error should update axis.error_ return true; }); set_step_dir_enabled(false); - return error_ == ERROR_NO_ERROR; + return error_ == ERROR_NONE; } bool Axis::run_idle_loop() { @@ -179,11 +190,9 @@ bool Axis::run_idle_loop() { // if and only if we're in AXIS_STATE_IDLE safety_critical_disarm_motor_pwm(motor_); run_control_loop([this](){ - sensorless_estimator_.update(nullptr, nullptr, nullptr); - encoder_.update(nullptr, nullptr, nullptr); return true; }); - return error_ == ERROR_NO_ERROR; + return error_ == ERROR_NONE; } // Infinite loop that does calibration and enters main control loop as appropriate @@ -246,43 +255,37 @@ void Axis::run_state_machine_loop() { // Handlers should exit if requested_state != AXIS_STATE_UNDEFINED bool status; switch (current_state_) { - case AXIS_STATE_MOTOR_CALIBRATION: - status = motor_.run_calibration(); - if (!status) - error_ |= ERROR_MOTOR_FAILED; - break; + case AXIS_STATE_MOTOR_CALIBRATION: + status = motor_.run_calibration(); + break; - case AXIS_STATE_ENCODER_INDEX_SEARCH: - status = encoder_.run_index_search(); - if (!status) - error_ |= ERROR_ENCODER_FAILED; - break; + case AXIS_STATE_ENCODER_INDEX_SEARCH: + status = encoder_.run_index_search(); + break; - case AXIS_STATE_ENCODER_OFFSET_CALIBRATION: - status = encoder_.run_offset_calibration(); - if (!status) - error_ |= ERROR_ENCODER_FAILED; - break; + case AXIS_STATE_ENCODER_OFFSET_CALIBRATION: + status = encoder_.run_offset_calibration(); + break; - case AXIS_STATE_SENSORLESS_CONTROL: - status = run_sensorless_spin_up(); // TODO: restart if desired - if (status) - status = run_sensorless_control_loop(); - break; + case AXIS_STATE_SENSORLESS_CONTROL: + status = run_sensorless_spin_up(); // TODO: restart if desired + if (status) + status = run_sensorless_control_loop(); + break; - case AXIS_STATE_CLOSED_LOOP_CONTROL: - status = run_closed_loop_control_loop(); - break; + case AXIS_STATE_CLOSED_LOOP_CONTROL: + status = run_closed_loop_control_loop(); + break; - case AXIS_STATE_IDLE: - run_idle_loop(); - status = motor_.arm(); // done with idling - try to arm the motor - break; + case AXIS_STATE_IDLE: + run_idle_loop(); + status = motor_.arm(); // done with idling - try to arm the motor + break; - default: - error_ |= ERROR_INVALID_STATE; - status = false; // this will set the state to idle - break; + default: + error_ |= ERROR_INVALID_STATE; + status = false; // this will set the state to idle + break; } // If the state failed, go to idle, else advance task chain @@ -291,6 +294,4 @@ void Axis::run_state_machine_loop() { else memcpy(task_chain_, task_chain_ + 1, sizeof(task_chain_) - sizeof(task_chain_[0])); } - - thread_id_valid_ = false; } diff --git a/Firmware/MotorControl/axis.hpp b/Firmware/MotorControl/axis.hpp index 9ad4804a..8eda2892 100644 --- a/Firmware/MotorControl/axis.hpp +++ b/Firmware/MotorControl/axis.hpp @@ -42,7 +42,7 @@ struct AxisConfig_t { class Axis { public: enum Error_t { - ERROR_NO_ERROR = 0x00, + ERROR_NONE = 0x00, ERROR_INVALID_STATE = 0x01, // void run_control_loop(const T& update_handler) { while (requested_state_ == AXIS_STATE_UNDEFINED) { - if (!brake_resistor_armed_) { - error_ |= ERROR_BRAKE_RESISTOR_DISARMED; + if (!do_checks()) // look for errors at axis level and also all subcomponents break; - } - if ((current_state_ != AXIS_STATE_IDLE) && (motor_.armed_state_ == Motor::ARMED_STATE_DISARMED)) { - // motor got disarmed in something other than the idle loop - error_ |= ERROR_MOTOR_DISARMED; - break; - } - if (motor_.error_ != Motor::ERROR_NO_ERROR) { - error_ |= ERROR_MOTOR_FAILED; - break; - } - - if (!do_checks()) // error set during function call + if (!do_updates()) // Update all estimators break; // Run main loop function, defer quitting for after wait @@ -160,7 +149,7 @@ public: volatile bool thread_id_valid_ = false; // variables exposed on protocol - Error_t error_ = ERROR_NO_ERROR; + Error_t error_ = ERROR_NONE; bool enable_step_dir_ = false; // auto enabled after calibration, based on config.enable_step_dir AxisState_t requested_state_ = AXIS_STATE_STARTUP_SEQUENCE; AxisState_t task_chain_[10] = { AXIS_STATE_UNDEFINED }; diff --git a/Firmware/MotorControl/board_config_v3.h b/Firmware/MotorControl/board_config_v3.h index 791246de..b0dbcb8e 100644 --- a/Firmware/MotorControl/board_config_v3.h +++ b/Firmware/MotorControl/board_config_v3.h @@ -32,6 +32,12 @@ typedef struct { TIM_HandleTypeDef* timer; GPIO_TypeDef* index_port; uint16_t index_pin; + GPIO_TypeDef* hallA_port; + uint16_t hallA_pin; + GPIO_TypeDef* hallB_port; + uint16_t hallB_pin; + GPIO_TypeDef* hallC_port; + uint16_t hallC_pin; } EncoderHardwareConfig_t; typedef struct { TIM_HandleTypeDef* timer; @@ -56,6 +62,7 @@ typedef struct { extern const BoardHardwareConfig_t hw_configs[2]; +//TODO stick this in a C file #ifdef __MAIN_CPP__ const BoardHardwareConfig_t hw_configs[2] = { { .axis_config = { @@ -69,6 +76,12 @@ const BoardHardwareConfig_t hw_configs[2] = { { .timer = &htim3, .index_port = M0_ENC_Z_GPIO_Port, .index_pin = M0_ENC_Z_Pin, + .hallA_port = M0_ENC_A_GPIO_Port, + .hallA_pin = M0_ENC_A_Pin, + .hallB_port = M0_ENC_B_GPIO_Port, + .hallB_pin = M0_ENC_B_Pin, + .hallC_port = M0_ENC_Z_GPIO_Port, + .hallC_pin = M0_ENC_Z_Pin, }, .motor_config = { .timer = &htim1, @@ -97,6 +110,12 @@ const BoardHardwareConfig_t hw_configs[2] = { { .timer = &htim4, .index_port = M1_ENC_Z_GPIO_Port, .index_pin = M1_ENC_Z_Pin, + .hallA_port = M1_ENC_A_GPIO_Port, + .hallA_pin = M1_ENC_A_Pin, + .hallB_port = M1_ENC_B_GPIO_Port, + .hallB_pin = M1_ENC_B_Pin, + .hallC_port = M1_ENC_Z_GPIO_Port, + .hallC_pin = M1_ENC_Z_Pin, }, .motor_config = { .timer = &htim8, @@ -117,4 +136,12 @@ const BoardHardwareConfig_t hw_configs[2] = { { #endif + +#define I2C_A0_PORT GPIO_3_GPIO_Port +#define I2C_A0_PIN GPIO_3_Pin +#define I2C_A1_PORT GPIO_4_GPIO_Port +#define I2C_A1_PIN GPIO_4_Pin +#define I2C_A2_PORT GPIO_5_GPIO_Port +#define I2C_A2_PIN GPIO_5_Pin + #endif // __BOARD_CONFIG_H diff --git a/Firmware/MotorControl/controller.cpp b/Firmware/MotorControl/controller.cpp index 7cc55894..43bb206b 100644 --- a/Firmware/MotorControl/controller.cpp +++ b/Firmware/MotorControl/controller.cpp @@ -46,7 +46,7 @@ void Controller::set_current_setpoint(float current_setpoint) { void Controller::start_anticogging_calibration() { // Ensure the cogging map was correctly allocated earlier and that the motor is capable of calibrating - if (anticogging_.cogging_map != NULL && axis_->error_ == Axis::ERROR_NO_ERROR) { + if (anticogging_.cogging_map != NULL && axis_->error_ == Axis::ERROR_NONE) { anticogging_.calib_anticogging = true; } } diff --git a/Firmware/MotorControl/controller.hpp b/Firmware/MotorControl/controller.hpp index c76161ea..f10b6211 100644 --- a/Firmware/MotorControl/controller.hpp +++ b/Firmware/MotorControl/controller.hpp @@ -18,7 +18,7 @@ struct ControllerConfig_t { Motor_control_mode_t control_mode = CTRL_MODE_POSITION_CONTROL; //see: Motor_control_mode_t float pos_gain = 20.0f; // [(counts/s) / counts] float vel_gain = 5.0f / 10000.0f; // [A/(counts/s)] - // float vel_gain = 15.0f / 200.0f, // [A/(rad/s)] + // float vel_gain = 5.0f / 200.0f, // [A/(rad/s)] float vel_integrator_gain = 10.0f / 10000.0f; // [A/(counts/s * s)] float vel_limit = 20000.0f; // [counts/s] }; diff --git a/Firmware/MotorControl/encoder.cpp b/Firmware/MotorControl/encoder.cpp index 2c5de455..f80f04dc 100644 --- a/Firmware/MotorControl/encoder.cpp +++ b/Firmware/MotorControl/encoder.cpp @@ -3,7 +3,7 @@ Encoder::Encoder(const EncoderHardwareConfig_t& hw_config, - EncoderConfig_t& config) : + Config_t& config) : hw_config_(hw_config), config_(config) { @@ -14,6 +14,11 @@ Encoder::Encoder(const EncoderHardwareConfig_t& hw_config, // Critically damped pll_ki_ = 0.25f * (pll_kp_ * pll_kp_); + + if (config.pre_calibrated && (config.mode == Encoder::MODE_HALL)) { + offset_ = config.offset; + is_ready_ = true; + } } static void enc_index_cb_wrapper(void* ctx) { @@ -26,6 +31,15 @@ void Encoder::setup() { enc_index_cb_wrapper, this); } +void Encoder::set_error(Encoder::Error_t error) { + error_ |= error; + axis_->error_ |= Axis::ERROR_MOTOR_FAILED; +} + +bool Encoder::do_checks(){ + return error_ == ERROR_NONE; +} + //-------------------- // Hardware Dependent //-------------------- @@ -105,7 +119,7 @@ bool Encoder::run_index_search() { // continue until the index is found return !index_found_; }); - return axis_->error_ != Axis::ERROR_NO_ERROR; + return true; } // @brief Turns the motor in one direction for a bit and then in the other @@ -139,10 +153,10 @@ bool Encoder::run_offset_calibration() { axis_->motor_.log_timing(Motor::TIMING_LOG_ENC_CALIB); return ++i < start_lock_duration * current_meas_hz; }); - if (axis_->error_ != Axis::ERROR_NO_ERROR) + if (axis_->error_ != Axis::ERROR_NONE) return false; - int32_t init_enc_val = (int16_t)hw_config_.timer->Instance->CNT; + int32_t init_enc_val = shadow_count_; int64_t encvaluesum = 0; // scan forward @@ -155,32 +169,32 @@ bool Encoder::run_offset_calibration() { return false; // error set inside enqueue_voltage_timings axis_->motor_.log_timing(Motor::TIMING_LOG_ENC_CALIB); - encvaluesum += (int16_t)hw_config_.timer->Instance->CNT; + encvaluesum += shadow_count_; return ++i < num_steps; }); - if (axis_->error_ != Axis::ERROR_NO_ERROR) + if (axis_->error_ != Axis::ERROR_NONE) return false; //TODO avoid recomputing elec_rad_per_enc every time float elec_rad_per_enc = axis_->motor_.config_.pole_pairs * 2 * M_PI * (1.0f / (float)(config_.cpr)); float expected_encoder_delta = scan_distance / elec_rad_per_enc; - float actual_encoder_delta_abs = fabsf((int16_t)hw_config_.timer->Instance->CNT-init_enc_val); + float actual_encoder_delta_abs = fabsf(shadow_count_-init_enc_val); if(fabsf(actual_encoder_delta_abs - expected_encoder_delta)/expected_encoder_delta > config_.calib_range) { - error_ |= ERROR_CPR_OUT_OF_RANGE; + set_error(ERROR_CPR_OUT_OF_RANGE); return false; } // check direction - if ((int16_t)hw_config_.timer->Instance->CNT > init_enc_val + 8) { + if (shadow_count_ > init_enc_val + 8) { // motor same dir as encoder axis_->motor_.config_.direction = 1; - } else if ((int16_t)hw_config_.timer->Instance->CNT < init_enc_val - 8) { + } else if (shadow_count_ < init_enc_val - 8) { // motor opposite dir as encoder axis_->motor_.config_.direction = -1; } else { // Encoder response error - error_ |= ERROR_RESPONSE; + set_error(ERROR_RESPONSE); return false; } @@ -194,61 +208,118 @@ bool Encoder::run_offset_calibration() { return false; // error set inside enqueue_voltage_timings axis_->motor_.log_timing(Motor::TIMING_LOG_ENC_CALIB); - encvaluesum += (int16_t)hw_config_.timer->Instance->CNT; + encvaluesum += shadow_count_; return ++i < num_steps; }); - if (axis_->error_ != Axis::ERROR_NO_ERROR) + if (axis_->error_ != Axis::ERROR_NONE) return false; offset_ = encvaluesum / (num_steps * 2); + config_.offset = offset_; + int32_t residual = encvaluesum - ((int64_t)offset_ * (int64_t)(num_steps * 2)); + config_.offset_float = (float)residual / (float)(num_steps * 2) + 0.5f; // add 0.5 to center-align state to phase is_ready_ = true; config_.use_index = old_use_index; return true; } -bool Encoder::update(float* pos_estimate, float* vel_estimate, float* phase_output) { +static bool decode_hall(uint8_t hall_state, int32_t* hall_cnt) { + switch (hall_state) { + case 0b001: *hall_cnt = 0; return true; + case 0b011: *hall_cnt = 1; return true; + case 0b010: *hall_cnt = 2; return true; + case 0b110: *hall_cnt = 3; return true; + case 0b100: *hall_cnt = 4; return true; + case 0b101: *hall_cnt = 5; return true; + default: return false; + } +} + +bool Encoder::update() { // Check that we don't get problems with discrete time approximation if (!(current_meas_period * pll_kp_ < 1.0f)) { - error_ |= ERROR_NUMERICAL; + set_error(ERROR_UNSTABLE_GAIN); return false; } - // update internal encoder state - int16_t delta_enc_16 = (int16_t)hw_config_.timer->Instance->CNT - (int16_t)shadow_count_; - int32_t delta_enc = (int32_t)delta_enc_16; //sign extend + // update internal encoder state. + int32_t delta_enc = 0; + switch (config_.mode) { + case MODE_INCREMENTAL: { + //TODO: use count_in_cpr_ instead as shadow_count_ can overflow + //or use 64 bit + int16_t delta_enc_16 = (int16_t)hw_config_.timer->Instance->CNT - (int16_t)shadow_count_; + delta_enc = (int32_t)delta_enc_16; //sign extend + } break; + + case MODE_HALL: { + int32_t hall_cnt; + if (decode_hall(hall_state_, &hall_cnt)) { + delta_enc = hall_cnt - count_in_cpr_; + delta_enc = mod(delta_enc, 6); + if (delta_enc > 3) + delta_enc -= 6; + } else { + set_error(ERROR_ILLEGAL_HALL_STATE); + return false; + } + } break; + + default: { + set_error(ERROR_UNSUPPORTED_ENCODER_MODE); + return false; + } break; + } + shadow_count_ += delta_enc; count_in_cpr_ += delta_enc; count_in_cpr_ = mod(count_in_cpr_, config_.cpr); - // compute electrical phase - int corrected_enc = count_in_cpr_ - offset_; - //TODO avoid recomputing elec_rad_per_enc every time - float elec_rad_per_enc = axis_->motor_.config_.pole_pairs * 2 * M_PI * (1.0f / (float)(config_.cpr)); - float ph = elec_rad_per_enc * (float)corrected_enc; - // ph = fmodf(ph, 2*M_PI); - phase_ = wrap_pm_pi(ph); - - - // run pll (for now pll is in units of encoder counts) + //// run pll (for now pll is in units of encoder counts) // Predict current pos pos_estimate_ += current_meas_period * pll_vel_; - pos_cpr_ += current_meas_period * pll_vel_; + pos_cpr_ += current_meas_period * pll_vel_; // discrete phase detector float delta_pos = (float)(shadow_count_ - (int32_t)floorf(pos_estimate_)); float delta_pos_cpr = (float)(count_in_cpr_ - (int32_t)floorf(pos_cpr_)); delta_pos_cpr = wrap_pm(delta_pos_cpr, 0.5f * (float)(config_.cpr)); // pll feedback pos_estimate_ += current_meas_period * pll_kp_ * delta_pos; - pos_cpr_ += current_meas_period * pll_kp_ * delta_pos_cpr; + pos_cpr_ += current_meas_period * pll_kp_ * delta_pos_cpr; pos_cpr_ = fmodf_pos(pos_cpr_, (float)(config_.cpr)); pll_vel_ += current_meas_period * pll_ki_ * delta_pos_cpr; - if (fabsf(pll_vel_) < 0.5f * current_meas_period * pll_ki_) + bool snap_to_zero_vel = false; + if (fabsf(pll_vel_) < 0.5f * current_meas_period * pll_ki_) { pll_vel_ = 0.0f; //align delta-sigma on zero to prevent jitter + snap_to_zero_vel = true; + } + + //// run encoder count interpolation + int32_t corrected_enc = count_in_cpr_ - offset_; + // if we are stopped, make sure we don't randomly drift + if (snap_to_zero_vel) { + interpolation_ = 0.5f; + // reset interpolation if encoder edge comes + } else if (delta_enc > 0) { + interpolation_ = 0.0f; + } else if (delta_enc < 0) { + interpolation_ = 1.0f; + } else { + // Interpolate (predict) between encoder counts using pll_vel, + interpolation_ += current_meas_period * pll_vel_; + // don't allow interpolation indicated position outside of [enc, enc+1) + if (interpolation_ > 1.0f) interpolation_ = 1.0f; + if (interpolation_ < 0.0f) interpolation_ = 0.0f; + } + float interpolated_enc = corrected_enc + interpolation_; + + //// compute electrical phase + //TODO avoid recomputing elec_rad_per_enc every time + float elec_rad_per_enc = axis_->motor_.config_.pole_pairs * 2 * M_PI * (1.0f / (float)(config_.cpr)); + float ph = elec_rad_per_enc * (interpolated_enc - config_.offset_float); + // ph = fmodf(ph, 2*M_PI); + phase_ = wrap_pm_pi(ph); - // Assign output arguments - if (pos_estimate) *pos_estimate = pos_estimate_; - if (vel_estimate) *vel_estimate = pll_vel_; - if (phase_output) *phase_output = phase_; return true; } diff --git a/Firmware/MotorControl/encoder.hpp b/Firmware/MotorControl/encoder.hpp index 9a59654e..60299dca 100644 --- a/Firmware/MotorControl/encoder.hpp +++ b/Firmware/MotorControl/encoder.hpp @@ -5,33 +5,44 @@ #error "This file should not be included directly. Include odrive_main.h instead." #endif -struct EncoderConfig_t { - bool use_index = false; - bool pre_calibrated = false; // If true, this means the offset stored in - // configuration is valid and does not need - // be determined by run_offset_calibration. - // In this case the encoder will enter ready - // state as soon as the index is found. - float idx_search_speed = 10.0f; // [rad/s electrical] - int32_t cpr = (2048 * 4); // Default resolution of CUI-AMT102 encoder, - int32_t offset = 0; // If pre_calibrated is true, this is copied into encoder.offset_ once - // index search succeeds - float calib_range = 0.02f; -}; - class Encoder { public: enum Error_t { ERROR_NONE = 0, - ERROR_NUMERICAL = 0x01, + ERROR_UNSTABLE_GAIN = 0x01, ERROR_CPR_OUT_OF_RANGE = 0x02, ERROR_RESPONSE = 0x04, + ERROR_UNSUPPORTED_ENCODER_MODE = 0x08, + ERROR_ILLEGAL_HALL_STATE = 0x10, + }; + + enum Mode_t { + MODE_INCREMENTAL, + MODE_HALL + }; + + struct Config_t { + Encoder::Mode_t mode = Encoder::MODE_INCREMENTAL; + bool use_index = false; + bool pre_calibrated = false; // If true, this means the offset stored in + // configuration is valid and does not need + // be determined by run_offset_calibration. + // In this case the encoder will enter ready + // state as soon as the index is found. + float idx_search_speed = 10.0f; // [rad/s electrical] + int32_t cpr = (2048 * 4); // Default resolution of CUI-AMT102 encoder, + int32_t offset = 0; // If pre_calibrated is true, this is copied into encoder.offset_ once + // index search succeeds + float offset_float = 0.0f; // Sub-count phase alignment offset + float calib_range = 0.02f; }; Encoder(const EncoderHardwareConfig_t& hw_config, - EncoderConfig_t& config); + Config_t& config); void setup(); + void set_error(Error_t error); + bool do_checks(); void enc_index_cb(); @@ -42,10 +53,10 @@ public: bool run_index_search(); bool run_offset_calibration(); - bool update(float* pos_estimate, float* vel_estimate, float* phase); + bool update(); const EncoderHardwareConfig_t& hw_config_; - EncoderConfig_t& config_; + Config_t& config_; Axis* axis_ = nullptr; // set by Axis constructor Error_t error_ = ERROR_NONE; @@ -54,6 +65,7 @@ public: int32_t shadow_count_ = 0; int32_t count_in_cpr_ = 0; int32_t offset_ = 0; + float interpolation_ = 0.0f; float phase_ = 0.0f; // [rad] float pos_estimate_ = 0.0f; // [rad] float pos_cpr_ = 0.0f; // [rad] @@ -61,6 +73,9 @@ public: float pll_kp_ = 0.0f; // [rad/s / rad] float pll_ki_ = 0.0f; // [(rad/s^2) / rad] + // Updated by low_level pwm_adc_cb + uint8_t hall_state_ = 0x0; // bit[0] = HallA, .., bit[2] = HallC + // Communication protocol definitions auto make_protocol_definitions() { return make_protocol_member_list( @@ -70,18 +85,22 @@ public: make_protocol_property("shadow_count", &shadow_count_), make_protocol_property("count_in_cpr", &count_in_cpr_), make_protocol_property("offset", &offset_), + make_protocol_property("interpolation", &interpolation_), make_protocol_property("phase", &phase_), make_protocol_property("pos_estimate", &pos_estimate_), make_protocol_property("pos_cpr", &pos_cpr_), + make_protocol_property("hall_state", &hall_state_), make_protocol_property("pll_vel", &pll_vel_), make_protocol_property("pll_kp", &pll_kp_), make_protocol_property("pll_ki", &pll_ki_), make_protocol_object("config", + make_protocol_property("mode", &config_.mode), make_protocol_property("use_index", &config_.use_index), make_protocol_property("pre_calibrated", &config_.pre_calibrated), make_protocol_property("idx_search_speed", &config_.idx_search_speed), make_protocol_property("cpr", &config_.cpr), make_protocol_property("offset", &config_.offset), + make_protocol_property("offset_float", &config_.offset_float), make_protocol_property("calib_range", &config_.calib_range) ) ); diff --git a/Firmware/MotorControl/low_level.cpp b/Firmware/MotorControl/low_level.cpp index dc8be580..9b701609 100644 --- a/Firmware/MotorControl/low_level.cpp +++ b/Firmware/MotorControl/low_level.cpp @@ -29,14 +29,18 @@ /* Private typedef -----------------------------------------------------------*/ /* Global constant data ------------------------------------------------------*/ /* Global variables ----------------------------------------------------------*/ + // This value is updated by the DC-bus reading ADC. // Arbitrary non-zero inital value to avoid division by zero if ADC reading is late float vbus_voltage = 12.0f; -bool brake_resistor_armed_ = false; - +bool brake_resistor_armed = false; /* Private constant data -----------------------------------------------------*/ +static const GPIO_TypeDef* GPIOs_to_samp[] = { GPIOA, GPIOB, GPIOC }; +static const int num_GPIO = sizeof(GPIOs_to_samp) / sizeof(GPIOs_to_samp[0]); /* Private variables ---------------------------------------------------------*/ +// Two motors, sampling port A,B,C (coherent with current meas timing) +static uint16_t GPIO_port_samples [2][num_GPIO]; /* CPU critical section helpers ----------------------------------------------*/ static inline uint8_t cpu_enter_critical() { @@ -94,13 +98,23 @@ static inline void cpu_exit_critical(uint8_t status_register) { * at a high rate. */ +// @brief Floats ALL phases immediately and disarms both motors and the brake resistor. +void low_level_fault(Motor::Error_t error) { + // Disable all motors NOW! + for (size_t i = 0; i < AXIS_COUNT; ++i) { + safety_critical_disarm_motor_pwm(axes[i]->motor_); + axes[i]->motor_.error_ |= error; + } + + safety_critical_disarm_brake_resistor(); +} // @brief Kicks off the arming process of the motor. // All calls to this function must clearly originate // from user input. void safety_critical_arm_motor_pwm(Motor& motor) { uint8_t sr = cpu_enter_critical(); - if (brake_resistor_armed_) { + if (brake_resistor_armed) { motor.armed_state_ = Motor::ARMED_STATE_WAITING_FOR_TIMINGS; } cpu_exit_critical(sr); @@ -127,7 +141,7 @@ bool safety_critical_disarm_motor_pwm(Motor& motor) { // timer period. void safety_critical_apply_motor_pwm_timings(Motor& motor, uint16_t timings[3]) { uint8_t sr = cpu_enter_critical(); - if (!brake_resistor_armed_) { + if (!brake_resistor_armed) { motor.armed_state_ = Motor::ARMED_STATE_ARMED; } @@ -158,7 +172,7 @@ void safety_critical_apply_motor_pwm_timings(Motor& motor, uint16_t timings[3]) // @brief Arms the brake resistor void safety_critical_arm_brake_resistor() { uint8_t sr = cpu_enter_critical(); - brake_resistor_armed_ = true; + brake_resistor_armed = true; htim2.Instance->CCR3 = 0; htim2.Instance->CCR4 = TIM_APB1_PERIOD_CLOCKS + 1; cpu_exit_critical(sr); @@ -170,7 +184,7 @@ void safety_critical_arm_brake_resistor() { // by calling safety_critical_arm_brake_resistor(). void safety_critical_disarm_brake_resistor() { uint8_t sr = cpu_enter_critical(); - brake_resistor_armed_ = false; + brake_resistor_armed = false; htim2.Instance->CCR3 = 0; htim2.Instance->CCR4 = TIM_APB1_PERIOD_CLOCKS + 1; for (size_t i = 0; i < AXIS_COUNT; ++i) { @@ -183,9 +197,9 @@ void safety_critical_disarm_brake_resistor() { // the brake resistor is disarmed. void safety_critical_apply_brake_resistor_timings(uint32_t low_off, uint32_t high_on) { if (high_on - low_off < TIM_APB1_DEADTIME_CLOCKS) - for(;;); + low_level_fault(Motor::ERROR_BRAKE_DEADTIME_VIOLATION); uint8_t sr = cpu_enter_critical(); - if (brake_resistor_armed_) { + if (brake_resistor_armed) { // Safe update of low and high side timings // To avoid race condition, first reset timings to safe state // ch3 is low side, ch4 is high side @@ -225,6 +239,10 @@ void start_adc_pwm() { __HAL_TIM_MOE_DISABLE_UNCONDITIONALLY(&htim1); __HAL_TIM_MOE_DISABLE_UNCONDITIONALLY(&htim8); + // Enable the update interrupt (used to coherently sample GPIO) + __HAL_TIM_ENABLE_IT(&htim1, TIM_IT_UPDATE); + __HAL_TIM_ENABLE_IT(&htim8, TIM_IT_UPDATE); + // Start brake resistor PWM in floating output configuration htim2.Instance->CCR3 = 0; htim2.Instance->CCR4 = TIM_APB1_PERIOD_CLOCKS + 1; @@ -303,17 +321,6 @@ void sync_timers(TIM_HandleTypeDef* htim_a, TIM_HandleTypeDef* htim_b, htim_b->Instance->BDTR |= MOE_store_b; } -// @brief Floats ALL phases immediately and disarms both motors and the brake resistor. -void low_level_fault(Motor::Error_t error) { - // Disable all motors NOW! - for (size_t i = 0; i < AXIS_COUNT; ++i) { - safety_critical_disarm_motor_pwm(axes[i]->motor_); - axes[i]->motor_.error_ |= error; - } - - safety_critical_disarm_brake_resistor(); -} - // @brief ADC1 measurements are written to this buffer by DMA uint16_t adc_measurements_[ADC_CHANNEL_COUNT] = { 0 }; @@ -424,7 +431,6 @@ float get_adc_voltage(GPIO_TypeDef* GPIO_port, uint16_t GPIO_pin) { // IRQ Callbacks //-------------------------------- - void vbus_sense_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { static const float voltage_scale = 3.3f * VBUS_S_DIVIDER_RATIO / (float)(1 << 12); // Only one conversion in sequence, so only rank1 @@ -437,6 +443,35 @@ void vbus_sense_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { } } +static void decode_hall_samples(Encoder& enc, uint16_t GPIO_samples[num_GPIO]) { + GPIO_TypeDef* hall_ports[] = { + enc.hw_config_.hallC_port, + enc.hw_config_.hallB_port, + enc.hw_config_.hallA_port, + }; + uint16_t hall_pins[] = { + enc.hw_config_.hallC_pin, + enc.hw_config_.hallB_pin, + enc.hw_config_.hallA_pin, + }; + + uint8_t hall_state = 0x0; + for (int i = 0; i < 3; ++i) { + int port_idx = 0; + for (;;) { + auto port = GPIOs_to_samp[port_idx]; + if (port == hall_ports[i]) + break; + ++port_idx; + } + + hall_state <<= 1; + hall_state |= (GPIO_samples[port_idx] & hall_pins[i]) ? 1 : 0; + } + + enc.hall_state_ = hall_state; +} + // This is the callback from the ADC that we expect after the PWM has triggered an ADC conversion. // TODO: Document how the phasing is done, link to timing diagram void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { @@ -454,6 +489,7 @@ void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { // If the corresponding timer is counting up, we just sampled in SVM vector 0, i.e. real current // If we are counting down, we just sampled in SVM vector 7, with zero current Axis& axis = injected ? *axes[0] : *axes[1]; + int axis_num = injected ? 0 : 1; Axis& other_axis = injected ? *axes[1] : *axes[0]; bool counting_down = axis.motor_.hw_config_.timer->Instance->CR1 & TIM_CR1_DIR; @@ -512,6 +548,8 @@ void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { } else { axis.motor_.current_meas_.phC = current - axis.motor_.DC_calib_.phC; } + // Prepare hall readings + decode_hall_samples(axis.encoder_, GPIO_port_samples[axis_num]); // Trigger axis thread axis.signal_current_meas(); } else { @@ -524,6 +562,22 @@ void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { } } +void tim_update_cb(TIM_HandleTypeDef* htim) { + int portsamples_arr; + if (htim == &htim1) { + portsamples_arr = 0; + } else if (htim == &htim8) { + portsamples_arr = 1; + } else { + low_level_fault(Motor::ERROR_UNEXPECTED_TIMER_CALLBACK); + return; + } + + for (int i = 0; i < num_GPIO; ++i) { + GPIO_port_samples[portsamples_arr][i] = GPIOs_to_samp[i]->IDR; + } +} + // @brief Sums up the Ibus contribution of each motor and updates the // brake resistor PWM accordingly. void update_brake_current() { diff --git a/Firmware/MotorControl/low_level.h b/Firmware/MotorControl/low_level.h index d99c9916..095881cc 100644 --- a/Firmware/MotorControl/low_level.h +++ b/Firmware/MotorControl/low_level.h @@ -18,6 +18,8 @@ extern "C" { /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ /* Exported variables --------------------------------------------------------*/ +extern float vbus_voltage; +extern bool brake_resistor_armed; /* Exported macro ------------------------------------------------------------*/ /* Exported functions --------------------------------------------------------*/ @@ -32,6 +34,7 @@ void safety_critical_apply_brake_resistor_timings(uint32_t low_off, uint32_t hig extern "C" { void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected); void vbus_sense_adc_cb(ADC_HandleTypeDef* hadc, bool injected); +void tim_update_cb(TIM_HandleTypeDef* htim); } // Initalisation diff --git a/Firmware/MotorControl/main.cpp b/Firmware/MotorControl/main.cpp index 2fea3d8c..4801b039 100644 --- a/Firmware/MotorControl/main.cpp +++ b/Firmware/MotorControl/main.cpp @@ -6,9 +6,10 @@ #include "freertos_vars.h" #include #include +#include BoardConfig_t board_config; -EncoderConfig_t encoder_configs[AXIS_COUNT]; +Encoder::Config_t encoder_configs[AXIS_COUNT]; ControllerConfig_t controller_configs[AXIS_COUNT]; MotorConfig_t motor_configs[AXIS_COUNT]; AxisConfig_t axis_configs[AXIS_COUNT]; @@ -20,7 +21,7 @@ Axis *axes[AXIS_COUNT]; typedef Config< BoardConfig_t, - EncoderConfig_t[AXIS_COUNT], + Encoder::Config_t[AXIS_COUNT], ControllerConfig_t[AXIS_COUNT], MotorConfig_t[AXIS_COUNT], AxisConfig_t[AXIS_COUNT]> ConfigFormat; @@ -33,6 +34,8 @@ void save_configuration(void) { &motor_configs, &axis_configs)) { //printf("saving configuration failed\r\n"); osDelay(5); + } else { + user_config_loaded_ = true; } } @@ -48,7 +51,7 @@ void load_configuration(void) { //If loading failed, restore defaults board_config = BoardConfig_t(); for (size_t i = 0; i < AXIS_COUNT; ++i) { - encoder_configs[i] = EncoderConfig_t(); + encoder_configs[i] = Encoder::Config_t(); controller_configs[i] = ControllerConfig_t(); motor_configs[i] = MotorConfig_t(); axis_configs[i] = AxisConfig_t(); @@ -104,6 +107,29 @@ int odrive_main(void) { // Load persistent configuration (or defaults) load_configuration(); + if (board_config.enable_i2c_instead_of_can) { + // Set up the direction GPIO as input + GPIO_InitTypeDef GPIO_InitStruct; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLUP; + + GPIO_InitStruct.Pin = I2C_A0_PIN; + HAL_GPIO_Init(I2C_A0_PORT, &GPIO_InitStruct); + GPIO_InitStruct.Pin = I2C_A1_PIN; + HAL_GPIO_Init(I2C_A1_PORT, &GPIO_InitStruct); + GPIO_InitStruct.Pin = I2C_A2_PIN; + HAL_GPIO_Init(I2C_A2_PORT, &GPIO_InitStruct); + + osDelay(1); + i2c_stats_.addr = (0xD << 3); + i2c_stats_.addr |= HAL_GPIO_ReadPin(I2C_A0_PORT, I2C_A0_PIN) != GPIO_PIN_RESET ? 0x1 : 0; + i2c_stats_.addr |= HAL_GPIO_ReadPin(I2C_A1_PORT, I2C_A1_PIN) != GPIO_PIN_RESET ? 0x2 : 0; + i2c_stats_.addr |= HAL_GPIO_ReadPin(I2C_A2_PORT, I2C_A2_PIN) != GPIO_PIN_RESET ? 0x4 : 0; + MX_I2C1_Init(i2c_stats_.addr); + } else { + MX_CAN1_Init(); + } + // Init general user ADC on some GPIOs. GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; diff --git a/Firmware/MotorControl/motor.cpp b/Firmware/MotorControl/motor.cpp index 3272c746..0c8707eb 100644 --- a/Firmware/MotorControl/motor.cpp +++ b/Firmware/MotorControl/motor.cpp @@ -65,41 +65,51 @@ void Motor::update_current_controller_gains() { // @brief Set up the gate drivers void Motor::DRV8301_setup() { - DRV_SPI_8301_Vars_t* local_regs = &gate_driver_regs_; - - DRV8301_enable(&gate_driver_); - DRV8301_setupSpi(&gate_driver_, local_regs); - - // TODO we can use reporting only if we actually wire up the nOCTW pin - local_regs->Ctrl_Reg_1.OC_MODE = DRV8301_OcMode_LatchShutDown; - // Overcurrent set to approximately 150A at 100degC. This may need tweaking. - local_regs->Ctrl_Reg_1.OC_ADJ_SET = DRV8301_VdsLevel_0p730_V; + // for reference: // 20V/V on 500uOhm gives a range of +/- 150A // 40V/V on 500uOhm gives a range of +/- 75A // 20V/V on 666uOhm gives a range of +/- 110A // 40V/V on 666uOhm gives a range of +/- 55A - local_regs->Ctrl_Reg_2.GAIN = DRV8301_ShuntAmpGain_40VpV; - // local_regs->Ctrl_Reg_2.GAIN = DRV8301_ShuntAmpGain_20VpV; - switch (local_regs->Ctrl_Reg_2.GAIN) { - case DRV8301_ShuntAmpGain_10VpV: - phase_current_rev_gain_ = 1.0f / 10.0f; - break; - case DRV8301_ShuntAmpGain_20VpV: - phase_current_rev_gain_ = 1.0f / 20.0f; - break; - case DRV8301_ShuntAmpGain_40VpV: - phase_current_rev_gain_ = 1.0f / 40.0f; - break; - case DRV8301_ShuntAmpGain_80VpV: - phase_current_rev_gain_ = 1.0f / 80.0f; - break; - } + // Solve for exact gain, then snap down to have equal or larger range as requested + // or largest possible range otherwise + static const float kMargin = 0.90f; + static const float max_output_swing = 1.6f; // [V] out of amplifier + float max_unity_gain_current = kMargin * max_output_swing * hw_config_.shunt_conductance; // [A] + float requested_gain = max_unity_gain_current / config_.requested_current_range; // [V/V] - float margin = 0.90f; - float max_input = margin * 0.3f * hw_config_.shunt_conductance; - float max_swing = margin * 1.6f * hw_config_.shunt_conductance * phase_current_rev_gain_; - current_control_.max_allowed_current = std::min(max_input, max_swing); + // Decoding array for snapping gain + std::array, 4> gain_choices = { + std::make_pair(10.0f, DRV8301_ShuntAmpGain_10VpV), + std::make_pair(20.0f, DRV8301_ShuntAmpGain_20VpV), + std::make_pair(40.0f, DRV8301_ShuntAmpGain_40VpV), + std::make_pair(80.0f, DRV8301_ShuntAmpGain_80VpV) + }; + + // We use lower_bound in reverse because it snaps up by default, we want to snap down. + auto gain_snap_down = std::lower_bound(gain_choices.crbegin(), gain_choices.crend(), requested_gain, + [](std::pair pair, float val){ + return pair.first > val; + }); + + // If we snap to outside the array, clip to smallest val + if(gain_snap_down == gain_choices.crend()) + --gain_snap_down; + + // Values for current controller + phase_current_rev_gain_ = 1.0f / gain_snap_down->first; + // Clip all current control to actual usable range + current_control_.max_allowed_current = max_unity_gain_current * phase_current_rev_gain_; + + // We now have the gain settings we want to use, lets set up DRV chip + DRV_SPI_8301_Vars_t* local_regs = &gate_driver_regs_; + DRV8301_enable(&gate_driver_); + DRV8301_setupSpi(&gate_driver_, local_regs); + + local_regs->Ctrl_Reg_1.OC_MODE = DRV8301_OcMode_LatchShutDown; + // Overcurrent set to approximately 150A at 100degC. This may need tweaking. + local_regs->Ctrl_Reg_1.OC_ADJ_SET = DRV8301_VdsLevel_0p730_V; + local_regs->Ctrl_Reg_2.GAIN = gain_snap_down->second; local_regs->SndCmd = true; DRV8301_writeData(&gate_driver_, local_regs); @@ -124,9 +134,14 @@ bool Motor::check_DRV_fault() { return true; } +void Motor::set_error(Motor::Error_t error){ + error_ |= error; + axis_->error_ |= Axis::ERROR_MOTOR_FAILED; +} + bool Motor::do_checks() { if (!check_DRV_fault()) { - error_ |= ERROR_DRV_FAULT; + set_error(ERROR_DRV_FAULT); return false; } return true; @@ -169,7 +184,7 @@ bool Motor::measure_phase_resistance(float test_current, float max_voltage) { float Ialpha = -(current_meas_.phB + current_meas_.phC); test_voltage += (kI * current_meas_period) * (test_current - Ialpha); if (test_voltage > max_voltage || test_voltage < -max_voltage) - return error_ |= ERROR_PHASE_RESISTANCE_OUT_OF_RANGE, false; + return set_error(ERROR_PHASE_RESISTANCE_OUT_OF_RANGE), false; // Test voltage along phase A if (!enqueue_voltage_timings(test_voltage, 0.0f)) @@ -178,7 +193,7 @@ bool Motor::measure_phase_resistance(float test_current, float max_voltage) { return ++i < num_test_cycles; }); - if (axis_->error_ != Axis::ERROR_NO_ERROR) + if (axis_->error_ != Axis::ERROR_NONE) return false; //// De-energize motor @@ -207,7 +222,7 @@ bool Motor::measure_phase_inductance(float voltage_low, float voltage_high) { return ++t < (num_cycles << 1); }); - if (axis_->error_ != Axis::ERROR_NO_ERROR) + if (axis_->error_ != Axis::ERROR_NONE) return false; //// De-energize motor @@ -223,7 +238,7 @@ bool Motor::measure_phase_inductance(float voltage_low, float voltage_high) { config_.phase_inductance = L; // TODO arbitrary values set for now if (L < 1e-6f || L > 500e-6f) - return error_ |= ERROR_PHASE_INDUCTANCE_OUT_OF_RANGE, false; + return set_error(ERROR_PHASE_INDUCTANCE_OUT_OF_RANGE), false; return true; } @@ -250,7 +265,7 @@ bool Motor::run_calibration() { bool Motor::enqueue_modulation_timings(float mod_alpha, float mod_beta) { float tA, tB, tC; if (SVM(mod_alpha, mod_beta, &tA, &tB, &tC) != 0) - return error_ |= ERROR_NUMERICAL, false; + return set_error(ERROR_MODULATION_MAGNITUDE), false; next_timings_[0] = (uint16_t)(tA * (float)TIM_1_8_PERIOD_CLOCKS); next_timings_[1] = (uint16_t)(tB * (float)TIM_1_8_PERIOD_CLOCKS); next_timings_[2] = (uint16_t)(tC * (float)TIM_1_8_PERIOD_CLOCKS); @@ -358,7 +373,7 @@ bool Motor::update(float current_setpoint, float phase) { if(!FOC_voltage(0.0f, current_setpoint, phase)) return false; } else { - error_ |= ERROR_NOT_IMPLEMENTED_MOTOR_TYPE; + set_error(ERROR_NOT_IMPLEMENTED_MOTOR_TYPE); return false; } return true; diff --git a/Firmware/MotorControl/motor.hpp b/Firmware/MotorControl/motor.hpp index 950141bb..852a64f4 100644 --- a/Firmware/MotorControl/motor.hpp +++ b/Firmware/MotorControl/motor.hpp @@ -37,7 +37,7 @@ typedef struct { // example: current_lim and calibration_current will instead determine the maximum voltage applied to the motor. typedef struct { bool pre_calibrated = false; // can be set to true to indicate that all values here are valid - int32_t pole_pairs = 7; // This value is correct for N5065 motors and Turnigy SK3 series. + int32_t pole_pairs = 7; float calibration_current = 10.0f; // [A] float resistance_calib_max_voltage = 1.0f; // [V] - You may need to increase this if this voltage isn't sufficient to drive calibration_current through the motor. float phase_inductance = 0.0f; // to be set by measure_phase_inductance @@ -46,23 +46,26 @@ typedef struct { Motor_type_t motor_type = MOTOR_TYPE_HIGH_CURRENT; // Read out max_allowed_current to see max supported value for current_lim. - // You can change DRV8301_ShuntAmpGain to get a different range. - // float current_lim = 75.0f; //[A] + // float current_lim = 70.0f; //[A] float current_lim = 10.0f; //[A] + // Value used to compute shunt amplifier gains + float requested_current_range = 70.0f; // [A] } MotorConfig_t; class Motor { public: enum Error_t { - ERROR_NO_ERROR = 0, - ERROR_PHASE_RESISTANCE_OUT_OF_RANGE = 0x01, - ERROR_PHASE_INDUCTANCE_OUT_OF_RANGE = 0x02, - ERROR_ADC_FAILED = 0x04, - ERROR_DRV_FAULT = 0x08, - ERROR_CONTROL_DEADLINE_MISSED = 0x10, - ERROR_NOT_IMPLEMENTED_MOTOR_TYPE = 0x20, - ERROR_BRAKE_CURRENT_OUT_OF_RANGE = 0x40, - ERROR_NUMERICAL = 0x80 + ERROR_NONE = 0, + ERROR_PHASE_RESISTANCE_OUT_OF_RANGE = 0x0001, + ERROR_PHASE_INDUCTANCE_OUT_OF_RANGE = 0x0002, + ERROR_ADC_FAILED = 0x0004, + ERROR_DRV_FAULT = 0x0008, + ERROR_CONTROL_DEADLINE_MISSED = 0x0010, + ERROR_NOT_IMPLEMENTED_MOTOR_TYPE = 0x0020, + ERROR_BRAKE_CURRENT_OUT_OF_RANGE = 0x0040, + ERROR_MODULATION_MAGNITUDE = 0x0080, + ERROR_BRAKE_DEADTIME_VIOLATION = 0x0100, + ERROR_UNEXPECTED_TIMER_CALLBACK = 0x0200 }; enum TimingLog_t { @@ -100,6 +103,7 @@ public: void update_current_controller_gains(); void DRV8301_setup(); bool check_DRV_fault(); + void set_error(Error_t error); bool do_checks(); void log_timing(TimingLog_t log_idx); float phase_current_from_adcval(uint32_t ADCValue); @@ -131,7 +135,7 @@ public: uint16_t timing_log_[TIMING_LOG_NUM_SLOTS] = { 0 }; // variables exposed on protocol - Error_t error_ = ERROR_NO_ERROR; + Error_t error_ = ERROR_NONE; // Do not write to this variable directly! // It is for exclusive use by the safety_critical_... functions. ArmedState_t armed_state_ = ARMED_STATE_DISARMED; @@ -204,7 +208,8 @@ public: make_protocol_property("phase_resistance", &config_.phase_resistance), make_protocol_property("direction", &config_.direction), make_protocol_property("motor_type", &config_.motor_type), - make_protocol_property("current_lim", &config_.current_lim) + make_protocol_property("current_lim", &config_.current_lim), + make_protocol_property("requested_current_range", &config_.requested_current_range) ) ); } diff --git a/Firmware/MotorControl/odrive_main.h b/Firmware/MotorControl/odrive_main.h index dbb08acc..af7bd3f3 100644 --- a/Firmware/MotorControl/odrive_main.h +++ b/Firmware/MotorControl/odrive_main.h @@ -7,6 +7,8 @@ extern "C" { // STM specific includes #include // Sets up the correct chip specifc defines required by arm_math +#include +#include #define ARM_MATH_CM4 // TODO: might change in future board versions #include @@ -23,11 +25,10 @@ extern "C" { //default timeout waiting for phase measurement signals #define PH_CURRENT_MEAS_TIMEOUT 2 // [ms] +//TODO clean this up static const float current_meas_period = CURRENT_MEAS_PERIOD; static const int current_meas_hz = CURRENT_MEAS_HZ; -extern float vbus_voltage; -extern bool brake_resistor_armed_; -extern const float elec_rad_per_enc; +// extern const float elec_rad_per_enc; extern uint32_t _reboot_cookie; extern bool user_config_loaded_; @@ -57,6 +58,8 @@ extern SystemStats_t system_stats_; // @brief general user configurable board configuration struct BoardConfig_t { bool enable_uart = true; + bool enable_i2c_instead_of_can = false; + bool enable_ascii_protocol_on_usb = true; float brake_resistance = 0.47f; // [ohm] float dc_bus_undervoltage_trip_level = 8.0f; //= 3*current_meas_hz) { - // trigger_ctr = 0; - - // //Change to sensorless units - // motor->vel_gain = 15.0f / 200.0f; - // motor->vel_setpoint = 800.0f * motor->encoder.motor_dir; - - // //Change mode - // motor->rotor_mode = ROTOR_MODE_SENSORLESS; - // } - - if (pos_estimate) *pos_estimate = pll_pos_; - if (vel_estimate) *vel_estimate = pll_vel_; - if (phase_output) *phase_output = phase_; return true; }; diff --git a/Firmware/MotorControl/sensorless_estimator.hpp b/Firmware/MotorControl/sensorless_estimator.hpp index 910bc05a..d8590d0e 100644 --- a/Firmware/MotorControl/sensorless_estimator.hpp +++ b/Firmware/MotorControl/sensorless_estimator.hpp @@ -5,12 +5,12 @@ class SensorlessEstimator { public: enum Error_t { ERROR_NONE = 0, - ERROR_NUMERICAL = 0x01, + ERROR_UNSTABLE_GAIN = 0x01, }; SensorlessEstimator(); - bool update(float* pos_estimate, float* vel_estimate, float* phase); + bool update(); Axis* axis_ = nullptr; // set by Axis constructor diff --git a/Firmware/README.md b/Firmware/README.md index ad315ac0..d101dce3 100644 --- a/Firmware/README.md +++ b/Firmware/README.md @@ -272,7 +272,7 @@ If you have an encoder with an index (Z) signal, you may avoid having to do the

The error nummber corresponds to the following: -0. `ERROR_NO_ERROR` +0. `ERROR_NONE` 1. `ERROR_PHASE_RESISTANCE_TIMING` 2. `ERROR_PHASE_RESISTANCE_MEASUREMENT_TIMEOUT` 3. `ERROR_PHASE_RESISTANCE_OUT_OF_RANGE` diff --git a/Firmware/Tupfile.lua b/Firmware/Tupfile.lua index ff95f0d1..11a56d45 100644 --- a/Firmware/Tupfile.lua +++ b/Firmware/Tupfile.lua @@ -43,8 +43,6 @@ if tup.getconfig("USB_PROTOCOL") == "native" or tup.getconfig("USB_PROTOCOL") == FLAGS += "-DUSB_PROTOCOL_NATIVE" elseif tup.getconfig("USB_PROTOCOL") == "native-stream" then FLAGS += "-DUSB_PROTOCOL_NATIVE_STREAM_BASED" -elseif tup.getconfig("USB_PROTOCOL") == "ascii" then - FLAGS += "-DUSB_PROTOCOL_ASCII" elseif tup.getconfig("USB_PROTOCOL") == "stdout" then FLAGS += "-DUSB_PROTOCOL_STDOUT" elseif tup.getconfig("USB_PROTOCOL") == "none" then @@ -163,6 +161,7 @@ build{ 'communication/protocol.cpp', 'communication/interface_uart.cpp', 'communication/interface_usb.cpp', + 'communication/interface_i2c.cpp', 'FreeRTOS-openocd.c' }, includes={ diff --git a/Firmware/communication/ascii_protocol.cpp b/Firmware/communication/ascii_protocol.cpp index 98f1cd02..78211f41 100644 --- a/Firmware/communication/ascii_protocol.cpp +++ b/Firmware/communication/ascii_protocol.cpp @@ -124,7 +124,6 @@ void ASCII_protocol_process_line(const uint8_t* buffer, size_t len, StreamSink& respond(response_channel, use_checksum, "invalid motor %u", motor_number); } else { axes[motor_number]->controller_.set_current_setpoint(current_setpoint); - respond(response_channel, use_checksum, "ok", motor_number); } } else if (cmd[0] == 'i'){ // Dump device info diff --git a/Firmware/communication/communication.cpp b/Firmware/communication/communication.cpp index 66f498df..0ddfb99f 100644 --- a/Firmware/communication/communication.cpp +++ b/Firmware/communication/communication.cpp @@ -5,6 +5,7 @@ #include "interface_usb.h" #include "interface_uart.h" +#include "interface_i2c.h" #include "odrive_main.h" #include "protocol.hpp" @@ -111,7 +112,7 @@ static inline auto make_obj_tree() { make_protocol_ro_property("fw_version_revision", &fw_version_revision), make_protocol_ro_property("fw_version_unreleased", &fw_version_unreleased), make_protocol_ro_property("user_config_loaded", const_cast(&user_config_loaded_)), - make_protocol_ro_property("brake_resistor_armed", &brake_resistor_armed_), + make_protocol_ro_property("brake_resistor_armed", &brake_resistor_armed), make_protocol_object("system_stats", make_protocol_ro_property("uptime", &system_stats_.uptime), make_protocol_ro_property("min_heap_space", &system_stats_.min_heap_space), @@ -126,12 +127,20 @@ static inline auto make_obj_tree() { make_protocol_ro_property("rx_cnt", &usb_stats_.rx_cnt), make_protocol_ro_property("tx_cnt", &usb_stats_.tx_cnt), make_protocol_ro_property("tx_overrun_cnt", &usb_stats_.tx_overrun_cnt) + ), + make_protocol_object("i2c", + make_protocol_ro_property("addr", &i2c_stats_.addr), + make_protocol_ro_property("addr_match_cnt", &i2c_stats_.addr_match_cnt), + make_protocol_ro_property("rx_cnt", &i2c_stats_.rx_cnt), + make_protocol_ro_property("error_cnt", &i2c_stats_.error_cnt) ) ), make_protocol_object("config", make_protocol_property("brake_resistance", &board_config.brake_resistance), // TODO: changing this currently requires a reboot - fix this make_protocol_property("enable_uart", &board_config.enable_uart), + make_protocol_property("enable_i2c_instead_of_can" , &board_config.enable_i2c_instead_of_can), // requires a reboot + make_protocol_property("enable_ascii_protocol_on_usb", &board_config.enable_ascii_protocol_on_usb), make_protocol_property("dc_bus_undervoltage_trip_level", &board_config.dc_bus_undervoltage_trip_level), make_protocol_property("dc_bus_overvoltage_trip_level", &board_config.dc_bus_overvoltage_trip_level) ), @@ -169,8 +178,11 @@ void communication_task(void * ctx) { auto endpoint_provider = EndpointProvider_from_MemberList(*tree_ptr); set_application_endpoints(&endpoint_provider); - serve_on_uart(); - serve_on_usb(); + start_uart_server(); + start_usb_server(); + if (board_config.enable_i2c_instead_of_can) { + start_i2c_server(); + } for (;;) { osDelay(1000); // nothing to do diff --git a/Firmware/communication/interface_i2c.cpp b/Firmware/communication/interface_i2c.cpp new file mode 100644 index 00000000..e5060572 --- /dev/null +++ b/Firmware/communication/interface_i2c.cpp @@ -0,0 +1,86 @@ + +#include "interface_i2c.h" +#include "protocol.hpp" + +#include + +#define I2C_RX_BUFFER_SIZE 128 +#define I2C_RX_BUFFER_PREAMBLE_SIZE 4 +#define I2C_TX_BUFFER_SIZE 128 + +I2CStats_t i2c_stats_ = {0}; + +static uint8_t i2c_rx_buffer[I2C_RX_BUFFER_PREAMBLE_SIZE + I2C_RX_BUFFER_SIZE]; +static uint8_t i2c_tx_buffer[I2C_TX_BUFFER_SIZE]; + +class I2CSender : public PacketSink { +public: + int process_packet(const uint8_t* buffer, size_t length) { + if (length >= 2 && (length - 2) <= sizeof(i2c_tx_buffer)) + memcpy(i2c_tx_buffer, buffer + 2, length - 2); + return 0; + } + size_t get_free_space() { return SIZE_MAX; } +} i2c1_packet_output; +BidirectionalPacketBasedChannel i2c1_channel(i2c1_packet_output); + +void start_i2c_server() { + // CAN H = SDA + // CAN L = SCL + HAL_I2C_EnableListen_IT(&hi2c1); +} + +void i2c_handle_packet(I2C_HandleTypeDef *hi2c) { + size_t received = sizeof(i2c_rx_buffer) - hi2c->XferCount; + if (received > I2C_RX_BUFFER_PREAMBLE_SIZE) { + i2c_stats_.rx_cnt++; + + write_le(0, i2c_rx_buffer); // hallucinate seq-no (not needed for I2C) + i2c_rx_buffer[2] = i2c_rx_buffer[4]; // endpoint-id = I2C register address + i2c_rx_buffer[3] = i2c_rx_buffer[5] | 0x80; // MSB must be 1 + size_t expected_bytes = (TX_BUF_SIZE - 2) < I2C_TX_BUFFER_SIZE ? (TX_BUF_SIZE - 2) : I2C_TX_BUFFER_SIZE; + write_le(expected_bytes, i2c_rx_buffer + 4); // hallucinate maximum number of expected response bytes + + i2c1_channel.process_packet(i2c_rx_buffer, received); + + // reset receive buffer + hi2c->pBuffPtr = I2C_RX_BUFFER_PREAMBLE_SIZE + i2c_rx_buffer; + hi2c->XferCount = sizeof(i2c_rx_buffer) - I2C_RX_BUFFER_PREAMBLE_SIZE; + } + + + if (hi2c->State == HAL_I2C_STATE_BUSY_RX_LISTEN) + hi2c->State = HAL_I2C_STATE_LISTEN; +} + + +void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c) { + i2c_handle_packet(hi2c); + // restart listening for address + HAL_I2C_EnableListen_IT(hi2c); +} + +void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode) { + i2c_stats_.addr_match_cnt += 1; + + i2c_handle_packet(hi2c); + + if (TransferDirection == I2C_DIRECTION_TRANSMIT) { + HAL_I2C_Slave_Sequential_Receive_IT(hi2c, + I2C_RX_BUFFER_PREAMBLE_SIZE + i2c_rx_buffer, + sizeof(i2c_rx_buffer) - I2C_RX_BUFFER_PREAMBLE_SIZE, I2C_FIRST_AND_LAST_FRAME); + } else { + HAL_I2C_Slave_Sequential_Transmit_IT(hi2c, i2c_tx_buffer, sizeof(i2c_tx_buffer), I2C_FIRST_AND_LAST_FRAME); + } +} + +void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) { + // ignore NACK errors + if (!(hi2c->ErrorCode & (~HAL_I2C_ERROR_AF))) + return; + + i2c_stats_.error_cnt += 1; + + // Continue listening + HAL_I2C_EnableListen_IT(hi2c); +} diff --git a/Firmware/communication/interface_i2c.h b/Firmware/communication/interface_i2c.h new file mode 100644 index 00000000..1bf89661 --- /dev/null +++ b/Firmware/communication/interface_i2c.h @@ -0,0 +1,25 @@ +#ifndef __INTERFACE_I2C_HPP +#define __INTERFACE_I2C_HPP + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct I2CStats_t { + uint8_t addr; + uint32_t addr_match_cnt; + uint32_t rx_cnt; + uint32_t error_cnt; +}; + +extern I2CStats_t i2c_stats_; + +void start_i2c_server(void); + +#ifdef __cplusplus +} +#endif + +#endif // __INTERFACE_I2C_HPP diff --git a/Firmware/communication/interface_uart.cpp b/Firmware/communication/interface_uart.cpp index 58b4f57d..432159b7 100644 --- a/Firmware/communication/interface_uart.cpp +++ b/Firmware/communication/interface_uart.cpp @@ -87,7 +87,7 @@ static void uart_server_thread(void * ctx) { }; } -void serve_on_uart() { +void start_uart_server() { // DMA is set up to recieve in a circular buffer forever. // We dont use interrupts to fetch the data, instead we periodically read // data out of the circular buffer into a parse buffer, controlled by a state machine @@ -95,7 +95,7 @@ void serve_on_uart() { dma_last_rcv_idx = UART_RX_BUFFER_SIZE - huart4.hdmarx->Instance->NDTR; // Start UART communication thread - osThreadDef(uart_server_thread_def, uart_server_thread, osPriorityNormal, 0, 512); + osThreadDef(uart_server_thread_def, uart_server_thread, osPriorityNormal, 0, 1024 /* the ascii protocol needs considerable stack space */); uart_thread = osThreadCreate(osThread(uart_server_thread_def), NULL); } diff --git a/Firmware/communication/interface_uart.h b/Firmware/communication/interface_uart.h index 8ad71c19..a7a291f0 100644 --- a/Firmware/communication/interface_uart.h +++ b/Firmware/communication/interface_uart.h @@ -12,7 +12,7 @@ extern "C" { extern osThreadId uart_thread; -void serve_on_uart(void); +void start_uart_server(void); #ifdef __cplusplus } diff --git a/Firmware/communication/interface_usb.cpp b/Firmware/communication/interface_usb.cpp index 5687e186..c0194ec5 100644 --- a/Firmware/communication/interface_usb.cpp +++ b/Firmware/communication/interface_usb.cpp @@ -12,8 +12,12 @@ #include #include +#include +#include "ascii_protocol.h" + static uint8_t* usb_buf; static uint32_t usb_len; +static uint8_t active_endpoint_pair; // FIXME: the stdlib doesn't know about CMSIS threads, so this is just a global variable static thread_local uint32_t deadline_ms = 0; @@ -39,12 +43,12 @@ public: // transmit packet uint8_t status = CDC_Transmit_FS( const_cast(buffer) /* casting this const away is safe because... - well... it's not actually. Stupid STM. */, length); + well... it's not actually. Stupid STM. */, length, active_endpoint_pair); if (status != USBD_OK) { osSemaphoreRelease(sem_usb_tx); return -1; } - usb_stats_.tx_cnt = 0; + usb_stats_.tx_cnt++; return 0; } } usb_packet_output; @@ -90,27 +94,30 @@ static void usb_server_thread(void * ctx) { if (sem_stat == osOK) { usb_stats_.rx_cnt++; deadline_ms = timeout_to_deadline(PROTOCOL_SERVER_TIMEOUT_MS); + if (active_endpoint_pair == CDC_OUT_EP && board_config.enable_ascii_protocol_on_usb) { + ASCII_protocol_parse_stream(usb_buf, usb_len, usb_stream_output); + } else { #if defined(USB_PROTOCOL_NATIVE) - usb_channel.process_packet(usb_buf, usb_len); + usb_channel.process_packet(usb_buf, usb_len); #elif defined(USB_PROTOCOL_NATIVE_STREAM_BASED) - usb_native_stream_input.process_bytes(usb_buf, usb_len); -#elif defined(USB_PROTOCOL_ASCII) - ASCII_protocol_parse_stream(usb_buf, usb_len, usb_stream_output); + usb_native_stream_input.process_bytes(usb_buf, usb_len); #endif - USBD_CDC_ReceivePacket(&hUsbDeviceFS); // Allow next packet + } + USBD_CDC_ReceivePacket(&hUsbDeviceFS, active_endpoint_pair); // Allow next packet } } } // Called from CDC_Receive_FS callback function, this allows the communication // thread to handle the incoming data -void usb_process_packet(uint8_t *buf, uint32_t len) { +void usb_process_packet(uint8_t *buf, uint32_t len, uint8_t endpoint_pair) { usb_buf = buf; usb_len = len; + active_endpoint_pair = endpoint_pair; osSemaphoreRelease(sem_usb_rx); } -void serve_on_usb() { +void start_usb_server() { // Start USB communication thread osThreadDef(usb_server_thread_def, usb_server_thread, osPriorityNormal, 0, 512); usb_thread = osThreadCreate(osThread(usb_server_thread_def), NULL); diff --git a/Firmware/communication/interface_usb.h b/Firmware/communication/interface_usb.h index 9038d822..f8b11ee0 100644 --- a/Firmware/communication/interface_usb.h +++ b/Firmware/communication/interface_usb.h @@ -21,8 +21,8 @@ typedef struct { extern USBStats_t usb_stats_; -void usb_process_packet(uint8_t *buf, uint32_t len); -void serve_on_usb(void); +void usb_process_packet(uint8_t *buf, uint32_t len, uint8_t endpoint_pair); +void start_usb_server(void); #ifdef __cplusplus } diff --git a/Firmware/communication/protocol.hpp b/Firmware/communication/protocol.hpp index f51fc2de..a1082575 100644 --- a/Firmware/communication/protocol.hpp +++ b/Firmware/communication/protocol.hpp @@ -552,7 +552,7 @@ ProtocolObject make_protocol_object(const char * name, TMembers&&.. // TODO: move to cpp_utils #define ENABLE_IF_SAME(a, b, type) \ - template typename std::enable_if_t::value, bool> + template typename std::enable_if_t::value, type> template class ProtocolProperty : public Endpoint { @@ -635,6 +635,26 @@ public: snprintf(buffer, length, "%lu", *property_); return true; } + ENABLE_IF_SAME(std::decay_t, int16_t, bool) + get_string_ex(char * buffer, size_t length, int) { + snprintf(buffer, length, "%hd", *property_); + return true; + } + ENABLE_IF_SAME(std::decay_t, uint16_t, bool) + get_string_ex(char * buffer, size_t length, int) { + snprintf(buffer, length, "%hu", *property_); + return true; + } + ENABLE_IF_SAME(std::decay_t, int8_t, bool) + get_string_ex(char * buffer, size_t length, int) { + snprintf(buffer, length, "%hhd", *property_); + return true; + } + ENABLE_IF_SAME(std::decay_t, uint8_t, bool) + get_string_ex(char * buffer, size_t length, int) { + snprintf(buffer, length, "%hhu", *property_); + return true; + } ENABLE_IF_SAME(std::decay_t, bool, bool) get_string_ex(char * buffer, size_t length, int) { buffer[0] = (*property_) ? '1' : '0'; @@ -647,6 +667,7 @@ public: bool get_string(char * buffer, size_t length) final { return get_string_ex(buffer, length, 0); } + ENABLE_IF_SAME(TProperty, float, bool) set_string_ex(char * buffer, size_t length, int) { return sscanf(buffer, "%f", property_) == 1; @@ -659,6 +680,22 @@ public: set_string_ex(char * buffer, size_t length, int) { return sscanf(buffer, "%lu", property_) == 1; } + ENABLE_IF_SAME(TProperty, int16_t, bool) + set_string_ex(char * buffer, size_t length, int) { + return sscanf(buffer, "%hd", property_) == 1; + } + ENABLE_IF_SAME(TProperty, uint16_t, bool) + set_string_ex(char * buffer, size_t length, int) { + return sscanf(buffer, "%hu", property_) == 1; + } + ENABLE_IF_SAME(TProperty, int8_t, bool) + set_string_ex(char * buffer, size_t length, int) { + return sscanf(buffer, "%hhd", property_) == 1; + } + ENABLE_IF_SAME(TProperty, uint8_t, bool) + set_string_ex(char * buffer, size_t length, int) { + return sscanf(buffer, "%hhu", property_) == 1; + } ENABLE_IF_SAME(TProperty, bool, bool) set_string_ex(char * buffer, size_t length, int) { int val; diff --git a/tools/odrive/code_generator.py b/tools/odrive/code_generator.py new file mode 100644 index 00000000..c14d6bcb --- /dev/null +++ b/tools/odrive/code_generator.py @@ -0,0 +1,69 @@ + +import jinja2 +import os +import json + +def get_flat_endpoint_list(json, prefix, id_offset): + flat_list = [] + for item in json: + item = item.copy() + if 'id' in item: + item['id'] -= id_offset + if 'type' in item: + if item['type'] in {'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64'}: + item['type'] += '_t' + is_property = True + elif item['type'] in {'bool', 'float'}: + is_property = True + elif item['type'] in {'function'}: + if len(item.get('arguments', [])) == 0 and len(item.get('inputs', [])) == 0 and len(item.get('outputs', [])) == 0: + item['type'] = 'void' + is_property = True + else: + is_property = False + else: + is_property = False + if is_property: + item['name'] = prefix + item['name'] + flat_list.append(item) + if 'members' in item: + flat_list = flat_list + get_flat_endpoint_list(item['members'], prefix + item['name'] + '.', id_offset) + return flat_list + +def generate_code(odrv, template_file, output_file): + json_data = odrv._json_data + json_crc = odrv._json_crc + + axis0_json = [item for item in json_data if item['name'].startswith("axis0")][0] + axis1_json = [item for item in json_data if item['name'].startswith("axis1")][0] + json_data = [item for item in json_data if not item['name'].startswith("axis")] + endpoints = get_flat_endpoint_list(json_data, '', 0) + per_axis_offset = axis1_json['members'][0]['id'] - axis0_json['members'][0]['id'] + axis_endpoints = get_flat_endpoint_list(axis0_json['members'], 'axis.', 0) + axis_endpoints_copy = get_flat_endpoint_list(axis1_json['members'], 'axis.', per_axis_offset) + if axis_endpoints != axis_endpoints_copy: + raise Exception("axis0 and axis1 don't look exactly equal") + + env = jinja2.Environment( + #loader = jinja2.FileSystemLoader("/Data/Projects/") + #trim_blocks=True, + #lstrip_blocks=True + ) + + # Expose helper functions to jinja template code + #env.filters["delimit"] = camel_case_to_words + + #import ipdb; ipdb.set_trace() + + # Load and render template + template = env.from_string(template_file.read()) + output = template.render( + json_crc=json_crc, + endpoints=endpoints, + per_axis_offset=per_axis_offset, + axis_endpoints=axis_endpoints, + output_name=os.path.basename(output_file.name) + ) + + # Output + output_file.write(output) diff --git a/tools/odrive/configuration.py b/tools/odrive/configuration.py new file mode 100644 index 00000000..8f297249 --- /dev/null +++ b/tools/odrive/configuration.py @@ -0,0 +1,82 @@ + +import json +import os +import tempfile +import odrive.remote_object +from odrive.utils import OperationAbortedException + +def get_dict(obj, is_config_object): + result = {} + for (k,v) in obj._remote_attributes.items(): + if isinstance(v, odrive.remote_object.RemoteProperty) and is_config_object: + result[k] = v.get_value() + elif isinstance(v, odrive.remote_object.RemoteObject): + sub_dict = get_dict(v, k == 'config') + if sub_dict != {}: + result[k] = sub_dict + return result + +def set_dict(obj, path, config_dict): + errors = [] + for (k,v) in config_dict.items(): + name = path + ("." if path != "" else "") + k + if not k in obj._remote_attributes: + errors.append("Could not restore {}: property not found on device".format(name)) + continue + remote_attribute = obj._remote_attributes[k] + if isinstance(remote_attribute, odrive.remote_object.RemoteObject): + errors += set_dict(remote_attribute, name, v) + else: + try: + remote_attribute.set_value(v) + except Exception as ex: + errors.append("Could not restore {}: {}".format(name, str(ex))) + return errors + +def get_temp_config_filename(device): + serial_number = odrive.utils.get_serial_number_str(device) + safe_serial_number = ''.join(filter(str.isalnum, serial_number)) + return os.path.join(tempfile.gettempdir(), 'odrive-config-{}.json'.format(safe_serial_number)) + +def backup_config(device, filename, logger): + """ + Exports the configuration of an ODrive to a JSON file. + If no file name is provided, the file is placed into a + temporary directory. + """ + + if filename is None: + filename = get_temp_config_filename(device) + + logger.info("Saving configuration to {}...".format(filename)) + + if os.path.exists(filename): + if not odrive.utils.yes_no_prompt("The file {} already exists. Do you want to override it?".format(filename), True): + raise OperationAbortedException() + + data = get_dict(device, False) + with open(filename, 'w') as file: + json.dump(data, file) + logger.info("Configuration saved.") + +def restore_config(device, filename, logger): + """ + Restores the configuration stored in a file + """ + + if filename is None: + filename = get_temp_config_filename(device) + + with open(filename) as file: + data = json.load(file) + + logger.info("Restoring configuration from {}...".format(filename)) + errors = odrive.configuration.set_dict(device, "", data) + + for error in errors: + logger.info(error) + if errors: + logger.warn("Some of the configuration could not be restored.") + + device.save_configuration() + logger.info("Configuration restored.") diff --git a/tools/odrive/dfu.py b/tools/odrive/dfu.py index 1efd4592..0f7b458d 100755 --- a/tools/odrive/dfu.py +++ b/tools/odrive/dfu.py @@ -9,11 +9,13 @@ import time import threading import platform import struct -import array -import fractions +import requests +import re +import io +import os import usb.core import odrive.discovery -from odrive.utils import Event +from odrive.utils import Event, OperationAbortedException from odrive.dfuse import * try: @@ -24,46 +26,17 @@ except: sys.exit(1) -SIZE_MULTIPLIERS = {' ': 1, 'K': 1024, 'M' : 1024*1024} -MAX_TRANSFER_SIZE = 2048 +def get_fw_version_string(fw_version): + if (fw_version[0], fw_version[1], fw_version[2]) == (0, 0, 0): + return "[unknown version]" + else: + return "v{}.{}.{}{}".format(fw_version[0], fw_version[1], fw_version[2], "-dev" if fw_version[3] else "") - -def get_device_sectors(dfudev): - """ - Returns a list of all sectors on the device. - Each sector is represented as a dictionary with the following keys: - - name: name of the associated memory region (e.g. "Internal Flash") - - alt: USB alternate setting associated with this memory region - - addr: Start address of the sector (e.g. 0x08004000 for the second flash sectors) - - baseaddr: Start address of the memory region associated with the sector - (e.g. 0x08000000 for all flash sectors) - - len: Number of bytes in the sector - """ - for name, alt in dfudev.alternates(): - # example for name: - # '@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg' - label, baseaddr, layout = name.split('/') - baseaddr = int(baseaddr, 0) # convert hex to decimal - addr = baseaddr - - for sector in layout.split(','): - repeat, size = map(int, sector[:-2].split('*')) - size *= SIZE_MULTIPLIERS[sector[-2].upper()] - mode = sector[-1] - - while repeat > 0: - # TODO: verify if the section is writable - yield { - 'name': label.strip().strip('@'), - 'alt': alt, - 'baseaddr': baseaddr, - 'addr': addr, - 'len': size, - 'mode': mode - } - - addr += size - repeat -= 1 +def get_hw_version_string(hw_version): + if hw_version == (0, 0, 0): + return "[unknown version]" + else: + return "v{}.{}{}".format(hw_version[0], hw_version[1], ("-" + str(hw_version[2]) + "V") if hw_version[2] > 0 else "") def populate_sectors(sectors, hexfile): """ @@ -88,66 +61,6 @@ def populate_sectors(sectors, hexfile): # TODO: verify if the section is writable yield (sector, hexfile.tobinarray(addr, addr + size - 1)) -def set_alternate_safe(dfudev, alt): - dfudev.set_alternate(alt) - if dfudev.get_state() == DfuState.DFU_ERROR: - dfudev.clear_status() - dfudev.wait_while_state(DfuState.DFU_ERROR) - -#def clear_error(dfudev) -def set_address_safe(dfudev, addr): - dfudev.set_address(addr) - status = dfudev.wait_while_state(DfuState.DFU_DOWNLOAD_BUSY) - if status[1] != DfuState.DFU_DOWNLOAD_IDLE: - raise RuntimeError("An error occured. Device Status: %r" % status) - # take device out of DFU_DOWNLOAD_SYNC and into DFU_IDLE - dfudev.abort() - status = dfudev.wait_while_state(DfuState.DFU_DOWNLOAD_SYNC) - if status[1] != DfuState.DFU_IDLE: - raise RuntimeError("An error occured. Device Status: %r" % status) - - -def erase(dfudev, sector): - set_alternate_safe(dfudev, sector['alt']) - dfudev.erase(sector['addr']) - status = dfudev.wait_while_state(DfuState.DFU_DOWNLOAD_BUSY, timeout=sector['len']/32) - if status[1] != DfuState.DFU_DOWNLOAD_IDLE: - raise RuntimeError("An error occured. Device Status: %r" % status) - -def flash(dfudev, sector, data): - set_alternate_safe(dfudev, sector['alt']) - set_address_safe(dfudev, sector['addr']) - - transfer_size = fractions.gcd(sector['len'], MAX_TRANSFER_SIZE) - - blocks = [data[i:i + transfer_size] for i in range(0, len(data), transfer_size)] - for blocknum, block in enumerate(blocks): - #print('write to {:08X} ({} bytes)'.format( - # sector['addr'] + blocknum * TRANSFER_SIZE, len(block))) - dfudev.write(blocknum, block) - status = dfudev.wait_while_state(DfuState.DFU_DOWNLOAD_BUSY) - if status[1] != DfuState.DFU_DOWNLOAD_IDLE: - raise RuntimeError("An error occured. Device Status: %r" % status) - -def read(dfudev, sector): - """ - Reads data from the specified sector - Returns: a byte array containing the data - """ - set_alternate_safe(dfudev, sector['alt']) - set_address_safe(dfudev, sector['addr']) - - transfer_size = fractions.gcd(sector['len'], MAX_TRANSFER_SIZE) - #blocknum_offset = int((sector['addr'] - sector['baseaddr']) / transfer_size) - - - data = array.array(u'B') - for blocknum in range(int(sector['len'] / transfer_size)): - #print('read at {:08X}'.format(sector['addr'] + blocknum * TRANSFER_SIZE)) - deviceBlock = dfudev.read(blocknum, transfer_size) - data.extend(deviceBlock) - dfudev.abort() # take device into DFU_IDLE - return data def get_first_mismatch_index(array1, array2): """ @@ -161,42 +74,132 @@ def get_first_mismatch_index(array1, array2): return pos return None - -def jump_to_application(dfudev, address): - set_address_safe(dfudev, address) - #dfudev.set_address(address) - #status = dfudev.wait_while_state(DfuState.DFU_DOWNLOAD_BUSY) - #if status[1] != DfuState.DFU_DOWNLOAD_IDLE: - # raise RuntimeError("An error occured. Device Status: {}".format(status[1])) - - dfudev.leave() - status = dfudev.wait_while_state(DfuState.DFU_MANIFEST_SYNC) - if status[1] != DfuState.DFU_MANIFEST: - raise RuntimeError("An error occured. Device Status: {}".format(status[1])) - - -def dump_otp(): +def dump_otp(dfudev): """ Dumps the contents of the one-time-programmable - memory. The OTP will be used in future versions of - this script to determine the board version. + memory for debugging purposes. + The OTP is used to determine the board version. """ # 512 Byte OTP - otp_sector = [s for s in sectors if s['name'] == 'OTP Memory' and s['addr'] == 0x1fff7800][0] - data = read(dfudev, otp_sector) + otp_sector = [s for s in dfudev.sectors if s['name'] == 'OTP Memory' and s['addr'] == 0x1fff7800][0] + data = dfudev.read_sector(otp_sector) print(' '.join('{:02X}'.format(x) for x in data)) # 16 lock bytes - otp_lock_sector = [s for s in sectors if s['name'] == 'OTP Memory' and s['addr'] == 0x1fff7A00][0] - data = read(dfudev, otp_lock_sector) + otp_lock_sector = [s for s in dfudev.sectors if s['name'] == 'OTP Memory' and s['addr'] == 0x1fff7A00][0] + data = dfudev.read_sector(otp_lock_sector) print(' '.join('{:02X}'.format(x) for x in data)) +class Firmware(): + def __init__(self): + self.fw_version = (0, 0, 0, True) + self.hw_version = (0, 0, 0) + + @staticmethod + def is_newer(a, b): + a_num = (a[0], a[1], a[2]) + b_num = (b[0], b[1], b[2]) + if a_num == (0, 0, 0) or b_num == (0, 0, 0): + return False # Cannot compare unknown versions + return a_num > b_num or (a_num == b_num and not a[3] and b[3]) + + def __gt__(self, other): + """ + Compares two firmware versions. If both versions are equal, the + prerelease version is considered older than the release version. + """ + if not isinstance(other, tuple): + other = other.fw_version + return Firmware.is_newer(self.fw_version, other) + + def __lt__(self, other): + """ + Compares two firmware versions. If both versions are equal, the + prerelease version is considered older than the release version. + """ + if not isinstance(other, tuple): + other = other.fw_version + return Firmware.is_newer(other, self.fw_version) + + def is_compatible(self, hw_version): + """ + Determines if this firmware is compatible + with the specified hardware version + """ + return self.hw_version == hw_version + +class FirmwareFromGithub(Firmware): + """ + Represents a firmware asset + """ + def __init__(self, release_json, asset_json): + Firmware.__init__(self) + if release_json['draft'] or release_json['prerelease']: + release_json['tag_name'] += "*" + self.fw_version = odrive.version.version_str_to_tuple(release_json['tag_name']) + + hw_version_regex = r'.*v([0-9]+).([0-9]+)(-(?P[0-9]+)V)?.hex' + hw_version_match = re.search(hw_version_regex, asset_json['name']) + self.hw_version = (int(hw_version_match[1]), + int(hw_version_match[2]), + int(hw_version_match.groupdict().get('voltage') or 0)) + self.github_asset_id = asset_json['id'] + self.hex = None + # no technical reason to fetch this - just interesting + self.download_count = asset_json['download_count'] + + def get_as_hex(self): + """ + Returns the content of the firmware in as a binary array in Intel Hex format + """ + if self.hex is None: + print("Downloading firmware {}...".format(get_fw_version_string(self.fw_version))) + response = requests.get('https://api.github.com/repos/madcowswe/ODrive/releases/assets/' + str(self.github_asset_id), + headers={'Accept': 'application/octet-stream'}) + if response.status_code != 200: + raise Exception("failed to download firmware") + self.hex = response.content + return io.StringIO(self.hex.decode('utf-8')) + +class FirmwareFromFile(Firmware): + def __init__(self, file): + Firmware.__init__(self) + self._file = file + def get_as_hex(self): + return self._file + +def get_all_github_firmwares(): + response = requests.get('https://api.github.com/repos/madcowswe/ODrive/releases') + if response.status_code != 200: + raise Exception("could not fetch releases") + response_json = response.json() + + for release_json in response_json: + for asset_json in release_json['assets']: + try: + if asset_json['name'].lower().endswith('.hex'): + fw = FirmwareFromGithub(release_json, asset_json) + yield fw + except Exception as ex: + print(ex) + +def get_newest_firmware(hw_version): + """ + Returns the newest available firmware for the specified hardware version + """ + firmwares = get_all_github_firmwares() + firmwares = filter(lambda fw: not fw.fw_version[3], firmwares) # ignore prereleases + firmwares = filter(lambda fw: fw.hw_version == hw_version, firmwares) + firmwares = list(firmwares) + firmwares.sort() + return firmwares[-1] if len(firmwares) else None + def show_deferred_message(message, cancellation_token): """ Shows a message after 10s, unless cancellation_token gets set. """ def show_message_thread(message, cancellation_token): - for i in range(1,10): + for _ in range(1,10): if cancellation_token.is_set(): return time.sleep(1) @@ -206,104 +209,157 @@ def show_deferred_message(message, cancellation_token): t.daemon = True t.start() -def put_odrive_into_dfu_mode(my_drive, cancellation_token): +def put_into_dfu_mode(device, cancellation_token): """ Puts the specified device into DFU mode """ - if not hasattr(my_drive, "enter_dfu_mode"): + if not hasattr(device, "enter_dfu_mode"): print("The firmware on device {} does not support DFU. You need to \n" "flash the firmware once using STLink (`make flash`), after that \n" "DFU with this script should work fine." - .format(my_drive.__channel__.usb_device.serial_number)) + .format(device.__channel__.usb_device.serial_number)) return - hw_version_major = my_drive.hw_version_major if hasattr(my_drive, 'hw_version_major') else 3 - hw_version_minor = my_drive.hw_version_minor if hasattr(my_drive, 'hw_version_minor') else 4 - if hw_version_major == 3 and hw_version_minor >= 5: - print("Putting device {} into DFU mode...".format(my_drive.__channel__.usb_device.serial_number)) - try: - my_drive.enter_dfu_mode() - except odrive.protocol.ChannelBrokenException: - pass # this is expected because the device reboots - if platform.system() == "Windows": - show_deferred_message("Still waiting for the device to reappear.\n" - "Use the Zadig utility to set the driver of 'STM32 BOOTLOADER' to libusb-win32.", - cancellation_token) - else: - print("Found device {}".format(my_drive.__channel__.usb_device.serial_number)) + hw_version_major = device.hw_version_major if hasattr(device, 'hw_version_major') else 3 + hw_version_minor = device.hw_version_minor if hasattr(device, 'hw_version_minor') else 4 + if hw_version_major == 3 and hw_version_minor < 5: print(" DFU mode is not supported on board version 3.4 or earlier.") print(" This is because entering DFU mode on such a device would") print(" break the brake resistor FETs under some circumstances.") + raise Exception("not supported") + + print("Putting device {} into DFU mode...".format(device.__channel__.usb_device.serial_number)) + try: + device.enter_dfu_mode() + except odrive.protocol.ChannelBrokenException: + pass # this is expected because the device reboots + if platform.system() == "Windows": + show_deferred_message("Still waiting for the device to reappear.\n" + "Use the Zadig utility to set the driver of 'STM32 BOOTLOADER' to libusb-win32.", + cancellation_token) -def launch_dfu(args, app_shutdown_token): +def find_device_in_dfu_mode(serial_number, cancellation_token): """ - Waits for a device that matches args.path and args.serial_number - and then upgrades the device's firmware. + Polls libusb until a device in DFU mode is found """ + while not cancellation_token.is_set(): + params = {} if serial_number == None else {'serial_number': serial_number} + stm_device = usb.core.find(idVendor=0x0483, idProduct=0xdf11, **params) + if stm_device != None: + return stm_device + time.sleep(1) + return None + +def update_device(device, firmware, logger, cancellation_token): + """ + Updates the specified device with the specified firmware. + The device passed to this function can either be in + normal mode or in DFU mode. + The firmware should be an instance of Firmware or None. + If firmware is None, the newest firmware for the device is + downloaded from GitHub releases. + """ + + if isinstance(device, usb.core.Device): + serial_number = device.serial_number + dfudev = DfuDevice(device) + if (logger._verbose): + logger.debug("OTP:") + dump_otp(dfudev) + + # Read hardware version from one-time-programmable memory + otp_sector = [s for s in dfudev.sectors if s['name'] == 'OTP Memory' and s['addr'] == 0x1fff7800][0] + otp_data = dfudev.read_sector(otp_sector) + if otp_data[0] == 0: + otp_data = otp_data[16:] + if otp_data[0] == 0xfe: + hw_version = (otp_data[3], otp_data[4], otp_data[5]) + else: + hw_version = (0, 0, 0) + else: + serial_number = device.__channel__.usb_device.serial_number + dfudev = None + + # Read hardware version as reported from firmware + hw_version_major = device.hw_version_major if hasattr(device, 'hw_version_major') else 0 + hw_version_minor = device.hw_version_minor if hasattr(device, 'hw_version_minor') else 0 + hw_version_variant = device.hw_version_variant if hasattr(device, 'hw_version_variant') else 0 + hw_version = (hw_version_major, hw_version_minor, hw_version_variant) + + fw_version_major = device.fw_version_major if hasattr(device, 'fw_version_major') else 0 + fw_version_minor = device.fw_version_minor if hasattr(device, 'fw_version_minor') else 0 + fw_version_revision = device.fw_version_revision if hasattr(device, 'fw_version_revision') else 0 + fw_version_prerelease = device.fw_version_prerelease if hasattr(device, 'fw_version_prerelease') else True + fw_version = (fw_version_major, fw_version_minor, fw_version_revision, fw_version_prerelease) + + print("Found ODrive {} ({}) with firmware {}{}".format( + serial_number, + get_hw_version_string(hw_version), + get_fw_version_string(fw_version), + " in DFU mode" if dfudev is not None else "")) + + if firmware is None: + if hw_version == (0, 0, 0): + if dfudev is None: + suggestion = 'You have to manually flash an up-to-date firmware to make automatic checks work. Run `odrivetool dfu --help` for more info.' + else: + suggestion = 'Run "make write_otp" to program the board version.' + raise Exception('Cannot check online for new firmware because the board version is unknown. ' + suggestion) + print("Checking online for newest firmware...", end='') + firmware = get_newest_firmware(hw_version) + if firmware is None: + raise Exception("could not find any firmware release for this board version") + print(" found {}".format(get_fw_version_string(firmware.fw_version))) + + if firmware < fw_version: + print("Warning: you are about to flash firmware {} which is older than the firmware on the device ({}).".format( + get_fw_version_string(firmware.fw_version), + get_fw_version_string(fw_version))) + if not odrive.utils.yes_no_prompt("Do you want to flash this firmware anyway?", True): + raise OperationAbortedException() # load hex file # TODO: Either use the elf format or pack a custom format with a manifest. # This way we can for instance verify the target board version and only - # have to publish one file for every board. - hexfile = IntelHex(args.file) + # have to publish one file for every board (instead of elf AND hex files). + hexfile = IntelHex(firmware.get_as_hex()) - if (args.verbose): - print("Contiguous segments in hex file:") - for start, end in hexfile.segments(): - print(" {:08X} to {:08X}".format(start, end - 1)) + logger.debug("Contiguous segments in hex file:") + for start, end in hexfile.segments(): + logger.debug(" {:08X} to {:08X}".format(start, end - 1)) - serial_number = args.serial_number + # Back up configuration + if dfudev is None: + did_backup_config = device.user_config_loaded if hasattr(device, 'user_config_loaded') else False + if did_backup_config: + odrive.configuration.backup_config(device, None, logger) + elif not odrive.utils.yes_no_prompt("The configuration cannot be backed up because the device is already in DFU mode. The configuration may be lost after updating. Do you want to continue anyway?", True): + raise OperationAbortedException() - find_odrive_cancellation_token = Event(app_shutdown_token) + # Put the device into DFU mode if it's not already in DFU mode + if dfudev is None: + put_into_dfu_mode(device, cancellation_token) + stm_device = find_device_in_dfu_mode(serial_number, cancellation_token) + dfudev = DfuDevice(stm_device) - print("Waiting for ODrive...") - - # Scan for ODrives not in DFU mode and put them into DFU mode once they appear - # We only scan on USB because DFU is only possible over USB - odrive.discovery.find_all(args.path, serial_number, - lambda dev: put_odrive_into_dfu_mode(dev, find_odrive_cancellation_token), - find_odrive_cancellation_token, app_shutdown_token) - - # Poll libUSB until a device in DFU mode is found - while not app_shutdown_token.is_set(): - params = {} if serial_number == None else {'serial_number': serial_number} - stm_device = usb.core.find(idVendor=0x0483, idProduct=0xdf11, **params) - if stm_device != None: - break - time.sleep(1) - find_odrive_cancellation_token.set() # we don't need this thread anymore - if app_shutdown_token.is_set(): - sys.exit(1) - print("Found device {} in DFU mode".format(stm_device.serial_number)) - - dfudev = DfuDevice(stm_device) - - sectors = list(get_device_sectors(dfudev)) - - if (args.verbose): - print("Sectors on device: ") - for sector in sectors: - print(" {:08X} to {:08X} ({})".format( - sector['addr'], - sector['addr'] + sector['len'] - 1, - sector['name'])) + logger.debug("Sectors on device: ") + for sector in dfudev.sectors: + logger.debug(" {:08X} to {:08X} ({})".format( + sector['addr'], + sector['addr'] + sector['len'] - 1, + sector['name'])) # fill sectors with data - touched_sectors = list(populate_sectors(sectors, hexfile)) + touched_sectors = list(populate_sectors(dfudev.sectors, hexfile)) - if (args.verbose): - print("The following sectors will be flashed: ") - for sector,_ in touched_sectors: - print(" {:08X} to {:08X}".format(sector['addr'], sector['addr'] + sector['len'] - 1)) - - if (args.verbose): - print("OTP:") - dump_otp() + logger.debug("The following sectors will be flashed: ") + for sector,_ in touched_sectors: + logger.debug(" {:08X} to {:08X}".format(sector['addr'], sector['addr'] + sector['len'] - 1)) # Erase try: for i, (sector, data) in enumerate(touched_sectors): print("Erasing... (sector {}/{}) \r".format(i, len(touched_sectors)), end='', flush=True) - erase(dfudev, sector) + dfudev.erase_sector(sector) print('Erasing... done \r', end='', flush=True) finally: print('', flush=True) @@ -312,7 +368,7 @@ def launch_dfu(args, app_shutdown_token): try: for i, (sector, data) in enumerate(touched_sectors): print("Flashing... (sector {}/{}) \r".format(i, len(touched_sectors)), end='', flush=True) - flash(dfudev, sector, data) + dfudev.write_sector(sector, data) print('Flashing... done \r', end='', flush=True) finally: print('', flush=True) @@ -321,7 +377,7 @@ def launch_dfu(args, app_shutdown_token): try: for i, (sector, expected_data) in enumerate(touched_sectors): print("Verifying... (sector {}/{}) \r".format(i, len(touched_sectors)), end='', flush=True) - observed_data = read(dfudev, sector) + observed_data = dfudev.read_sector(sector) mismatch_pos = get_first_mismatch_index(observed_data, expected_data) if not mismatch_pos is None: mismatch_pos -= mismatch_pos % 16 @@ -341,7 +397,47 @@ def launch_dfu(args, app_shutdown_token): # So for debugging you should comment this last part out. # Jump to application - jump_to_application(dfudev, 0x08000000) + dfudev.jump_to_application(0x08000000) + + logger.info("Waiting for the device to reappear...") + device = odrive.discovery.find_any("usb", serial_number, + cancellation_token, cancellation_token, timeout=30) + + if did_backup_config: + odrive.configuration.restore_config(device, None, logger) + os.remove(odrive.configuration.get_temp_config_filename(device)) + + logger.success("Device firmware update successful.") + +def launch_dfu(args, logger, cancellation_token): + """ + Waits for a device that matches args.path and args.serial_number + and then upgrades the device's firmware. + """ + + serial_number = args.serial_number + find_odrive_cancellation_token = Event(cancellation_token) + + logger.info("Waiting for ODrive...") + + devices = [None, None] + + # Start background thread to scan for ODrives in DFU mode + def find_device_in_dfu_mode_thread(): + devices[0] = find_device_in_dfu_mode(serial_number, find_odrive_cancellation_token) + find_odrive_cancellation_token.set() + threading.Thread(target=find_device_in_dfu_mode_thread).start() + + # Scan for ODrives not in DFU mode + # We only scan on USB because DFU is only implemented over USB + devices[1] = odrive.discovery.find_any("usb", serial_number, + find_odrive_cancellation_token, cancellation_token) + find_odrive_cancellation_token.set() + + device = devices[0] or devices[1] + firmware = FirmwareFromFile(args.file) if args.file else None + + update_device(device, firmware, logger, cancellation_token) diff --git a/tools/odrive/dfuse/DfuDevice.py b/tools/odrive/dfuse/DfuDevice.py index b9ca449c..e7158d3b 100644 --- a/tools/odrive/dfuse/DfuDevice.py +++ b/tools/odrive/dfuse/DfuDevice.py @@ -1,5 +1,8 @@ import usb.util import time +import fractions +import array +from odrive.dfuse.DfuState import DfuState DFU_REQUEST_SEND = 0x21 DFU_REQUEST_RECEIVE = 0xa1 @@ -12,6 +15,9 @@ DFU_CLRSTATUS = 0x04 DFU_GETSTATE = 0x05 DFU_ABORT = 0x06 +SIZE_MULTIPLIERS = {' ': 1, 'K': 1024, 'M' : 1024*1024} +MAX_TRANSFER_SIZE = 2048 + # Order is LSB first def address_to_4bytes(a): return [ a % 256, (a >> 8)%256, (a >> 16)%256, (a >> 24)%256 ] @@ -24,6 +30,7 @@ class DfuDevice: self.intf = None #self.dev.reset() self.cfg.set() + self.sectors = list(self.get_device_sectors()) def alternates(self): return [(usb.util.get_string(self.dev, intf.iInterface), intf) for intf in self.cfg] @@ -98,3 +105,115 @@ class DfuDevice: return status + ## High level functions ## + # by ODrive Robotics + + def get_device_sectors(self): + """ + Returns a list of all sectors on the device. + Each sector is represented as a dictionary with the following keys: + - name: name of the associated memory region (e.g. "Internal Flash") + - alt: USB alternate setting associated with this memory region + - addr: Start address of the sector (e.g. 0x08004000 for the second flash sectors) + - baseaddr: Start address of the memory region associated with the sector + (e.g. 0x08000000 for all flash sectors) + - len: Number of bytes in the sector + """ + for name, alt in self.alternates(): + # example for name: + # '@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg' + label, baseaddr, layout = name.split('/') + baseaddr = int(baseaddr, 0) # convert hex to decimal + addr = baseaddr + + for sector in layout.split(','): + repeat, size = map(int, sector[:-2].split('*')) + size *= SIZE_MULTIPLIERS[sector[-2].upper()] + mode = sector[-1] + + while repeat > 0: + # TODO: verify if the section is writable + yield { + 'name': label.strip().strip('@'), + 'alt': alt, + 'baseaddr': baseaddr, + 'addr': addr, + 'len': size, + 'mode': mode + } + + addr += size + repeat -= 1 + + def set_alternate_safe(self, alt): + self.set_alternate(alt) + if self.get_state() == DfuState.DFU_ERROR: + self.clear_status() + self.wait_while_state(DfuState.DFU_ERROR) + + #def clear_error(self) + def set_address_safe(self, addr): + self.set_address(addr) + status = self.wait_while_state(DfuState.DFU_DOWNLOAD_BUSY) + if status[1] != DfuState.DFU_DOWNLOAD_IDLE: + raise RuntimeError("An error occured. Device Status: %r" % status) + # take device out of DFU_DOWNLOAD_SYNC and into DFU_IDLE + self.abort() + status = self.wait_while_state(DfuState.DFU_DOWNLOAD_SYNC) + if status[1] != DfuState.DFU_IDLE: + raise RuntimeError("An error occured. Device Status: %r" % status) + + + def erase_sector(self, sector): + self.set_alternate_safe(sector['alt']) + self.erase(sector['addr']) + status = self.wait_while_state(DfuState.DFU_DOWNLOAD_BUSY, timeout=sector['len']/32) + if status[1] != DfuState.DFU_DOWNLOAD_IDLE: + raise RuntimeError("An error occured. Device Status: %r" % status) + + def write_sector(self, sector, data): + self.set_alternate_safe(sector['alt']) + self.set_address_safe(sector['addr']) + + transfer_size = fractions.gcd(sector['len'], MAX_TRANSFER_SIZE) + + blocks = [data[i:i + transfer_size] for i in range(0, len(data), transfer_size)] + for blocknum, block in enumerate(blocks): + #print('write to {:08X} ({} bytes)'.format( + # sector['addr'] + blocknum * TRANSFER_SIZE, len(block))) + self.write(blocknum, block) + status = self.wait_while_state(DfuState.DFU_DOWNLOAD_BUSY) + if status[1] != DfuState.DFU_DOWNLOAD_IDLE: + raise RuntimeError("An error occured. Device Status: %r" % status) + + def read_sector(self, sector): + """ + Reads data from the specified sector + Returns: a byte array containing the data + """ + self.set_alternate_safe(sector['alt']) + self.set_address_safe(sector['addr']) + + transfer_size = fractions.gcd(sector['len'], MAX_TRANSFER_SIZE) + #blocknum_offset = int((sector['addr'] - sector['baseaddr']) / transfer_size) + + + data = array.array(u'B') + for blocknum in range(int(sector['len'] / transfer_size)): + #print('read at {:08X}'.format(sector['addr'] + blocknum * TRANSFER_SIZE)) + deviceBlock = self.read(blocknum, transfer_size) + data.extend(deviceBlock) + self.abort() # take device into DFU_IDLE + return data + + def jump_to_application(self, address): + self.set_address_safe(address) + #self.set_address(address) + #status = self.wait_while_state(DfuState.DFU_DOWNLOAD_BUSY) + #if status[1] != DfuState.DFU_DOWNLOAD_IDLE: + # raise RuntimeError("An error occured. Device Status: {}".format(status[1])) + + self.leave() + status = self.wait_while_state(DfuState.DFU_MANIFEST_SYNC) + if status[1] != DfuState.DFU_MANIFEST: + raise RuntimeError("An error occured. Device Status: {}".format(status[1])) diff --git a/tools/odrive/discovery.py b/tools/odrive/discovery.py index a6536638..d05d8f98 100644 --- a/tools/odrive/discovery.py +++ b/tools/odrive/discovery.py @@ -53,7 +53,7 @@ def find_all(path, serial_number, except UnicodeDecodeError: printer("device responded on endpoint 0 with something that is not ASCII") return - printer("JSON: " + json_string) + printer("JSON: " + json_string.replace('{"name"', '\n{"name"')) printer("JSON checksum: 0x{:02X} 0x{:02X}".format(json_crc16 & 0xff, (json_crc16 >> 8) & 0xff)) try: json_data = json.loads(json_string) @@ -62,7 +62,11 @@ def find_all(path, serial_number, return json_data = {"name": "odrive", "members": json_data} obj = odrive.remote_object.RemoteObject(json_data, None, channel, printer) - device_serial_number = format(obj.serial_number, 'x').upper() if hasattr(obj, 'serial_number') else "[unknown serial number]" + + obj.__dict__['_json_data'] = json_data['members'] + obj.__dict__['_json_crc'] = json_crc16 + + device_serial_number = odrive.utils.get_serial_number_str(obj) if serial_number != None and device_serial_number != serial_number: printer("Ignoring device with serial number {}".format(device_serial_number)) return diff --git a/tools/odrive/enums.py b/tools/odrive/enums.py index 52b1e610..f5369007 100644 --- a/tools/odrive/enums.py +++ b/tools/odrive/enums.py @@ -11,7 +11,7 @@ AXIS_STATE_ENCODER_INDEX_SEARCH = 6 AXIS_STATE_ENCODER_OFFSET_CALIBRATION = 7 AXIS_STATE_CLOSED_LOOP_CONTROL = 8 -AXIS_ERROR_NO_ERROR = 0 +AXIS_ERROR_NONE = 0 AXIS_ERROR_INVALID_STATE = 1 #AXIS_ERROR_DC_BUS_UNDER_VOLTAGE = 2 #AXIS_ERROR_DC_BUS_OVER_VOLTAGE = 3 @@ -27,7 +27,7 @@ MOTOR_TYPE_HIGH_CURRENT = 0 #MOTOR_TYPE_LOW_CURRENT = 1 MOTOR_TYPE_GIMBAL = 2 -CTRL_MODE_VOLTAGE_CONTROL = 0, -CTRL_MODE_CURRENT_CONTROL = 1, -CTRL_MODE_VELOCITY_CONTROL = 2, +CTRL_MODE_VOLTAGE_CONTROL = 0 +CTRL_MODE_CURRENT_CONTROL = 1 +CTRL_MODE_VELOCITY_CONTROL = 2 CTRL_MODE_POSITION_CONTROL = 3 diff --git a/tools/odrive/shell.py b/tools/odrive/shell.py index ef072010..7fc3e5ad 100644 --- a/tools/odrive/shell.py +++ b/tools/odrive/shell.py @@ -52,7 +52,7 @@ def did_discover_device(odrive, logger, app_shutdown_token): # Publish new ODrive to interactive console interactive_variables[interactive_name] = odrive globals()[interactive_name] = odrive # Add to globals so tab complete works - logger.info("{} to ODrive {:012X} as {}".format(verb, serial_number, interactive_name)) + logger.notify("{} to ODrive {:012X} as {}".format(verb, serial_number, interactive_name)) # Subscribe to disappearance of the device odrive.__channel__._channel_broken.subscribe(lambda: did_lose_device(interactive_name, logger, app_shutdown_token)) diff --git a/tools/odrive/tests.py b/tools/odrive/tests.py index 43ef182b..0fb64cbb 100644 --- a/tools/odrive/tests.py +++ b/tools/odrive/tests.py @@ -51,12 +51,22 @@ class AxisTestContext(): self.odrv_ctx = odrv_ctx def test_assert_eq(observed, expected, range=None, accuracy=None): - if range is None and accuracy is None and observed != expected: - raise TestFailed("value mismatch: expected {} but observed {}".format(expected, observed)) - if not range is None and ((observed < expected - range) or (observed > expected + range)): - raise TestFailed("value out of range: expected {}+-{} but observed {}".format(expected, range, observed)) - elif not accuracy is None and ((observed < expected * (1 - accuracy)) or (observed > expected * (1 + accuracy))): - raise TestFailed("value out of range: expected {}+-{}% but observed {}".format(expected, accuracy*100.0, observed)) + sign = lambda x: 1 if x >= 0 else -1 + + # Comparision with absolute range + if not range is None: + if (observed < expected - range) or (observed > expected + range): + raise TestFailed("value out of range: expected {}+-{} but observed {}".format(expected, range, observed)) + + # Comparision with relative range + elif not accuracy is None: + if sign(observed) != sign(expected) or (abs(observed) < abs(expected) * (1 - accuracy)) or (abs(observed) > abs(expected) * (1 + accuracy)): + raise TestFailed("value out of range: expected {}+-{}% but observed {}".format(expected, accuracy*100.0, observed)) + + # Exact comparision + else: + if observed != expected: + raise TestFailed("value mismatch: expected {} but observed {}".format(expected, observed)) def get_errors(axis_ctx: AxisTestContext): errors = [] @@ -111,7 +121,7 @@ def request_state(axis_ctx: AxisTestContext, state, expect_success=True): else: test_assert_eq(axis_ctx.handle.current_state, AXIS_STATE_IDLE) test_assert_eq(axis_ctx.handle.error, AXIS_ERROR_INVALID_STATE) - axis_ctx.handle.error = AXIS_ERROR_NO_ERROR # reset error + axis_ctx.handle.error = AXIS_ERROR_NONE # reset error def set_limits(axis_ctx: AxisTestContext, logger, vel_limit=20000, current_limit=10): """ @@ -154,6 +164,9 @@ def get_max_rpm(axis_ctx: AxisTestContext): rated_rpm = min(base_speed_rpm, axis_ctx.yaml['encoder-max-rpm']) return rated_rpm +def get_sensorless_vel(axis_ctx: AxisTestContext, vel): + return vel * 2 * math.pi / axis_ctx.yaml['encoder-cpr'] * axis_ctx.yaml['motor-pole-pairs'] + class ODriveTest(ABC): """ Tests inheriting from this class get full ownership of the ODrive @@ -669,3 +682,98 @@ class TestVelCtrlVsPosCtrl(DualAxisTest): #init_pos = axis1_ctx.handle.encoder.pos_estimate #axis1_ctx.handle.controller.set_pos_setpoint(init_pos + 100000, 0, 0) #request_state(axis1_ctx, AXIS_STATE_CLOSED_LOOP_CONTROL) + + +# ASCII protocol helper functions +def gcode_calc_checksum(data): + from functools import reduce + return reduce(lambda a, b: a ^ b, data) +def gcode_append_checksum(data): + return data + b'*' + str(gcode_calc_checksum(data)).encode('ascii') +def get_lines(port): + buf = port.get_bytes(512, time.monotonic() + 0.2) + return [line.rstrip(b'\r') for line in buf.split(b'\n') if line.rstrip(b'\r')] + +class TestAsciiProtocol(ODriveTest): + def run_test(self, odrv_ctx: ODriveTestContext, logger): + import odrive.serial_transport + port = odrive.serial_transport.SerialStreamTransport(odrv_ctx.yaml['uart'], 115200) + + # send garbage to throw the device off track + port.process_bytes(b"garbage\r\n\r\0trash\n") + port.process_bytes(b"\n") # start a new clean line + get_lines(port) # flush RX buffer + + # info command without checksum + port.process_bytes(b"i\n") + # check if it reports the serial number (among other things) + lines = get_lines(port) + expected_line = ('Serial number: ' + odrv_ctx.yaml['serial-number']).encode('ascii') + if not expected_line in lines: + raise Exception("expected {} in ASCII protocol response but got {}".format(expected_line, str(lines))) + + # info command with checksum + port.process_bytes(gcode_append_checksum(b"i") + b" ; a useless comment\n") + # check if it reports the serial number with checksum (among other things) + lines = get_lines(port) + expected_line = gcode_append_checksum(('Serial number: ' + odrv_ctx.yaml['serial-number']).encode('ascii')) + if not expected_line in lines: + raise Exception("expected {} in ASCII protocol response but got {}".format(expected_line, str(lines))) + + port.process_bytes(b"p 0 2000 -10 0.002\n") + time.sleep(0.01) # 1ms is too short, 2ms usually works, 10ms for good measure + test_assert_eq(odrv_ctx.handle.axis0.controller.pos_setpoint, 2000, accuracy=0.001) + test_assert_eq(odrv_ctx.handle.axis0.controller.vel_setpoint, -10, accuracy=0.001) + test_assert_eq(odrv_ctx.handle.axis0.controller.current_setpoint, 0.002, accuracy=0.001) + + port.process_bytes(b"v 1 -21.1 0.32\n") + time.sleep(0.01) + test_assert_eq(odrv_ctx.handle.axis1.controller.vel_setpoint, -21.1, accuracy=0.001) + test_assert_eq(odrv_ctx.handle.axis1.controller.current_setpoint, 0.32, accuracy=0.001) + + port.process_bytes(b"c 0 0.1\n") + time.sleep(0.01) + test_assert_eq(odrv_ctx.handle.axis0.controller.current_setpoint, 0.1, accuracy=0.001) + + # write arbitrary parameter + port.process_bytes(b"w axis0.controller.pos_setpoint -123.456 ; comment\n") + time.sleep(0.01) + test_assert_eq(odrv_ctx.handle.axis0.controller.pos_setpoint, -123.456, accuracy=0.001) + + port.process_bytes(b"r axis0.controller.pos_setpoint\n") + lines = get_lines(port) + expected_line = b'-123.4560' + if lines != [expected_line]: + raise Exception("expected {} in ASCII protocol response but got {}".format(expected_line, str(lines))) + + # read/write enums + port.process_bytes(b"r axis0.error\n") + lines = get_lines(port) + expected_line = b'0' + if lines != [expected_line]: + raise Exception("expected {} in ASCII protocol response but got {}".format(expected_line, str(lines))) + + test_assert_eq(odrv_ctx.axes[0].handle.current_state, AXIS_STATE_CLOSED_LOOP_CONTROL) + port.process_bytes(b"w axis0.requested_state {}\n".format(AXIS_STATE_IDLE)) + time.sleep(0.01) + test_assert_eq(odrv_ctx.axes[0].handle.current_state, AXIS_STATE_IDLE) + + # disable axes + odrv_ctx.handle.axis0.controller.set_pos_setpoint(0, 0, 0) + odrv_ctx.handle.axis1.controller.set_pos_setpoint(0, 0, 0) + request_state(odrv_ctx.axes[0], AXIS_STATE_IDLE) + request_state(odrv_ctx.axes[1], AXIS_STATE_IDLE) + + +class TestSensorlessControl(AxisTest): + def run_test(self, axis_ctx: AxisTestContext, logger): + odrv0.axis0.controller.config.vel_gain = 5 / get_sensorless_vel(axis_ctx, 10000) + odrv0.axis0.controller.config.vel_integrator_gain = 10 / get_sensorless_vel(axis_ctx, 10000) + target_vel = get_sensorless_vel(axis_ctx, 20000) + axis_ctx.handle.controller.set_vel_setpoint(target_vel, 0) + request_state(axis_ctx, AXIS_STATE_SENSORLESS_CONTROL) + # wait for spinup + time.sleep(2) + test_assert_eq(odrv0.axis0.encoder.pll_vel, target_vel, range=2000) + + request_state(axis_ctx, AXIS_STATE_IDLE) diff --git a/tools/odrive/usbbulk_transport.py b/tools/odrive/usbbulk_transport.py index eefc33e8..6d7b5cff 100644 --- a/tools/odrive/usbbulk_transport.py +++ b/tools/odrive/usbbulk_transport.py @@ -46,20 +46,30 @@ class USBBulkTransport(odrive.protocol.PacketSource, odrive.protocol.PacketSink) if platform.system() != 'Windows': self.dev.reset() - interface_number = 1 + #self.dev.set_configuration() # no args: set first configuration + + # Find the best interface + self.cfg = self.dev.get_active_configuration() + custom_interfaces = [i for i in self.cfg.interfaces() if i.bInterfaceClass == 0x00 and i.bInterfaceSubClass == 0x01] + cdc_interfaces = [i for i in self.cfg.interfaces() if i.bInterfaceClass == 0x0a and i.bInterfaceSubClass == 0x00] + all_compatible_interfaces = custom_interfaces + cdc_interfaces + if len(all_compatible_interfaces) == 0: + raise Exception("the device has no compatible interfaces") + self.intf = all_compatible_interfaces[0] + + # Try to detach kernel driver from interface + #interface_number = 1 try: - if self.dev.is_kernel_driver_active(interface_number): - self.dev.detach_kernel_driver(interface_number) + if self.dev.is_kernel_driver_active(self.intf.bInterfaceNumber): + self.dev.detach_kernel_driver(self.intf.bInterfaceNumber) self._printer("Detached Kernel Driver") + else: + self._printer("Kernel Driver was not attached") except NotImplementedError: pass #is_kernel_driver_active not implemented on Windows - self.dev.set_configuration() # no args: set first configuration - self.cfg = self.dev.get_active_configuration() - self.intf = self.cfg[(1,0)] # this implicitly claims the interface - # write endpoint + # find write endpoint (first OUT endpoint) self.epw = usb.util.find_descriptor(self.intf, - # match the first OUT endpoint custom_match = \ lambda e: \ usb.util.endpoint_direction(e.bEndpointAddress) == \ @@ -67,9 +77,8 @@ class USBBulkTransport(odrive.protocol.PacketSource, odrive.protocol.PacketSink) ) assert self.epw is not None self._printer("EndpointAddress for writing {}".format(self.epw.bEndpointAddress)) - # read endpoint + # find read endpoint (first IN endpoint) self.epr = usb.util.find_descriptor(self.intf, - # match the first IN endpoint custom_match = \ lambda e: \ usb.util.endpoint_direction(e.bEndpointAddress) == \ @@ -154,15 +163,18 @@ def discover_channels(path, serial_number, callback, cancellation_token, channel known_devices = [] def device_matcher(device): #print(" test {:04X}:{:04X}".format(device.idVendor, device.idProduct)) - if (device.bus, device.address) in known_devices: - return False - if bus != None and device.bus != bus: - return False - if address != None and device.address != address: - return False - if serial_number != None and device.serial_number != serial_number: - return False - if (device.idVendor, device.idProduct) not in ODRIVE_VID_PID_PAIRS: + try: + if (device.bus, device.address) in known_devices: + return False + if bus != None and device.bus != bus: + return False + if address != None and device.address != address: + return False + if serial_number != None and device.serial_number != serial_number: + return False + if (device.idVendor, device.idProduct) not in ODRIVE_VID_PID_PAIRS: + return False + except: return False return True diff --git a/tools/odrive/utils.py b/tools/odrive/utils.py index 050d4110..d73cbba2 100755 --- a/tools/odrive/utils.py +++ b/tools/odrive/utils.py @@ -25,6 +25,9 @@ data_rate = 100 plot_rate = 10 num_samples = 1000 +class OperationAbortedException(Exception): + pass + def start_liveplotter(get_var_callback): """ Starts a liveplotter. @@ -157,6 +160,11 @@ def setup_udev_rules(logger): subprocess.run(["udevadm", "trigger"], check=True) logger.info('udev rules configured successfully') +def get_serial_number_str(device): + if hasattr(device, 'serial_number'): + return format(device.serial_number, 'x').upper() + else: + return "[unknown serial number]" ## Exceptions ## @@ -357,9 +365,30 @@ class Logger(): def success(self, text): self.print_colored(self._prefix + text, Logger.COLOR_GREEN) def info(self, text): + self.print_colored(self._prefix + text, Logger.COLOR_DEFAULT) + def notify(self, text): self.print_colored(self._prefix + text, Logger.COLOR_CYAN) def warn(self, text): self.print_colored(self._prefix + text, Logger.COLOR_YELLOW) def error(self, text): # TODO: write to stderr self.print_colored(self._prefix + text, Logger.COLOR_RED) + +def yes_no_prompt(question, default=None): + if default is None: + question += " [y/n] " + elif default == True: + question += " [Y/n] " + elif default == False: + question += " [y/N] " + + while True: + print(question, end='') + + choice = input().lower() + if choice in {'yes', 'y'}: + return True + elif choice in {'no', 'n'}: + return False + elif choice == '' and default is not None: + return default diff --git a/tools/odrive/version.py b/tools/odrive/version.py index 68bad7d0..b0b43035 100644 --- a/tools/odrive/version.py +++ b/tools/odrive/version.py @@ -4,6 +4,20 @@ import subprocess import os import sys +def version_str_to_tuple(version_string): + """ + Converts a version string to a tuple of the form + (major, minor, revision, prerelease) + + Example: "fw-v0.3.6-23" => (0, 3, 6, True) + """ + regex=r'.*v([0-9a-zA-Z]+).([0-9a-zA-Z]+).([0-9a-zA-Z]+)(.*)' + return (int(re.sub(regex, r"\1", version_string)), + int(re.sub(regex, r"\2", version_string)), + int(re.sub(regex, r"\3", version_string)), + (re.sub(regex, r"\4", version_string) != "")) + + def get_version_from_git(): script_dir = os.path.dirname(os.path.realpath(__file__)) try: @@ -12,19 +26,15 @@ def get_version_from_git(): cwd=script_dir) git_tag = git_tag.decode(sys.stdout.encoding).rstrip('\n') - regex=r'.*v([0-9a-zA-Z]).([0-9a-zA-Z]).([0-9a-zA-Z])(.*)' - package_version_major = int(re.sub(regex, r"\1", git_tag)) - package_version_minor = int(re.sub(regex, r"\2", git_tag)) - package_version_revision = int(re.sub(regex, r"\3", git_tag)) - package_version_unreleased = (re.sub(regex, r"\4", git_tag) != "") + (major, minor, revision, is_prerelease) = version_str_to_tuple(git_tag) - if package_version_unreleased: - package_version_revision += 1 + if is_prerelease: + revision += 1 + return git_tag, major, minor, revision, is_prerelease except Exception as ex: print(ex) return "[unknown version]", 0, 0, 0, 1 - return git_tag, package_version_major, package_version_minor, package_version_revision, package_version_unreleased def get_version_str(git_only=False): """ diff --git a/tools/odrive_header_template.h.in b/tools/odrive_header_template.h.in new file mode 100644 index 00000000..8a7befd1 --- /dev/null +++ b/tools/odrive_header_template.h.in @@ -0,0 +1,46 @@ +/* +* This file was autogenerated using the "odrivetool generate-code" feature. +* +* The file matches a specific firmware version. If you add/remove/rename any +* properties exposed by the ODrive, this file needs to be regenerated, otherwise +* the ODrive will ignore all commands. +*/ + +#ifndef __ODRIVE_ENDPOINTS_HPP +#define __ODRIVE_ENDPOINTS_HPP +{% macro enum_name(endpoint) %}{{ endpoint.name | replace('.', '__') | upper }}{% endmacro %} + +namespace odrive { + +static constexpr const uint16_t json_crc = 0x{{ "%0x" | format(json_crc) }}; + +static constexpr const uint16_t per_axis_offset = {{ per_axis_offset }}; + +enum { {% for endpoint in endpoints %} + {{enum_name(endpoint)}} = {{endpoint.id}}, +{%- endfor %} + + // Per-Axis endpoints (to be used with read_axis_property and write_axis_property) +{%- for endpoint in axis_endpoints %} + {{enum_name(endpoint)}} = {{endpoint.id}}, +{%- endfor %} +}; + +template +struct endpoint_type; + +{% for endpoint in endpoints -%} +template<> struct endpoint_type<{{enum_name(endpoint)}}> { typedef {{endpoint.type}} type; }; +{% endfor %} + +// Per-axis endpoints +{% for endpoint in axis_endpoints -%} +template<> struct endpoint_type<{{enum_name(endpoint)}}> { typedef {{endpoint.type}} type; }; +{% endfor %} + +template +using endpoint_type_t = typename endpoint_type::type; + +} + +#endif // __ODRIVE_ENDPOINTS_HPP diff --git a/tools/odrivetool b/tools/odrivetool index 901ebde3..2e784dc7 100755 --- a/tools/odrivetool +++ b/tools/odrivetool @@ -6,8 +6,10 @@ ODrive command line utility from __future__ import print_function import sys import argparse +import os import odrive.discovery -from odrive.utils import Logger, Event +from odrive.utils import Logger, Event, OperationAbortedException +from odrive.configuration import * # Flush stdout by default # Source: @@ -19,6 +21,7 @@ def print(*args, **kwargs): file = kwargs.get('file', sys.stdout) file.flush() if file is not None else sys.stdout.flush() +script_path=os.path.dirname(os.path.realpath(__file__)) ## Parse arguments ## parser = argparse.ArgumentParser(description='ODrive command line utility\n' @@ -33,8 +36,33 @@ shell_parser.add_argument("--no-ipython", action="store_true", "instead of the IPython shell, " "even if IPython is installed.") -dfu_parser = subparsers.add_parser('dfu', help="Upgrade the ODrive device firmware") -dfu_parser.add_argument('file', metavar='HEX', help='The .hex file to be flashed. Make sure your firmware board version matches the actual board version.') +dfu_parser = subparsers.add_parser('dfu', help="Upgrade the ODrive device firmware." + "If no serial number is specified, the first ODrive that is found is updated") +dfu_parser.add_argument('file', metavar='HEX', nargs='?', + help='The .hex file to be flashed. Make sure target board version ' + 'of the firmware file matches the actual board version. ' + 'You can download the latest release manually from ' + 'https://github.com/madcowswe/ODrive/releases. ' + 'If no file is provided, the script automatically downloads ' + 'the latest firmware.') + + +dfu_parser = subparsers.add_parser('backup-config', help="Saves the configuration of the ODrive to a JSON file") +dfu_parser.add_argument('file', nargs='?', + help="Path to the file where to store the data. " + "If no path is provided, the configuration is stored in {}.".format(tempfile.gettempdir())) + +dfu_parser = subparsers.add_parser('restore-config', help="Restores the configuration of the ODrive from a JSON file") +dfu_parser.add_argument('file', nargs='?', + help="Path to the file that contains the configuration data. " + "If no path is provided, the configuration is loaded from {}.".format(tempfile.gettempdir())) + +code_generator_parser = subparsers.add_parser('generate-code', help="Process a jinja2 template, passing the ODrive's JSON data as data input") +code_generator_parser.add_argument("-t", "--template", type=argparse.FileType('r'), + help="the code template") +code_generator_parser.add_argument("-o", "--output", type=argparse.FileType('w'), default='-', + help="path of the generated output") +code_generator_parser.set_defaults(template = os.path.join(script_path, 'odrive_header_template.h.in')) subparsers.add_parser('liveplotter', help="Upgrade the ODrive's Firmware") subparsers.add_parser('drv-status', help="Show status of the on-board DRV8301 chips (for debugging only)") @@ -110,12 +138,14 @@ try: elif args.command == 'dfu': print_version() import odrive.dfu - odrive.dfu.launch_dfu(args, app_shutdown_token) + odrive.dfu.launch_dfu(args, logger, app_shutdown_token) elif args.command == 'liveplotter': from odrive.utils import start_liveplotter print("Waiting for ODrive...") - my_odrive = odrive.discovery.find_any(path=args.path, serial_number=args.serial_number) + my_odrive = odrive.discovery.find_any(path=args.path, serial_number=args.serial_number, + search_cancellation_token=app_shutdown_token, + channel_termination_token=app_shutdown_token) # If you want to plot different values, change them here. # You can plot any number of values concurrently. @@ -125,22 +155,50 @@ try: elif args.command == 'drv-status': from odrive.utils import print_drv_regs print("Waiting for ODrive...") - my_odrive = odrive.discovery.find_any(path=args.path, serial_number=args.serial_number) + my_odrive = odrive.discovery.find_any(path=args.path, serial_number=args.serial_number, + search_cancellation_token=app_shutdown_token, + channel_termination_token=app_shutdown_token) print_drv_regs("Motor 0", my_odrive.axis0.motor) print_drv_regs("Motor 1", my_odrive.axis1.motor) elif args.command == 'rate-test': from odrive.utils import rate_test print("Waiting for ODrive...") - my_odrive = odrive.discovery.find_any(path=args.path, serial_number=args.serial_number) + my_odrive = odrive.discovery.find_any(path=args.path, serial_number=args.serial_number, + search_cancellation_token=app_shutdown_token, + channel_termination_token=app_shutdown_token) rate_test(my_odrive) elif args.command == 'udev-setup': from odrive.utils import setup_udev_rules setup_udev_rules(logger) + + elif args.command == 'generate-code': + from odrive.code_generator import generate_code + my_odrive = odrive.discovery.find_any(path=args.path, serial_number=args.serial_number, + channel_termination_token=app_shutdown_token) + generate_code(my_odrive, args.template, args.output) + + elif args.command == 'backup-config': + from odrive.configuration import backup_config + print("Waiting for ODrive...") + my_odrive = odrive.discovery.find_any(path=args.path, serial_number=args.serial_number, + search_cancellation_token=app_shutdown_token, + channel_termination_token=app_shutdown_token) + backup_config(my_odrive, args.file, logger) + + elif args.command == 'restore-config': + from odrive.configuration import restore_config + print("Waiting for ODrive...") + my_odrive = odrive.discovery.find_any(path=args.path, serial_number=args.serial_number, + search_cancellation_token=app_shutdown_token, + channel_termination_token=app_shutdown_token) + restore_config(my_odrive, args.file, logger) else: raise Exception("unknown command: " + args.command) +except OperationAbortedException: + logger.info("Operation aborted.") finally: app_shutdown_token.set() diff --git a/tools/run_tests.py b/tools/run_tests.py index 1cb1bcd8..3ba2e5ab 100755 --- a/tools/run_tests.py +++ b/tools/run_tests.py @@ -87,6 +87,12 @@ else: all_tests.append(TestDiscoverAndGotoIdle()) all_tests.append(TestEncoderOffsetCalibration(pass_if_ready=True)) +all_tests.append(TestAsciiProtocol()) +all_tests.append(TestSensorlessControl()) + +#all_tests.append(TestStepDirInput()) +#all_tests.append(TestPWMInput()) + if test_rig_yaml['type'] == 'parallel': #all_tests.append(TestHighVelocity()) all_tests.append(TestHighVelocityInViscousFluid(load_current=35, driver_current=45)) @@ -136,7 +142,7 @@ try: if isinstance(test, ODriveTest): def odrv_test_thread(odrv_name): odrv_ctx = odrives_by_name[odrv_name] - logger.info('* running {} on {}...'.format(type(test).__name__, odrv_name)) + logger.notify('* running {} on {}...'.format(type(test).__name__, odrv_name)) try: test.check_preconditions(odrv_ctx, logger.indent(' {}: '.format(odrv_name))) @@ -165,7 +171,7 @@ try: try: if not app_shutdown_token.is_set(): # Run test on this axis - logger.info('* running {} on {}...'.format(type(test).__name__, axis_name)) + logger.notify('* running {} on {}...'.format(type(test).__name__, axis_name)) try: test.check_preconditions(axis_ctx, logger.indent(' {}: '.format(axis_name))) @@ -197,7 +203,7 @@ try: try: if not app_shutdown_token.is_set(): # Run test on this axis - logger.info('* running {} on {}...'.format(type(test).__name__, coupling_name)) + logger.notify('* running {} on {}...'.format(type(test).__name__, coupling_name)) try: test.check_preconditions(coupled_axes[0], coupled_axes[1], logger.indent(' {}: '.format(coupling_name)))