Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions DMA/DMA (1).txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
DMA

STM32 at least one DMA controller for data transfer duties offload from cpu

STM32G4 - more flexible

32bit data width (same as STM32F0/F1/F3/Cx/Gx/Lx/U0)
----------------------
AHB buses (1 or +) bus matrix and the peripherals.
"AHB bus does not provide the data (aka layer) parallelism of the bus matrix, but it runs on the same system
clock speed, and provide moderate bandwidth, thanks to its pipelined data/address protocol"

APB
APB buses (1 or +) DMA data transfer from or to an APB peripheral is first crossing the bus matrix, and the AHB to APB bridge.
APB bus -> connect and share 1+ APB periph (low bandwidth req). APB CLK spd can be tuned down from AHB speed w/CLK div.
high divider ratio
yields lower power consumption, but at the cost of lower bandwidth and higher latency.

DMA channels == improves bus bandwidth usage, but + latency (due to highest priority channel DMA arbitration scheme)

Same transfer in the opposite direction (peripheral to memory) same latency for the DMA data transfer.


"The assignment of the available bus resources can be focused on bandwidth (bus is assigned for a longer period,
minimizing overhead) or on low latency in sharing (simple and fast switching between tasks). The requirements in
MCU use cases favor the latter choice. This way it is impossible to use the whole bus bandwidth for a single DMA
transfer, but sharing is efficient."

DMA1 transfer from SRAM1 to AES can access the
bus matrix simultaneously with DMA2 transfer from flash memory to any APB communication interface. No
conflict and arbitration occurs

better to assign priorities to minimize latency within the round for selected channels

The APB bus introduces a first
additional latency with the AHB to APB bridge. Another APB cause of extra latency is when the APB peripheral is
used with a lower APB frequency vs the AHB frequency.




==========================
DMAMUX:

The DMAMUX controller is designed to simplify the allocation of embedded application resources. It offers the
flexibility to dynamically allocate a peripheral to a DMA channel, and increases the DMA capabilities thanks to a
synchronization mechanism that allows to free the CPU from some tasks. The combination of synchronization and
request generation can be used to implement power optimized data transfer (in autonomous mode without CPU
involvement)


explained:

fully configurable routing of any DMA request from a given peripheral in DMA mode to any DMA channel of the DMA controllers.
not add any clock cycles between DMA req (sent from periph) and (received by dma channel)
Dedicated inputs for DMA req sync
able to generate req from own trigger in or software.
more flexibility, resulting in full dynamic DMA peripheral request mapping instead of pseudo-dynamic mapping.


synchronization signal (SYNC_ID), the synchronization signal polarity (SPOL) and the number of requests to
forward (NBREQ + 1) are configured in the request line multiplexer channel configuration register
(DMAMUX_CxCR).
==========================






************************
SPECIFIC TO G4:
8 DMA 1
8 DMA 2

as x2 8 DMA chann :. 16 request multiplexer channels available

DMAMUX - 4 channels, 21 IN
Harvard arch
Flash mem connection - 32 + 32 b
CPU Core - M4
AHB:APB bridge CLK - 2


***********************



***********************

STM32H7


DUAL AHB master bus architecture with independent FIFO: optimize the system bandwidth
16 streams over (DMA1 DMA2)
indep stream interr flags
four-word FIFO per stream allows performing data
packing/unpacking and burst transfers

STM32CubeH7 examples
The following examples are available on the STM32CubeH7 under root "Projects\STM32H743I-
EVAL\Examples\DMA\":

***********************


59 changes: 59 additions & 0 deletions DMA/DMATransfer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
********************************************************************************
* @file DMATransfer.hpp
* @author Javier
* @date 2026-01-10
* @brief Header for the DMA Transfer Driver.
********************************************************************************
*/

#ifndef DMATRANSFER_HPP
#define DMATRANSFER_HPP

/************************************
* INCLUDES
************************************/
#include "main.h"
#include "cmsis_os.h"
#include <type_traits>

/************************************
* CLASS DEFINITIONS
************************************/
class DMAControl {
public:
template <typename HandleType>
static HAL_StatusTypeDef Transfer(HandleType* handle, uint16_t devAddr, uint8_t* txData, uint8_t* rxData, uint16_t size) {

// H7 / G4 Cache Management
#if defined(STM32H7) || defined(STM32G4)
// Cache To RAM before DMA
if (txData != nullptr) SCB_CleanDCache_by_Addr((uint32_t*)txData, size);
// Clean Cache to Force read RAM
if (rxData != nullptr) SCB_InvalidateDCache_by_Addr((uint32_t*)rxData, size);
#endif

// === SPI Logic ===
if constexpr (std::is_same_v<HandleType, SPI_HandleTypeDef>) {
// SPI Transfer (Full-Duplex)
return HAL_SPI_TransmitReceive_DMA(handle, txData, rxData, size);
}

// === I2C Logic ===
if constexpr (std::is_same_v<HandleType, I2C_HandleTypeDef>) {

// Transmit
if (txData != nullptr && rxData == nullptr) {
return HAL_I2C_Master_Transmit_DMA(handle, devAddr, txData, size);
}

// Receive
else if (rxData != nullptr && txData == nullptr) {
return HAL_I2C_Master_Receive_DMA(handle, devAddr, rxData, size);
}
}
return HAL_ERROR;
}
};

#endif /* DMATRANSFER_HPP */
167 changes: 167 additions & 0 deletions NAU7802/NAU7802.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/**
********************************************************************************
* @file nau7802.cpp
* @author Javier
* @date 2025-11-25
* @brief Implementation of the NAU7802 driver.
********************************************************************************
*/

#include "NAU7802.hpp"
#include "main.h"
#include <cstdint>

NAU7802::NAU7802(I2C_Wrapper* i2c_pointer, std::uint8_t address)
: _i2c(i2c_pointer), _deviceAddress(address) {}

// Begin NAU7802 Startup Sequence
NauStatus NAU7802::begin(uint8_t initialGain) {

// 1. Send a reset command
if (reset() != NauStatus::OK) {
return NauStatus::ERR_I2C; // Failed to reset
}
HAL_Delay(10);

// 2. Power up the analog and digital sections
uint8_t pu_ctrl = NAU7802_PU_CTRL_PUA | NAU7802_PU_CTRL_PUD;
writeRegister(NAU7802_REG_PU_CTRL, pu_ctrl);

// 3. Wait for the Power Up Ready bit
uint8_t attempts = 100;
bool powerReady = false;
while (attempts > 0) {
if (readRegister(NAU7802_REG_PU_CTRL, &pu_ctrl) == NauStatus::OK) {
if (pu_ctrl & NAU7802_PU_CTRL_PUR) {
powerReady = true;
break;
}
}
HAL_Delay(1);
attempts--;
}
return setGain(initialGain);
}

bool NAU7802::isReady() {
uint8_t status;
if (readRegister(NAU7802_REG_PU_CTRL, &status) == NauStatus::OK) {
return (status & NAU7802_PU_CTRL_CR) != 0;
}
return false;
}

NauStatus NAU7802::readSensor(NAU7802_OUT *dest) {
uint8_t buffer[3];

if (readRegisters(NAU7802_REG_ADC_B2, buffer, 3 ) != NauStatus::OK) {
dest -> raw_reading = 0;
return NauStatus::ERR_I2C; // Read failed
}

// Combine the three bytes
int32_t value = ((int32_t)buffer[0] << 16) | \
((int32_t)buffer[1] << 8) | \
(buffer[2]);

// Sign-extend the 24-bit value to a 32-bit integer
if (value & 0x00800000) {
value |= 0xFF000000;
}

dest->raw_reading = value;
return NauStatus::OK;
}

NauStatus NAU7802::reset() {
// RR bit
modifyRegisterBit(NAU7802_REG_PU_CTRL, NAU7802_PU_CTRL_RR, true);

HAL_Delay(1); // Small delay to ensure reset is processed

// Clear RR bit
return modifyRegisterBit(NAU7802_REG_PU_CTRL, NAU7802_PU_CTRL_RR, false);
}

NauStatus NAU7802::setGain(uint8_t gain) {
if (gain > NAU7802_GAIN_128X) {
return NauStatus::ERR_INVALID_ARG; // Invalid gain setting
}

// Read current CTRL1 register state
uint8_t ctrl1;
if (readRegister(NAU7802_REG_CTRL1, &ctrl1) != NauStatus::OK) {
return NauStatus::ERR_I2C; // Failed to read CTRL1 register
}

// Modify gain bits
ctrl1 &= 0b11111000; // Clear existing gain
ctrl1 |= gain; // Set new gain

// Write back modified CTRL1 register
if (writeRegister(NAU7802_REG_CTRL1, ctrl1) != NauStatus::OK) {
return NauStatus::ERR_I2C; // Failed to write CTRL1 register
}

// Verify the gain setting
uint8_t verifyCtrl1;
if (readRegister(NAU7802_REG_CTRL1, &verifyCtrl1) != NauStatus::OK) {
return NauStatus::ERR_I2C; // Failed to read back CTRL1 register
}

// Check if gain bits match
if ((verifyCtrl1 & 0b00000111) == gain) {
return NauStatus::OK; // Success
}
else {
return NauStatus::ERR_I2C; // Verification failed
}
}

/* -- Private Helpers -- */
NauStatus NAU7802::writeRegister(std::uint8_t reg, std::uint8_t value) {
if (_i2c->writeByte(_deviceAddress, reg, value)) {
return NauStatus::OK;
}
return NauStatus::ERR_I2C;
}

NauStatus NAU7802::readRegister(std::uint8_t reg, std::uint8_t* value) {
if (_i2c->readByte(_deviceAddress, reg, value)) {
return NauStatus::OK;
}
return NauStatus::ERR_I2C;
}

NauStatus NAU7802::readRegisters(std::uint8_t reg, std::uint8_t* buffer, std::uint8_t len) {
if (_i2c->readBytes(_deviceAddress, reg, buffer, len)) {
return NauStatus::OK;
}
return NauStatus::ERR_I2C;
}

NauStatus NAU7802::modifyRegisterBit(std::uint8_t reg, std::uint8_t bitMask, bool state) {
uint8_t val;

// 1. Check Read Status
NauStatus status = readRegister(reg, &val);
if (status != NauStatus::OK) {
return status; // Propagate error
}

// 2. Modify
if (state) {
val |= bitMask;
} else {
val &= ~bitMask;
}

// 3. Return Write Status
return writeRegister(reg, val);
}

NauStatus NAU7802::calibrate() {
// TODO: Implement calibration logic based on datasheet
// Usually involves setting CALS bit in REG0x02
return modifyRegisterBit(NAU7802_REG_CTRL2, NAU7802_CTRL2_CALS, true);
}
Loading