Skip to content

Commit

Permalink
pw_uart_mcuxpresso: Simplify configuration struct
Browse files Browse the repository at this point in the history
- Utilize the pw_dma_mcuxpresso module to manage DMA channels.
- Directly query flexcomm clock freq after the clock is turned on during
  init.

Also fix const application in pw_dma_mcuxpresso that arm compiler in mac
CI didn't like and looked like a mistake anyways. This was needed to
dma_uart_example.cc could compile.

Change-Id: I52a55348aa80f367c07de387fd33e0bbe6358535
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/236919
Lint: Lint 🤖 <[email protected]>
Docs-Not-Needed: Jonathon Reinhart <[email protected]>
Pigweed-Auto-Submit: Austin Foxley <[email protected]>
Commit-Queue: Auto-Submit <[email protected]>
Reviewed-by: Jonathon Reinhart <[email protected]>
  • Loading branch information
afoxley authored and CQ Bot Account committed Sep 24, 2024
1 parent a4dab0b commit ca679a2
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 52 deletions.
4 changes: 2 additions & 2 deletions pw_dma_mcuxpresso/public/pw_dma_mcuxpresso/dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class McuxpressoDmaChannel {
uint32_t channel)
: controller_(controller), channel_(channel) {}

DMA_Type* const controller_base();
DMA_Type* controller_base() const;

McuxpressoDmaController& controller_;
uint32_t const channel_;
Expand Down Expand Up @@ -134,7 +134,7 @@ class McuxpressoDmaController {
uintptr_t const base_address_;
};

inline DMA_Type* const McuxpressoDmaChannel::controller_base() {
inline DMA_Type* McuxpressoDmaChannel::controller_base() const {
return controller_.base();
}

Expand Down
1 change: 1 addition & 0 deletions pw_uart_mcuxpresso/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ cc_library(
],
deps = [
"//pw_clock_tree",
"//pw_dma_mcuxpresso",
"//pw_preprocessor",
"//pw_sync:interrupt_spin_lock",
"//pw_sync:timed_thread_notification",
Expand Down
1 change: 1 addition & 0 deletions pw_uart_mcuxpresso/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ if (pw_third_party_mcuxpresso_SDK != "") {
public = [ "public/pw_uart_mcuxpresso/dma_uart.h" ]
public_deps = [
"$dir_pw_clock_tree",
"$dir_pw_dma_mcuxpresso",
"$dir_pw_sync:timed_thread_notification",
"$dir_pw_uart:uart",
]
Expand Down
56 changes: 21 additions & 35 deletions pw_uart_mcuxpresso/dma_uart.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include <optional>

#include "fsl_flexcomm.h"
#include "pw_assert/check.h"
#include "pw_preprocessor/util.h"

Expand All @@ -27,16 +28,8 @@ void DmaUartMcuxpresso::Deinit() {
return;
}

// We need to touch register space that can be shared
// among several DMA peripherals, hence we need to access
// it exclusively. We achieve exclusive access on non-SMP systems as
// a side effect of acquiring the interrupt_lock_, since acquiring the
// interrupt_lock_ disables interrupts on the current CPU, which means
// we cannot get descheduled until we release the interrupt_lock_.
interrupt_lock_.lock();
DMA_DisableChannel(config_.dma_base, config_.tx_dma_ch);
DMA_DisableChannel(config_.dma_base, config_.rx_dma_ch);
interrupt_lock_.unlock();
config_.tx_dma_ch.Disable();
config_.rx_dma_ch.Disable();

USART_Deinit(config_.usart_base);
clock_tree_element_controller_.Release().IgnoreError();
Expand All @@ -47,30 +40,27 @@ DmaUartMcuxpresso::~DmaUartMcuxpresso() { Deinit(); }
// Initialize the USART and DMA channels based on the configuration
// specified during object creation.
Status DmaUartMcuxpresso::Init() {
if (config_.srcclk == 0) {
return Status::InvalidArgument();
}
if (config_.usart_base == nullptr) {
return Status::InvalidArgument();
}
if (config_.baud_rate == 0) {
return Status::InvalidArgument();
}
if (config_.dma_base == nullptr) {
return Status::InvalidArgument();
}

usart_config_t defconfig_;
USART_GetDefaultConfig(&defconfig_);
usart_config_t defconfig;
USART_GetDefaultConfig(&defconfig);

defconfig_.baudRate_Bps = config_.baud_rate;
defconfig_.enableHardwareFlowControl = config_.flow_control;
defconfig_.parityMode = config_.parity;
defconfig_.enableTx = true;
defconfig_.enableRx = true;
defconfig.baudRate_Bps = config_.baud_rate;
defconfig.enableHardwareFlowControl = config_.flow_control;
defconfig.parityMode = config_.parity;
defconfig.enableTx = true;
defconfig.enableRx = true;

PW_TRY(clock_tree_element_controller_.Acquire());
status_t status = USART_Init(config_.usart_base, &defconfig_, config_.srcclk);
flexcomm_clock_freq_ =
CLOCK_GetFlexcommClkFreq(FLEXCOMM_GetInstance(config_.usart_base));
status_t status =
USART_Init(config_.usart_base, &defconfig, flexcomm_clock_freq_);
if (status != kStatus_Success) {
clock_tree_element_controller_.Release().IgnoreError();
return Status::Internal();
Expand All @@ -93,20 +83,17 @@ Status DmaUartMcuxpresso::Init() {
INPUTMUX, config_.tx_input_mux_dmac_ch_request_en, true);
INPUTMUX_Deinit(INPUTMUX);

DMA_EnableChannel(config_.dma_base, config_.tx_dma_ch);
DMA_EnableChannel(config_.dma_base, config_.rx_dma_ch);

DMA_CreateHandle(&tx_data_.dma_handle, config_.dma_base, config_.tx_dma_ch);
DMA_CreateHandle(&rx_data_.dma_handle, config_.dma_base, config_.rx_dma_ch);

interrupt_lock_.unlock();

config_.tx_dma_ch.Enable();
config_.rx_dma_ch.Enable();

status = USART_TransferCreateHandleDMA(config_.usart_base,
&uart_dma_handle_,
TxRxCompletionCallback,
this,
&tx_data_.dma_handle,
&rx_data_.dma_handle);
config_.tx_dma_ch.handle(),
config_.rx_dma_ch.handle());

if (status != kStatus_Success) {
Deinit();
Expand Down Expand Up @@ -385,7 +372,6 @@ Status DmaUartMcuxpresso::WaitForReceiveBytes(
// Copy the data from the receive ring buffer into the destination data buffer
void DmaUartMcuxpresso::CopyReceiveData(ByteBuilder& bb, size_t copy_size) {
ByteSpan ring_buffer = rx_data_.ring_buffer;
reinterpret_cast<uint8_t*>(rx_data_.ring_buffer.data());
// Check whether we need to perform a wrap around copy operation or end
// right at the end of the buffer.
if (rx_data_.ring_buffer_read_idx + copy_size >=
Expand Down Expand Up @@ -432,8 +418,8 @@ Status DmaUartMcuxpresso::DoSetBaudRate(uint32_t baud_rate) {
return OkStatus();
}

status_t status =
USART_SetBaudRate(config_.usart_base, config_.baud_rate, config_.srcclk);
status_t status = USART_SetBaudRate(
config_.usart_base, config_.baud_rate, flexcomm_clock_freq_);
switch (status) {
default:
return Status::Unknown();
Expand Down
14 changes: 6 additions & 8 deletions pw_uart_mcuxpresso/dma_uart_example.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// License for the specific language governing permissions and limitations under
// the License.

#include "pw_dma_mcuxpresso/dma.h"
#include "pw_status/try.h"
#include "pw_uart_mcuxpresso/dma_uart.h"
#include "pw_unit_test/framework.h"
Expand All @@ -20,32 +21,29 @@ namespace examples {

pw::Status DmaUartExample() {
// DOCSTAG: [pw_uart_mcuxpresso-DmaUartExample]
constexpr uint32_t kFlexcomm = 0;
const auto kUartBase = USART0;
constexpr uint32_t kBaudRate = 115200;
constexpr bool kFlowControl = true;
constexpr uint32_t kUartInstance = 5;
std::array<std::byte, 65536> ring_buffer = {};
constexpr uint32_t kUartRxDmaCh = 0;
constexpr uint32_t kUartTxDmaCh = 1;

uint32_t flexcomm_clock_freq = CLOCK_GetFlexcommClkFreq(kUartInstance);
static pw::dma::McuxpressoDmaController dma(DMA0_BASE);
static pw::dma::McuxpressoDmaChannel rx_dma_ch = dma.GetChannel(kUartRxDmaCh);
static pw::dma::McuxpressoDmaChannel tx_dma_ch = dma.GetChannel(kUartTxDmaCh);

const pw::uart::DmaUartMcuxpresso::Config kConfig = {
.usart_base = kUartBase,
.baud_rate = kBaudRate,
.flow_control = kFlowControl,
.parity = kUSART_ParityDisabled,
.stop_bits = kUSART_OneStopBit,
.dma_base = DMA0,
.rx_dma_ch = kUartRxDmaCh,
.tx_dma_ch = kUartTxDmaCh,
.rx_dma_ch = rx_dma_ch,
.tx_dma_ch = tx_dma_ch,
.rx_input_mux_dmac_ch_request_en =
kINPUTMUX_Flexcomm0RxToDmac0Ch0RequestEna,
.tx_input_mux_dmac_ch_request_en =
kINPUTMUX_Flexcomm0TxToDmac0Ch1RequestEna,
.buffer = pw::ByteSpan(ring_buffer),
.srcclk = flexcomm_clock_freq,
};

auto uart = pw::uart::DmaUartMcuxpresso{kConfig};
Expand Down
12 changes: 5 additions & 7 deletions pw_uart_mcuxpresso/public/pw_uart_mcuxpresso/dma_uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "pw_bytes/byte_builder.h"
#include "pw_bytes/span.h"
#include "pw_clock_tree/clock_tree.h"
#include "pw_dma_mcuxpresso/dma.h"
#include "pw_status/status.h"
#include "pw_sync/interrupt_spin_lock.h"
#include "pw_sync/timed_thread_notification.h"
Expand All @@ -37,17 +38,15 @@ class DmaUartMcuxpresso final : public Uart {
bool flow_control = false; // Hardware flow control setting
usart_parity_mode_t parity = kUSART_ParityDisabled; // Parity setting
usart_stop_bit_count_t stop_bits =
kUSART_OneStopBit; // Number of stop bits to use
DMA_Type* dma_base; // Base of DMA control struct
uint32_t rx_dma_ch; // Receive DMA channel
uint32_t tx_dma_ch; // Transmit DMA channel
kUSART_OneStopBit; // Number of stop bits to use
dma::McuxpressoDmaChannel& rx_dma_ch; // Receive DMA channel
dma::McuxpressoDmaChannel& tx_dma_ch; // Transmit DMA channel
inputmux_signal_t rx_input_mux_dmac_ch_request_en; // Rx input mux signal
inputmux_signal_t tx_input_mux_dmac_ch_request_en; // Tx input mux signal
ByteSpan buffer; // Receive ring buffer
pw::clock_tree::ClockTree* clock_tree{}; // Optional clock Tree
pw::clock_tree::Element*
clock_tree_element{}; // Optional clock tree element
uint32_t srcclk; // USART clock source frequency in Hz
};

DmaUartMcuxpresso(const Config& config)
Expand All @@ -67,7 +66,6 @@ class DmaUartMcuxpresso final : public Uart {
struct UsartDmaTxData {
ConstByteSpan buffer; // TX transaction buffer
size_t tx_idx; // Position within TX transaction
dma_handle_t dma_handle; // DMA handle
usart_transfer_t transfer; // USART TX transfer structure
std::atomic_uint8_t busy; // Flag to prevent concurrent access to TX queue
pw::sync::TimedThreadNotification
Expand All @@ -86,7 +84,6 @@ class DmaUartMcuxpresso final : public Uart {
// bytes
size_t completion_size{};
usart_transfer_t transfer{}; // USART RX transfer structure
dma_handle_t dma_handle{}; // DMA handle
std::atomic_uint8_t
busy{}; // Flag to prevent concurrent access to RX ring buffer
pw::sync::TimedThreadNotification
Expand Down Expand Up @@ -148,6 +145,7 @@ class DmaUartMcuxpresso final : public Uart {
// optional clock tree information
bool
initialized_; // Whether the USART and DMA channels have been initialized
uint32_t flexcomm_clock_freq_{};
};

} // namespace pw::uart

0 comments on commit ca679a2

Please sign in to comment.