Basic I2C functionality
This commit is contained in:
77
Core/Src/i2c.cpp
Normal file
77
Core/Src/i2c.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
#include "i2c.hpp"
|
||||
|
||||
#include "pindef.hpp"
|
||||
#include "stm32f4xx_hal_i2c.h"
|
||||
|
||||
namespace driver::i2c {
|
||||
I2c::I2c(I2C_TypeDef* i2c, const uint32_t clockSpeed, const uint32_t dutyCycle,
|
||||
const uint32_t ownAddress1, const uint32_t addressingMode, const uint32_t dualAddressMode,
|
||||
const uint32_t ownAddress2, const uint32_t generalCallMode, const uint32_t noStretchMode)
|
||||
: mHandle{.Instance = i2c,
|
||||
.Init{.ClockSpeed = clockSpeed,
|
||||
.DutyCycle = dutyCycle,
|
||||
.OwnAddress1 = ownAddress1,
|
||||
.AddressingMode = addressingMode,
|
||||
.DualAddressMode = dualAddressMode,
|
||||
.OwnAddress2 = ownAddress2,
|
||||
.GeneralCallMode = generalCallMode,
|
||||
.NoStretchMode = noStretchMode},
|
||||
.pBuffPtr = nullptr,
|
||||
.XferSize = 0,
|
||||
.XferCount = 0,
|
||||
.XferOptions = 0,
|
||||
.PreviousState = 0,
|
||||
.hdmatx = nullptr,
|
||||
.hdmarx = nullptr,
|
||||
.Lock = HAL_UNLOCKED,
|
||||
.State = HAL_I2C_STATE_RESET,
|
||||
.Mode = HAL_I2C_MODE_NONE,
|
||||
.ErrorCode = HAL_I2C_ERROR_NONE,
|
||||
.Devaddress = 0,
|
||||
.Memaddress = 0,
|
||||
.MemaddSize = 0,
|
||||
.EventCount = 0} {}
|
||||
|
||||
bool I2c::init() {
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
if (mHandle.Instance == I2C1) {
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
/**I2C1 GPIO Configuration
|
||||
PB6 ------> I2C1_SCL
|
||||
PB7 ------> I2C1_SDA
|
||||
*/
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
|
||||
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);
|
||||
|
||||
__HAL_RCC_I2C1_CLK_ENABLE();
|
||||
}
|
||||
return HAL_I2C_Init(&mHandle) == HAL_OK;
|
||||
}
|
||||
|
||||
void I2c::deinit() {}
|
||||
|
||||
HAL_StatusTypeDef I2c::write(const uint16_t slaveAddr, const uint16_t memAddr,
|
||||
std::vector<uint8_t>& data) {
|
||||
// Slave address needs to be shifted to the left, so that the r/w bit can be set by the HAL method
|
||||
// Addressing mode for slaves is fixed to 8bit for now...
|
||||
return HAL_I2C_Mem_Write(&mHandle, slaveAddr << 1, memAddr, I2C_MEMADD_SIZE_8BIT, data.data(),
|
||||
data.size(), I2C_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
std::pair<HAL_StatusTypeDef, uint8_t> I2c::read(const uint16_t slaveAddr, const uint16_t memAddr) {
|
||||
uint8_t data;
|
||||
// Slave address needs to be shifted to the left, so that the r/w bit can be set by the HAL method
|
||||
auto state = HAL_I2C_Mem_Read(&mHandle, slaveAddr << 1, memAddr, I2C_MEMADD_SIZE_8BIT, &data, 1,
|
||||
I2C_TIMEOUT_MS);
|
||||
return {state, data};
|
||||
}
|
||||
|
||||
uint32_t I2c::getLastError() {
|
||||
return mHandle.ErrorCode;
|
||||
}
|
||||
|
||||
} // namespace driver::i2c
|
@@ -1,12 +1,22 @@
|
||||
#include "main.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "gpio.h"
|
||||
#include "i2c.hpp"
|
||||
#include "stm32_hal_legacy.h"
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "stm32f4xx_hal_def.h"
|
||||
#include "stm32f4xx_hal_i2c.h"
|
||||
#include "usart.hpp"
|
||||
|
||||
// needs to be global to be accessible in error handler
|
||||
std::unique_ptr<driver::usart::Usart> usart2{nullptr};
|
||||
|
||||
void SystemClock_Config(void);
|
||||
void checkHalStatus(HAL_StatusTypeDef);
|
||||
|
||||
int main(void) {
|
||||
|
||||
@@ -19,20 +29,85 @@ int main(void) {
|
||||
/* Initialize all configured peripherals */
|
||||
MX_GPIO_Init();
|
||||
|
||||
driver::usart::Usart usart2(USART2, 115200, UART_WORDLENGTH_8B, UART_STOPBITS_1,
|
||||
UART_PARITY_NONE, UART_MODE_TX_RX, UART_HWCONTROL_NONE,
|
||||
UART_OVERSAMPLING_16);
|
||||
usart2 = std::make_unique<driver::usart::Usart>(
|
||||
driver::usart::Usart(USART2, 115200, UART_WORDLENGTH_8B, UART_STOPBITS_1, UART_PARITY_NONE,
|
||||
UART_MODE_TX_RX, UART_HWCONTROL_NONE, UART_OVERSAMPLING_16));
|
||||
|
||||
usart2.init();
|
||||
usart2.println("");
|
||||
usart2.println("\r\nWeight cell init.");
|
||||
usart2->init();
|
||||
usart2->println("");
|
||||
usart2->println("\r\nWeight cell init.");
|
||||
|
||||
int i{0};
|
||||
auto i2c1 = std::make_unique<driver::i2c::I2c>(
|
||||
I2C1, 100000, I2C_DUTYCYCLE_2, 0x00, I2C_ADDRESSINGMODE_7BIT, I2C_DUALADDRESS_DISABLED,
|
||||
0x00, I2C_GENERALCALL_DISABLED, I2C_NOSTRETCH_DISABLED);
|
||||
|
||||
if (!i2c1->init()) {
|
||||
usart2->println("Error intializing I2C1!");
|
||||
usart2->println("Last Error: " + std::to_string(i2c1->getLastError()));
|
||||
Error_Handler();
|
||||
} else {
|
||||
usart2->println("I2C1 intialized successful");
|
||||
}
|
||||
// init NAU7802
|
||||
{
|
||||
std::vector<uint8_t> data = {0x01};
|
||||
// reset NAU7802
|
||||
checkHalStatus(i2c1->write(0x2A, 0x00, data));
|
||||
usart2->println("Reset nau");
|
||||
HAL_Delay(100);
|
||||
|
||||
// power up digital logic
|
||||
data[0] = 0x02;
|
||||
i2c1->write(0x2A, 0x00, data);
|
||||
HAL_Delay(100);
|
||||
usart2->println("PUP digi");
|
||||
|
||||
// power up analog logic
|
||||
data[0] = 0x06;
|
||||
i2c1->write(0x2A, 0x00, data);
|
||||
HAL_Delay(100);
|
||||
|
||||
usart2->println("PUP analog");
|
||||
|
||||
// use internal LDO as reference
|
||||
data[0] = 0x86;
|
||||
checkHalStatus(i2c1->write(0x2A, 0x00, data));
|
||||
HAL_Delay(100);
|
||||
|
||||
// print status back to usart
|
||||
auto ret = i2c1->read(0x2A, 0x00);
|
||||
checkHalStatus(ret.first);
|
||||
usart2->println("NAU7802 reports state " + std::to_string(ret.second) + " at 0x00");
|
||||
|
||||
// REG_CHPS CLK_CHP off
|
||||
data[0] = 0x30;
|
||||
checkHalStatus(i2c1->write(0x2A, 0x15, data));
|
||||
HAL_Delay(100);
|
||||
}
|
||||
|
||||
uint32_t measurement = 0;
|
||||
auto val = i2c1->read(0x2A, 0x12);
|
||||
measurement |= (val.second << 16);
|
||||
|
||||
val = i2c1->read(0x2A, 0x13);
|
||||
measurement |= (val.second << 8);
|
||||
|
||||
val = i2c1->read(0x2A, 0x14);
|
||||
measurement |= val.second << 16;
|
||||
|
||||
while (1) {
|
||||
std::string buf{"Iteration #"};
|
||||
measurement = 0;
|
||||
val = i2c1->read(0x2A, 0x12);
|
||||
measurement |= (val.second << 16);
|
||||
|
||||
val = i2c1->read(0x2A, 0x13);
|
||||
measurement |= (val.second << 8);
|
||||
|
||||
val = i2c1->read(0x2A, 0x14);
|
||||
measurement |= val.second << 16;
|
||||
|
||||
usart2->println("Measurement " + std::to_string(measurement) + " counts");
|
||||
|
||||
usart2.println(buf + std::to_string(i++));
|
||||
HAL_Delay(1000);
|
||||
}
|
||||
}
|
||||
@@ -75,6 +150,17 @@ void SystemClock_Config(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void checkHalStatus(HAL_StatusTypeDef status) {
|
||||
if (status == HAL_OK) {
|
||||
return;
|
||||
}
|
||||
if (usart2 == nullptr) {
|
||||
Error_Handler();
|
||||
return; // never reached
|
||||
}
|
||||
usart2->println("HAL Status not okay! Calling Error Handler");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function is executed in case of error occurrence.
|
||||
* @retval None
|
||||
@@ -82,6 +168,10 @@ void SystemClock_Config(void) {
|
||||
void Error_Handler(void) {
|
||||
/* USER CODE BEGIN Error_Handler_Debug */
|
||||
/* User can add his own implementation to report the HAL error return state */
|
||||
if (usart2 != nullptr) {
|
||||
usart2->println("=== ERROR HANDLER ===");
|
||||
usart2->println("entering infinite loop...");
|
||||
}
|
||||
__disable_irq();
|
||||
while (1) {}
|
||||
/* USER CODE END Error_Handler_Debug */
|
||||
|
@@ -12,13 +12,29 @@ namespace driver::usart {
|
||||
Usart::Usart(USART_TypeDef* usart, uint32_t baudRate, uint32_t wordLength, uint32_t stopBits,
|
||||
uint32_t parity, uint32_t mode, uint32_t hwFlowCtl, uint32_t overSampling)
|
||||
: mHandle{.Instance = usart,
|
||||
.Init{.BaudRate = baudRate,
|
||||
.WordLength = wordLength,
|
||||
.StopBits = stopBits,
|
||||
.Parity = parity,
|
||||
.Mode = mode,
|
||||
.HwFlowCtl = hwFlowCtl,
|
||||
.OverSampling = overSampling}} {}
|
||||
.Init{
|
||||
.BaudRate = baudRate,
|
||||
.WordLength = wordLength,
|
||||
.StopBits = stopBits,
|
||||
.Parity = parity,
|
||||
.Mode = mode,
|
||||
.HwFlowCtl = hwFlowCtl,
|
||||
.OverSampling = overSampling,
|
||||
},
|
||||
.pTxBuffPtr = nullptr,
|
||||
.TxXferSize = 0,
|
||||
.TxXferCount = 0,
|
||||
.pRxBuffPtr = nullptr,
|
||||
.RxXferSize = 0,
|
||||
.RxXferCount = 0,
|
||||
.ReceptionType = HAL_UART_RECEPTION_STANDARD,
|
||||
.RxEventType = HAL_UART_RXEVENT_TC,
|
||||
.hdmatx = nullptr,
|
||||
.hdmarx = nullptr,
|
||||
.Lock = HAL_UNLOCKED,
|
||||
.gState = HAL_UART_STATE_RESET,
|
||||
.RxState = HAL_UART_STATE_RESET,
|
||||
.ErrorCode = 0} {}
|
||||
|
||||
bool Usart::init() {
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
@@ -38,7 +54,7 @@ bool Usart::init() {
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
}
|
||||
|
||||
return HAL_UART_Init(&mHandle) != HAL_OK;
|
||||
return HAL_UART_Init(&mHandle) == HAL_OK;
|
||||
}
|
||||
|
||||
void Usart::deinit() {
|
||||
@@ -60,14 +76,9 @@ void Usart::println(const std::string_view str) {
|
||||
}
|
||||
|
||||
void Usart::tx(const std::string_view range) {
|
||||
for (uint32_t pt{0}; pt <= range.size(); pt += TX_BUFSIZE) {
|
||||
uint8_t txLen{TX_BUFSIZE};
|
||||
if (range.length() < TX_BUFSIZE) {
|
||||
txLen = range.length();
|
||||
}
|
||||
HAL_UART_Transmit(&mHandle, reinterpret_cast<const uint8_t*>(range.begin() + pt), txLen,
|
||||
TX_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
HAL_UART_Transmit(&mHandle, reinterpret_cast<const uint8_t*>(range.begin()), range.size(),
|
||||
TX_TIMEOUT_MS);
|
||||
};
|
||||
|
||||
} // namespace driver::usart
|
Reference in New Issue
Block a user