mirror of
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
synced 2025-03-16 05:49:10 +00:00
448 lines
14 KiB
C
448 lines
14 KiB
C
/******************************************************************************
|
|
* The MIT License
|
|
*
|
|
* Copyright (c) 2010 Michael Hope.
|
|
* Copyright (c) 2012 LeafLabs, LLC.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without
|
|
* restriction, including without limitation the rights to use, copy,
|
|
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
* of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*****************************************************************************/
|
|
|
|
/**
|
|
* @file libmaple/include/libmaple/dma.h
|
|
*
|
|
* @author Marti Bolivar <mbolivar@leaflabs.com>;
|
|
* Original implementation by Michael Hope
|
|
*
|
|
* @brief Direct Memory Access peripheral support
|
|
*/
|
|
|
|
#ifndef _LIBMAPLE_DMA_H_
|
|
#define _LIBMAPLE_DMA_H_
|
|
|
|
#ifdef __cplusplus
|
|
extern "C"{
|
|
#endif
|
|
|
|
/* <series/dma.h> provides:
|
|
*
|
|
* - An opaque dma_tube type, and predefined rvalues for each tube
|
|
* supported by the series.
|
|
*
|
|
* A "DMA tube" is a series-specific (hopefully integer) datatype
|
|
* that abstracts the conduit through which DMA-ed data flow.
|
|
*
|
|
* Examples: On STM32F1, dma_tube is just an alias for dma_channel,
|
|
* and the tube values are just DMA_CH1 (=1), DMA_CH2 (=2), etc.
|
|
*
|
|
* Note that a dma_tube doesn't have to be an enum, and its values
|
|
* don't have to be integral. They _do_ need to be cheap to pass as
|
|
* arguments, though.
|
|
*
|
|
* - struct dma_tube_reg_map (and typedef to dma_tube_reg_map). DMA
|
|
* register maps tend to be split into global registers and per-tube
|
|
* registers. It's convenient to pass around pointers to a tube's
|
|
* registers, since that makes it possible to configure or otherwise
|
|
* mess with a tube without knowing which one you're dealing with.
|
|
*
|
|
* - Base pointers to the various dma_tube_reg_maps.
|
|
*
|
|
* Examples: On STM32F1, these are DMAxCHy_BASE. You can access
|
|
* registers like DMAxCHy_BASE->CPAR, etc.
|
|
*
|
|
* - enum dma_request_src (and typedef to dma_request_src). This
|
|
* specifies the peripheral DMA request sources (e.g. USART TX DMA
|
|
* requests, etc.).
|
|
*
|
|
* - enum dma_mode_flags (and typedef to dma_mode_flags). Used in
|
|
* dma_tube_config. If two series both support the same mode flags,
|
|
* they must use the same enumerator names for those flags (the
|
|
* values of those enumerators are of course allowed to differ).
|
|
*
|
|
* - Normal stuff: dma_reg_map and base pointers, register bit
|
|
* definitions, dma_dev pointer declarations, and any other
|
|
* convenience functions useful for the series. */
|
|
|
|
/* Roger clark. Replaced with line below #include <series/dma.h>*/
|
|
#include "stm32f1/include/series/dma.h"
|
|
|
|
/* <libmaple/dma_common.h> buys us dma_dev and other necessities. */
|
|
#include <libmaple/dma_common.h>
|
|
#include <libmaple/libmaple_types.h>
|
|
|
|
/*
|
|
* Declarations/documentation for some of the series-provided types.
|
|
*/
|
|
|
|
/**
|
|
* @brief (Series-dependent) DMA request sources.
|
|
*
|
|
* These specify the various pieces of peripheral functionality which
|
|
* may make DMA requests. Use them to set up a DMA transfer (see
|
|
* struct dma_tube_config, dma_tube_cfg()).
|
|
*/
|
|
enum dma_request_src;
|
|
|
|
/**
|
|
* @brief (Series-dependent) DMA tube configuration flags.
|
|
* These specify miscellaneous bits of configuration for a DMA tube.
|
|
* @see struct dma_mode_config
|
|
*/
|
|
enum dma_cfg_flags;
|
|
|
|
/**
|
|
* @brief (Series-dependent) DMA tube register map type.
|
|
* This allows you to access a tube's registers as a group.
|
|
* @see dma_tube_regs()
|
|
*/
|
|
struct dma_tube_reg_map;
|
|
|
|
/*
|
|
* Convenience functions
|
|
*/
|
|
|
|
/* Initialization */
|
|
|
|
void dma_init(dma_dev *dev);
|
|
|
|
/* dma_tube configuration
|
|
*
|
|
* Use these types and functions to set up DMA transfers, handle
|
|
* interrupts, etc. The main function of interest is dma_tube_cfg(),
|
|
* which the various series implement separately. */
|
|
|
|
/**
|
|
* @brief Specifies a DMA tube configuration.
|
|
*
|
|
* Use one of these to set up a DMA transfer by passing it to
|
|
* dma_tube_cfg().
|
|
*
|
|
* @see dma_tube_cfg()
|
|
* @see dma_xfer_size
|
|
*/
|
|
typedef struct dma_tube_config {
|
|
/** Source of data */
|
|
__io void *tube_src;
|
|
/** Source transfer size */
|
|
dma_xfer_size tube_src_size;
|
|
|
|
/** Destination of data */
|
|
__io void *tube_dst;
|
|
/** Destination transfer size */
|
|
dma_xfer_size tube_dst_size;
|
|
|
|
/**
|
|
* Number of data to transfer (0 to 65,535).
|
|
*
|
|
* Note that this is NOT measured in bytes; it's measured in
|
|
* number of data, which occur in multiples of tube_src_size. For
|
|
* example, if tube_src_size is DMA_SIZE_32BITS and tube_nr_xfers
|
|
* is 2, then 8 total bytes will be transferred.
|
|
*/
|
|
unsigned tube_nr_xfers;
|
|
|
|
/**
|
|
* Target-specific configuration flags.
|
|
*
|
|
* These are an OR of series-specific enum dma_mode_flags values.
|
|
* Consult the documentation for your target for what flags you
|
|
* can use here.
|
|
*
|
|
* Typical flag examples: DMA_CFG_SRC_INC, DMA_CFG_DST_INC,
|
|
* DMA_CFG_CIRC, DMA_CFG_CMPLT_IE, etc.
|
|
*/
|
|
unsigned tube_flags;
|
|
|
|
/**
|
|
* Currently unused. You must set this to 0 or something valid for
|
|
* your target. */
|
|
void *target_data;
|
|
|
|
/**
|
|
* Hardware DMA request source.
|
|
*
|
|
* This is ignored for memory-to-memory transfers.
|
|
*/
|
|
enum dma_request_src tube_req_src;
|
|
} dma_tube_config;
|
|
|
|
#define DMA_TUBE_CFG_SUCCESS 0
|
|
#define DMA_TUBE_CFG_EREQ 1
|
|
#define DMA_TUBE_CFG_ENDATA 2
|
|
#define DMA_TUBE_CFG_EDEV 3
|
|
#define DMA_TUBE_CFG_ESRC 4
|
|
#define DMA_TUBE_CFG_EDST 5
|
|
#define DMA_TUBE_CFG_EDIR 6
|
|
#define DMA_TUBE_CFG_ESIZE 7
|
|
#define DMA_TUBE_CFG_ECFG 0xFF
|
|
/**
|
|
* @brief Configure a DMA tube.
|
|
*
|
|
* Use this function to set up a DMA transfer. The tube will be
|
|
* disabled before being reconfigured. The transfer will have low
|
|
* priority by default. You can choose another priority before the
|
|
* transfer begins using dma_set_priority(). You can manage your
|
|
* interrupt handlers for the tube using dma_attach_interrupt() and
|
|
* dma_detach_interrupt().
|
|
*
|
|
* After calling dma_tube_cfg() and performing any other desired
|
|
* configuration, start the transfer using dma_enable().
|
|
*
|
|
* @param dev DMA device.
|
|
* @param tube DMA tube to configure.
|
|
* @param cfg Configuration to apply to tube.
|
|
*
|
|
* @return DMA_TUBE_CFG_SUCCESS (0) on success, <0 on failure. On
|
|
* failure, returned value will be the opposite (-) of one of:
|
|
*
|
|
* - DMA_TUBE_CFG_EREQ: tube doesn't work with cfg->tube_req_src
|
|
* - DMA_TUBE_CFG_ENDATA: cfg->tube_[src,dst]_size are
|
|
* incompatible with cfg->tube_nr_xfers, or cfg->tube_nr_xfers
|
|
* is out of bounds.
|
|
* - DMA_TUBE_CFG_EDEV: dev does not support cfg
|
|
* - DMA_TUBE_CFG_ESRC: bad cfg->tube_src
|
|
* - DMA_TUBE_CFG_EDST: bad cfg->tube_dst
|
|
* - DMA_TUBE_CFG_EDIR: dev can't transfer from cfg->tube_src to
|
|
* cfg->tube_dst
|
|
* - DMA_TUBE_CFG_ESIZE: something ended up wrong due to MSIZE/PSIZE
|
|
* - DMA_TUBE_CFG_ECFG: generic "something's wrong"
|
|
*
|
|
* @sideeffect Disables tube. May alter tube's registers even when an
|
|
* error occurs.
|
|
* @see struct dma_tube_config
|
|
* @see dma_attach_interrupt()
|
|
* @see dma_detach_interrupt()
|
|
* @see dma_enable()
|
|
*/
|
|
extern int dma_tube_cfg(dma_dev *dev, dma_tube tube, dma_tube_config *cfg);
|
|
|
|
/* Other tube configuration functions. You can use these if
|
|
* dma_tube_cfg() isn't enough, or to adjust parts of an existing tube
|
|
* configuration. */
|
|
|
|
/** DMA transfer priority. */
|
|
typedef enum dma_priority {
|
|
DMA_PRIORITY_LOW = 0, /**< Low priority */
|
|
DMA_PRIORITY_MEDIUM = 1, /**< Medium priority */
|
|
DMA_PRIORITY_HIGH = 2, /**< High priority */
|
|
DMA_PRIORITY_VERY_HIGH = 3, /**< Very high priority */
|
|
} dma_priority;
|
|
|
|
/**
|
|
* @brief Set the priority of a DMA transfer.
|
|
*
|
|
* You may not call this function while the tube is enabled.
|
|
*
|
|
* @param dev DMA device
|
|
* @param tube DMA tube
|
|
* @param priority priority to set.
|
|
*/
|
|
extern void dma_set_priority(dma_dev *dev, dma_tube tube,
|
|
dma_priority priority);
|
|
|
|
/**
|
|
* @brief Set the number of data transfers on a DMA tube.
|
|
*
|
|
* You may not call this function while the tube is enabled.
|
|
*
|
|
* @param dev DMA device
|
|
* @param tube Tube through which the transfer will occur.
|
|
* @param num_transfers Number of DMA transactions to set.
|
|
*/
|
|
extern void dma_set_num_transfers(dma_dev *dev, dma_tube tube,
|
|
uint16 num_transfers);
|
|
|
|
/**
|
|
* @brief Set the base memory address where data will be read from or
|
|
* written to.
|
|
*
|
|
* You must not call this function while the tube is enabled.
|
|
*
|
|
* If the DMA memory size is 16 bits, the address is automatically
|
|
* aligned to a half-word. If the DMA memory size is 32 bits, the
|
|
* address is aligned to a word.
|
|
*
|
|
* @param dev DMA Device
|
|
* @param tube Tube whose base memory address to set.
|
|
* @param address Memory base address to use.
|
|
*/
|
|
extern void dma_set_mem_addr(dma_dev *dev, dma_tube tube, __io void *address);
|
|
|
|
/**
|
|
* @brief Set the base peripheral address where data will be read from
|
|
* or written to.
|
|
*
|
|
* You must not call this function while the channel is enabled.
|
|
*
|
|
* If the DMA peripheral size is 16 bits, the address is automatically
|
|
* aligned to a half-word. If the DMA peripheral size is 32 bits, the
|
|
* address is aligned to a word.
|
|
*
|
|
* @param dev DMA Device
|
|
* @param tube Tube whose peripheral data register base address to set.
|
|
* @param address Peripheral memory base address to use.
|
|
*/
|
|
extern void dma_set_per_addr(dma_dev *dev, dma_tube tube, __io void *address);
|
|
|
|
/* Interrupt handling */
|
|
|
|
/**
|
|
* @brief Attach an interrupt to a DMA transfer.
|
|
*
|
|
* Interrupts are enabled using series-specific mode flags in
|
|
* dma_tube_cfg().
|
|
*
|
|
* @param dev DMA device
|
|
* @param tube Tube to attach handler to
|
|
* @param handler Interrupt handler to call when tube interrupt fires.
|
|
* @see dma_tube_cfg()
|
|
* @see dma_get_irq_cause()
|
|
* @see dma_detach_interrupt()
|
|
*/
|
|
extern void dma_attach_interrupt(dma_dev *dev, dma_tube tube,
|
|
void (*handler)(void));
|
|
|
|
|
|
/**
|
|
* @brief Detach a DMA transfer interrupt handler.
|
|
*
|
|
* After calling this function, the given tube's interrupts will be
|
|
* disabled.
|
|
*
|
|
* @param dev DMA device
|
|
* @param tube Tube whose handler to detach
|
|
* @sideeffect Clears the tube's interrupt enable bits.
|
|
* @see dma_attach_interrupt()
|
|
*/
|
|
extern void dma_detach_interrupt(dma_dev *dev, dma_tube tube);
|
|
|
|
/* Tube enable/disable */
|
|
|
|
/**
|
|
* @brief Enable a DMA tube.
|
|
*
|
|
* If the tube has been properly configured, calling this function
|
|
* allows it to start serving DMA requests.
|
|
*
|
|
* @param dev DMA device
|
|
* @param tube Tube to enable
|
|
* @see dma_tube_cfg()
|
|
*/
|
|
extern void dma_enable(dma_dev *dev, dma_tube tube);
|
|
|
|
/**
|
|
* @brief Disable a DMA channel.
|
|
*
|
|
* Calling this function makes the tube stop serving DMA requests.
|
|
*
|
|
* @param dev DMA device
|
|
* @param tube Tube to disable
|
|
*/
|
|
extern void dma_disable(dma_dev *dev, dma_tube tube);
|
|
|
|
/**
|
|
* @brief Check if a DMA tube is enabled.
|
|
* @param dev DMA device.
|
|
* @param tube Tube to check.
|
|
* @return 0 if the tube is disabled, >0 if it is enabled.
|
|
*/
|
|
static inline uint8 dma_is_enabled(dma_dev *dev, dma_tube tube);
|
|
|
|
/* Other conveniences */
|
|
|
|
/**
|
|
* @brief Obtain a pointer to an individual DMA tube's registers.
|
|
*
|
|
* Examples:
|
|
*
|
|
* - On STM32F1, dma_channel_regs(DMA1, DMA_CH1)->CCR is DMA1_BASE->CCR1.
|
|
*
|
|
* @param dev DMA device.
|
|
* @param tube DMA tube whose register map to obtain.
|
|
* @return (Series-specific) tube register map.
|
|
*/
|
|
static inline dma_tube_reg_map* dma_tube_regs(dma_dev *dev, dma_tube tube);
|
|
|
|
/**
|
|
* Encodes the reason why a DMA interrupt was called.
|
|
* @see dma_get_irq_cause()
|
|
*/
|
|
typedef enum dma_irq_cause {
|
|
DMA_TRANSFER_COMPLETE, /**< Transfer is complete. */
|
|
DMA_TRANSFER_HALF_COMPLETE, /**< Transfer is half complete. */
|
|
DMA_TRANSFER_ERROR, /**< Error occurred during transfer. */
|
|
DMA_TRANSFER_DME_ERROR, /**<
|
|
* @brief Direct mode error occurred during
|
|
* transfer. */
|
|
DMA_TRANSFER_FIFO_ERROR, /**< FIFO error occurred during transfer. */
|
|
} dma_irq_cause;
|
|
|
|
/**
|
|
* @brief Discover the reason why a DMA interrupt was called.
|
|
*
|
|
* You may only call this function within an attached interrupt
|
|
* handler for the given channel.
|
|
*
|
|
* This function resets the internal DMA register state which encodes
|
|
* the cause of the interrupt; consequently, it can only be called
|
|
* once per interrupt handler invocation.
|
|
*
|
|
* @param dev DMA device
|
|
* @param tube Tube whose interrupt is being handled.
|
|
* @return Reason why the interrupt fired.
|
|
* @sideeffect Clears flags in dev's interrupt status registers.
|
|
* @see dma_attach_interrupt()
|
|
* @see dma_irq_cause
|
|
*/
|
|
extern dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_tube tube);
|
|
|
|
/**
|
|
* @brief Get the ISR status bits for a DMA channel.
|
|
*
|
|
* The bits are returned right-aligned, in the order they appear in
|
|
* the corresponding ISR register.
|
|
*
|
|
* If you're trying to figure out why a DMA interrupt fired, you may
|
|
* find dma_get_irq_cause() more convenient.
|
|
*
|
|
* @param dev DMA device
|
|
* @param tube Tube whose ISR bits to return.
|
|
* @see dma_get_irq_cause().
|
|
*/
|
|
static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_tube tube);
|
|
|
|
/**
|
|
* @brief Clear the ISR status bits for a given DMA tube.
|
|
*
|
|
* If you're trying to clean up after yourself in a DMA interrupt, you
|
|
* may find dma_get_irq_cause() more convenient.
|
|
*
|
|
* @param dev DMA device
|
|
* @param tube Tube whose ISR bits to clear.
|
|
* @see dma_get_irq_cause()
|
|
*/
|
|
static inline void dma_clear_isr_bits(dma_dev *dev, dma_tube tube);
|
|
|
|
#ifdef __cplusplus
|
|
} // extern "C"
|
|
#endif
|
|
|
|
#endif
|