Initial commit

This commit is contained in:
2026-04-24 10:52:47 +09:00
commit 1707dc6349
1423 changed files with 1161776 additions and 0 deletions
+300
View File
@@ -0,0 +1,300 @@
# Changelog
All notable changes to this project are documented in this file.
## [1.9.0] - 2021-07-15
### Added
- Added high-drive pin configuration in the QSPI driver.
- Added report period setting of 1 sample in the QDEC HAL.
### Changed
- Updated MDK to version 8.40.3.
### Fixed
- Fixed register access sequence in the COMP driver.
- Fixed memory corruption when uninitialized channel was freed in the GPIOTE driver.
- Fixed a race condition in the NFCT driver when starting the transfer.
## [1.8.6] - 2020-08-31
### Added
- Implemented workaround for anomaly 223 in the USBD driver.
### Changed
- Updated MDK to version 8.35.0.
## [1.8.5] - 2020-07-09
### Added
- Implemented workaround for anomaly 211 in the USBD driver.
### Changed
- Updated MDK to version 8.32.3.
## [1.8.4] - 2020-04-27
- Fixed an issue in the NFCT driver where the FIELDDETECTED event would be ignored and the FIELDLOST event would be processed twice. The driver now properly handles FIELDDETECTED and FIELDLOST events.
## [1.8.3] - 2020-03-20
### Added
- Added documentation pages for nRF52820.
- Added possibility to use the nRF52833 DK in development for nRF52820. LEDs and buttons in this DK use GPIOs that are not present in the actual nRF52820 device, so accesses to these need special handling in the GPIO HAL.
### Fixed
- Fixed assertions that check input pin selections in the legacy SAADC driver. Now the VDDHDIV5 setting is handled properly.
- Fixed the number of machine cycles per single delay loop for nRF52820 in the nrfx_coredep module.
## [1.8.2] - 2020-03-05
### Added
- Added support for nRF52820.
- Added new implementation of the SAADC driver. The new version is enabled when the NRFX_SAADC_API_V2 symbol is defined, otherwise the legacy one is used.
- Introduced the NRFX_TWIM_NO_SPURIOUS_STOP_CHECK flag in the TWIM driver.
- Added function for getting the configuration of shortcuts in the TWIM HAL.
- Implemented workaround for nRF9160 anomaly 23 in the UARTE driver.
### Changed
- Updated MDK to version 8.32.1.
- Improved the UARTE driver to consume less current after the driver uninitialization. Now all clocks are disabled properly.
- Improved the GPIOTE driver robustness by setting the LATCH functionality to be used by default.
- Improved handling of spurious STOP condition in the TWIM driver.
- Removed support for revision Engineering A of nRF52840 in the USBD driver.
### Fixed
- Fixed assertions that check write addresses in the NVMC driver. Now the UICR memory region is handled properly.
- Fixed an issue in the TWI driver that would make the driver stuck when a premature STOP condition was generated by a slave device. The driver now handles this situation properly and signals that a bus error occurred.
- Fixed the stopping procedure in the PWM driver. Previously in very specific circumstances the PWM output might be not stopped at all or might be immediately restarted.
- Fixed a race condition in the CLOCK driver when requested clock was stopped during ramp-up from high priority interrupt.
- Fixed assertions that check pin numbers in the GPIO HAL and GPIOTE driver. Now noncontiguous groups of available pin numbers are handled properly.
## [1.8.1] - 2019-10-21
### Added
- Added functions in the GPIOTE driver for getting task or event for the specified GPIO pin.
### Changed
- Updated MDK to version 8.27.1.
- Moved the nrfx_gppi helper from helpers/nrfx_gppi/ to helpers/.
- Changed the interrupt initialization in the GPIOTE driver, so that mapping of the GPIOTEx_IRQn enumeration values is no longer needed for nRF9160.
## [1.8.0] - 2019-08-27
### Added
- Added support for nRF52833.
- Added bus recovery feature in the TWI and TWIM drivers.
- Added the nrfx_gppi helper layer to facilitate developing generic code that can utilize PPI or DPPI, depending on which interface is available in a given SoC.
### Changed
- Updated MDK to version 8.27.0.
### Fixed
- Fixed an issue in the TWIM driver that would make the driver stuck when a premature STOP condition was generated by a slave device. The driver now handles this situation properly and signals that a bus error occurred.
- Fixed a frame timing bug in the NFCT driver. Previously, the timing of the SENS_RES response could be violated after the NFCT peripheral was put to the Sleep state with the SLP_REQ command.
## [1.7.2] - 2019-07-25
### Added
- Added functions in the DPPI, GPIOTE, PPI, RTC, and TIMER HALs for getting tasks and events specified by index.
- Added the possibility of suspending transfers in the TWI driver. This allows combining several transfers into one continuous TWI transaction.
- Added termination of transfers at deinitialization of the UARTE driver.
- Added buffer alignment checks in the QSPI driver.
- Introduced the NRFX_OFFSETOF macro that duplicates the functionality of the built-in offsetof() mechanism, but can be used without issues also with non-constant expressions.
- Added an alternative way of ending the DMA transfer loop in the USBD driver.
- Added the CTSTARTED and CTSTOPPED events to the CLOCK HAL.
### Changed
- Removed an assertion that prevented setting the data payload size of isochronous endpoints to zero, to fulfill requirements of the USB 2.0 specification, paragraph 5.6.3.
- Declared the tx_buffer_length field in the UART driver's control block as volatile to prevent issues in case of compilation with high optimization level.
### Fixed
- Fixed an incorrect conversion of frequency values in the RADIO HAL.
- Fixed an incorrectly enabled interrupt in the QSPI driver.
- Corrected the LFCLK source selection values in the template configuration file for nRF9160.
- Fixed support for external LFCLK sources for nRF52811.
## [1.7.1] - 2019-04-08
### Added
- Added functions in the NVMC driver for getting the flash page size, the count of pages and the total flash size.
### Fixed
- Fixed handling of short unaligned write requests (1 or 2 bytes in length) in the nrfx_nvmc_bytes_write() function.
## [1.7.0] - 2019-03-29
### Added
- Added drivers for NVMC and TEMP.
- Added HALs: AAR and FICR.
- Added support for the custom instruction long frame mode in the QSPI driver.
### Changed
- Reworked HAL for NVMC. Now it can be used for all SoCs supported by nrfx.
- Reworked HAL for TEMP.
- Improved documentation. Now it is more precise and can be generated without warnings with newer versions of doxygen.
- Improved the UARTE driver to consume less current after the TX operation. Now at the end of the transmission the transmitter is turned off by the STOPTX task.
- Improved C++ support in drivers. Now fields in structures are filled up in the correct order.
- Changed to size_t the type used for holding the amount of data in the TWIS driver.
### Fixed
- Fixed a race condition in the USBD driver. It could occur when an IN transfer was interrupted by an OUT transaction, which in turn was interrupted by a process with a higher priority.
## [1.6.2] - 2019-02-12
### Added
- Added the possibility to use the macro NRFX_COREDEP_DELAY_US_LOOP_CYCLES to specify the number of cycles consumed by one iteration of the internal loop in the function nrfx_coredep_delay_us().
### Changed
- Updated MDK to version 8.24.1.
## [1.6.1] - 2019-01-29
### Fixed
- Fixed an issue in the NFCT driver that caused a performance loss on nRF52832. The interrupt configuration is now properly restored after the NRFX_NFCT_EVT_FIELD_LOST event.
## [1.6.0] - 2019-01-18
### Added
- Added support for nRF52811.
- Added support for the legacy peripherals SPI, TWI, and UART in nRF52810.
- Added support for SAMPLERATE in nrf_saadc.h.
- Added clearing of the STOPPED event in the nrfx_saadc_init() function to prevent driver deadlock in some cases.
- Added HALs: BPROT, MPU, MWU.
- Added function for reading the pin input buffer configuration in the GPIO HAL.
- Implemented workaround for nRF9160 anomaly 1 in the I2S driver.
### Changed
- Improved handling of hardware anomalies in the USBD driver.
- Updated MDK to version 8.23.1.
### Fixed
- Fixed the condition in NRFX_WAIT_FOR in the nrfx_saadc_abort() function. The macro now correctly waits for a stop of the driver.
- Fixed the pending interrupt clearing in NVIC in the nrfx_usbd_stop() function. The driver now correctly handles power management.
- Fixed the case when nrfx_uarte_tx_in_progress() function would return an incorrect value. The driver now correctly updates the tx_buffer_length variable internally.
## [1.5.0] - 2018-12-12
### Added
- Added support for nRF9160.
- Added allocator for DPPI.
- Added HALs: DPPI, KMU, REGULATORS, SPU, VMC.
- Added support for DPPI subscription and publishing in HALs related to nRF9160.
- Added support for instances 2 and 3 in SPIS, TWIM, TWIS, and UARTE drivers.
### Changed
- Updated MDK to version 8.21.1.
### Fixed
- Corrected NRFX_I2S_CONFIG_RATIO value in nrfx_config.h. It now correctly uses supported value.
## [1.4.0] - 2018-11-30
### Added
- Added the nrfx_is_word_aligned() function for checking whether an address is word-aligned.
- Added HAL for ACL.
- Added functions for disabling and re-enabling interrupts in the SWI driver.
- Added possibility to completely remove interrupt handling from the WDT driver.
### Changed
- Updated the documentation for the nrfx_uarte_rx() function. It now correctly reflects the actual behavior of the function.
### Fixed
- Corrected the type of the nrfx_uarte_xfer_evt_t structure field that holds the amount of transferred bytes.
- Corrected the way of disabling interrupts in the NFCT driver when moving the peripheral to the disabled state.
- Fixed a typo in the name of the bmRequest field in the nrfx_usbd_setup_t structure. The new correct name is bRequest.
- Fixed the nrfx_ppi_channel_fork_assign() function. It now accepts also pre-programmed channels.
- Fixed handling of long custom instruction responses in the QSPI driver.
- Fixed a bug affecting the conversion of time to ticks in the TIMER HAL.
## [1.3.1] - 2018-09-28
### Fixed
- Corrected the type of nrfx_usbd_ep_status_get() return value.
- Corrected calls to undefined macros in NFCT and USBD drivers.
## [1.3.0] - 2018-09-21
### Added
- Added HAL and driver for NFCT.
- Added driver for USBD.
- Added function for setting the burst mode in the SAADC HAL.
- Added the NRFX_ARRAY_SIZE macro.
### Changed
- Moved the implementation of nrfx_power_clock_irq_handler() to nrfx_power.c, removed nrfx_power_clock.c.
### Fixed
- Replaced ARRAY_SIZE macro calls with NRFX_ARRAY_SIZE ones.
## [1.2.0] - 2018-09-06
### Added
- Added function for checking if a specific channel is enabled in the GPIOTE HAL.
- Added support for using the QDEC driver without LED.
- Added functions for modifying only the event endpoint or only the task endpoint in the PPI HAL.
- Added function for reading the pin pull configuration in the GPIO HAL.
### Changed
- Corrected ISOSPLIT enumerator names in the USBD HAL.
### Fixed
- Fixed a double buffering bug that occurred in the UARTE driver after the RX abort.
- Fixed the TXRX transfers in the TWIM driver. They can now be started after transfers that are not ended with the stop condition.
## [1.1.0] - 2018-06-15
### Added
- Implemented workaround for nRF52832 and nRF52840 anomaly 194 in the I2S driver.
- Implemented workaround for nRF52840 anomaly 195 in the SPIM driver.
- Added HALs for CCM, ECB, and RADIO.
- Extended HALs for GPIO, PPI, SAADC, and USBD.
- Added support for external LFCLK sources.
### Changed
- Corrected handling of transfer lengths in the TWI driver.
- Updated MDK to version 8.17.0.
### Fixed
- Fixed logging in the PPI driver.
- Fixed SPIM interrupt definition for nRF52810.
- Fixed Slave Select configuration in the SPIM driver.
- Corrected default settings for NRF_SPIM3.
- Fixed a typo in the UARTE TXDRDY event definition.
- Corrected the TIMEOUT event clearing in the WDT interrupt handler.
## [1.0.0] - 2018-03-21
### Added
- Added the NRFX_WAIT_FOR macro to improve the time-out functionality in QSPI and SAADC drivers.
- Added glue layer macros for checking and modifying the pending status of interrupts.
- Added new enumeration values for interrupts and events in the UARTE HAL.
- Implemented workarounds for nRF52 anomalies 192 and 201 in the CLOCK driver.
- Implemented workaround for nRF52840 anomaly 122 in the QSPI driver.
- Implemented workaround for nRF52840 anomaly 198 in the SPIM driver.
### Changed
- Updated MDK to 8.16.0.
- Extended input pin configuration in the GPIOTE driver.
- Unified the way of checking if a required event handler was provided. Now, all drivers do it with assertions.
- Changed the RNG bias correction configuration option to be enabled by default.
- Refactored the ADC driver and HAL.
- Corrected assertions in the TIMER driver to make it usable in debug version with PPI.
- Improved buffer handling in the I2S driver. The API of the driver has been slightly modified.
- Enhanced SPIS driver API: added the "p_context" parameter, allowed NULL pointers for zero-length buffers.
### Fixed
- Fixed result value casting in the TEMP HAL.
- Fixed types of conversion result and buffer size in the ADC HAL and driver.
- Fixed time-out in the SAADC driver in abort function.
## [0.8.0] - 2017-12-20
### Added
- Added XIP support in the QSPI driver.
- Implemented Errata 132 in the CLOCK driver.
- Added function for checking if a TIMER instance is enabled.
- Added extended SPIM support.
### Changed
- Updated MDK to 8.15.0. Introduced Segger Embedded Studio startup files.
- Updated drivers: COMP, PWM, QDEC, SAADC, SPIS, TIMER, TWI, TWIS.
- Changed the type used for transfer lengths to 'size_t' in drivers: SPI, SPIM, SPIS, TWI, TWIM, TWIS, UART, UARTE. Introduced checking of EasyDMA transfers limits.
- Updated HALs: COMP, NVMC, UART, UARTE, USBD.
- Updated template files and documentation of configuration options.
### Fixed
- Fixed TWI and TWIM drivers so that they now support GPIOs from all ports.
- Fixed definitions related to compare channels in the TIMER HAL.
### Removed
- Removed the possibility of passing NULL instead of configuration to get default settings during drivers initialization.
- Removed support for UART1 and PRS box #5.
## [0.7.0] - 2017-10-20
### Added
- This CHANGELOG.md file.
- README.md file with simple description and explanations.
- HAL for: ADC, CLOCK, COMP, ECB, EGU, GPIO, GPIOTE, I2S, LPCOMP, NVMC, PDM, POWER, PPI, PWM, QDEC, QSPI, RNG, RTC, SAADC, SPI, SPIM, SPIS, ARM(R) SysTick, TEMP, TIMER, TWI, TWIM, TWIS, UART, UARTE, USBD, WDT.
- Drivers for: ADC, CLOCK, COMP, GPIOTE, I2S, LPCOMP, PDM, POWER, PWM, QDEC, QSPI, RNG, RTC, SAADC, SPI, SPIM, SPIS, ARM(R) SysTick, TIMER, TWI, TWIM, TWIS, UART, UARTE, WDT.
- Allocators for: PPI, SWI/EGU.
- MDK in version 8.14.0.
- Offline documentation for every added driver and simple integration description.
- Template integration files.
+39
View File
@@ -0,0 +1,39 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
+45
View File
@@ -0,0 +1,45 @@
# nrfx
## Overview
nrfx is a standalone set of drivers for peripherals present in Nordic
Semiconductor's SoCs. It originated as an extract from the nRF5 SDK.
The intention was to provide drivers that can be used in various environments
without the necessity to integrate other parts of the SDK into them.
For the user's convenience, the drivers come with the MDK package. This package
contains definitions of register structures and bitfields for all supported
SoCs, as well as startup and initialization files for them.
## Supported SoCs
* nRF51 Series
* nRF52810
* nRF52811
* nRF52820
* nRF52832
* nRF52833
* nRF52840
* nRF9160
## Directories
```
.
├── doc # Project documentation files
├── drivers # nrfx driver files
│ └── include # nrfx driver headers
│ └── src # nrfx driver sources
├── hal # Hardware Access Layer files
├── helpers # nrfx driver helper files
├── mdk # nRF MDK files
├── soc # SoC specific files
└── templates # Templates of nrfx integration files
```
## Generating documentation
nrfx documentation is available in the `doc\html` folder of the release package.
You can also generate documentation yourself from the source code. To do it, install doxygen
and run one of the scripts: `generate_html_doc.bat` or `generate_html_doc.sh`. Generated
documentation will be stored in the `doc\html` directory. Use `index.html` to open it.
@@ -0,0 +1,506 @@
.appliesto {background-color:#3D578C;color:#fff}
div.header
{
background-image:none;
background-color: #FFF;
border-bottom: 0px;
}
body, table, div, p, dl {
font-size: 16px;
font-family: Open Sans, Calibri, Arial, Sans-Serif;
color: #474747;
line-height: 20px;
}
a.code {
color: #1c99c7;
}
a.el {
font-weight: normal;
}
.contents a:visited, a:visited.code {
color: #16779a;
}
.title {
font-size: 1.34em
}
h1 {
font-size: 1.25em
}
h2 {
font-size: 1.15em
}
h3 {
font-size: 1.05em
}
h4 {
font-size: 1em
}
table.memberdecls, table.directory, table.memname {
margin:0px;
border:0px;
-moz-box-shadow: 0 0px 0px #d1d1d1;
-webkit-box-shadow: 0 0px 0px #d1d1d1;
box-shadow: 0 0px 0px #d1d1d1;
}
table.memberdecls tr {
padding-left:0px;
}
table.memberdecls tr:hover td, table.memname tr:hover td {
background: inherit;
}
table.directory tr.even, table.directory tr.odd {
background: inherit;
}
table.memberdecls td, table.directory td, table.directory td.desc {
border:0px;
padding: 2px 0px 0px;
}
table.memberdecls td.memSeparator {
background-color:#inherit;
padding:2px;
border-bottom: 1px dotted #DEE4F0;
}
.mdescLeft, .mdescRight,
.memItemLeft, .memItemRight,
.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
background-color: inherit;
}
div.levels {
display:none;
}
table.retval {
border:#ccc 1px solid;
}
table.memname td, table.params td, table.retval td {
padding:5px;
border:0px;
}
div.fragment div.line {
font-size: 14px;
line-height:18px;
}
table.fieldtable, table.params, table.retval {
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
}
table.fieldtable th {
border:none;
border-bottom:1px solid #A8B8D9;
}
table.blank, table.blank tr th, table.blank tr td {
border:none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
}
table.blank tr:hover td {
background: #ffffff;
}
#projectlogo
{
text-align: left;
vertical-align: middle;
border-collapse: separate;
}
#projectname
{
font-size: 40px;
font-family: Open Sans, Calibri, Arial, Sans-Serif;
margin: 0px;
padding: 2px 0px;
}
#projectbrief
{
font-size: 30px;
margin: 0px;
padding: 0px;
}
#titlearea
{
border-bottom: 1px solid #e0e0e0;
}
.label a, .item a
{
border-bottom: none;
}
#nav-tree {
background-image: none;
background-color: #FAFAFA;
}
div.contents {
margin-left: 30px;
margin-right: 30px;
}
div.header {
margin-left: 20px;
}
table td.doclinks a {
font-size: 12px;
font-style: italic;
color: #e97c25;
border: 1px solid #e97c25;
padding: 2px 5px;
text-decoration: none;
}
table td.docselected a {
background: #e97c25;
color: #fff;
}
table td.doclinkintro {
font-size: 12px;
font-style: italic;
}
/* nordic.css */
.p {
margin-top: .3em;
}
/* fix for table spacing */
td p.p {
margin: 0em;
padding: 0px;
}
dt.line_sep {
border-top: solid #c9c9c9 1px;
padding-top: 5px;
}
a
{
color: #1c99c7;
text-decoration: none;
border-bottom: 1px #e5e5e5 solid;
}
a:visited
{
color: #16779a;
}
a:hover
{
color: #none;
text-decoration: underline;
border: none;
}
a:active
{
}
ul.ul {
margin-top: 4px;
margin-bottom: 10px;
}
a[href*='.pdf'] {
background:transparent url(./pdf.png) center left no-repeat;
padding-left:22px;
line-height:18px;
}
a[href*='.zip'] {
background:transparent url(./zip_s.png) center left no-repeat;
padding-left:22px;
line-height:18px;
}
a[href*='.exe'] {
background:transparent url(./execute_s.png) center left no-repeat;
padding-left:22px;
line-height:18px;
}
a[href*='.msi'] {
background:transparent url(./msi_s.png) center left no-repeat;
padding-left:22px;
line-height:18px;
}
table a:link {
color: #1c99c7;
text-decoration: none;
border-bottom: 1px #e5e5e5 solid;
}
table a:visited {
color: #16779a;
}
table a:active,
table a:hover {
color: #none;
text-decoration: underline;
border: none;
}
table {
font-family:Calibri, Arial, Sans-Serif;
color:#474747;
font-size:16px;
margin-left: auto;
margin-right: auto;
border:#ccc 1px solid;
-moz-box-shadow: 0 1px 2px #d1d1d1;
-webkit-box-shadow: 0 1px 2px #d1d1d1;
box-shadow: 0 1px 2px #d1d1d1;
}
table th {
color: #000;
font-size: 18px;
font-weight: bold;
text-align: left;
padding:10px 15px 10px 10px;
border-top:1px solid #7eceed;
border-bottom:1px solid #7eceed;
border-right:1px solid #7eceed;
border-left:1px solid #7eceed;
background: #7eceed;
background: -webkit-gradient(linear, left top, left bottom, from(#7eceed), to(#7eceed));
background: -moz-linear-gradient(top, #7eceed, #7eceed);
}
table th.center {
text-align: center;
}
table tr {
text-align: left;
}
table td {
padding:5px 5px 5px 10px;
border-top: 1px solid #ffffff;
border-bottom:1px solid #e0e0e0;
border-left: 1px solid #e0e0e0;
border-right: 1px solid #e0e0e0;
}
table tr:hover td {
background: #ebebeb;
background: -webkit-gradient(linear, left top, left bottom, from(#f2f2f2), to(#f0f0f0));
background: -moz-linear-gradient(top, #f2f2f2, #f0f0f0);
}
img {
border: 0;
margin-left: auto;
margin-right: auto;
max-width:100%;
}
/* make svg files scale in IE. compatible with Dita OT v2.0
img:not(.png) {
width: 100%;
margin-left: auto;
margin-right: auto;
}
*/
/* make svg files scale in IE */
embed.image:not(.png):not(.gif):not(.jpg) {
width: 100%;
margin-left: auto;
margin-right: auto;
margin-bottom: 15px;
}
svg {
position: absolute;
top: 0;
left: 0;
}
caption {
caption-side: bottom;
text-align: center;
font-size: 100%;
font-weight: bold;
margin-top: 15px;
margin-bottom: 35px;
}
figdesc {
caption-side: bottom;
text-align: center;
font-size: 100%;
font-weight: bold;
margin-top: 15px;
margin-bottom: 20px;
}
/* to get figure captions to appear below the image and center */
div.fig {
display: table;
width: 100%;
margin-top: 10px;
margin-bottom: 55px;
}
div.fig span.figcap {
display:table-footer-group;
text-align:center;
font-size: 100%;
font-weight: bold;
margin-top: 10px;
margin-bottom: 20px;
font-style: normal;
}
div.fig div.imagecenter {
display:table-row-group;
}
/* fix to hide borders in image maps (Chrome only) */
img.map, map area{
outline: none;
}
/* fix placement of <sup>&reg;</sup> */
sup {
line-height: 1em;
}
.sdkversion span {
font-size: 12px;
font-style: italic;
color: #e97c25;
border: 1px solid #e97c25;
padding: 2px 5px;
}
.sdkversion {
text-align: right;
}
.whichSDs span,.whichnRF span {
font-size: 12px;
font-style: italic;
color: #e97c25;
border: 1px solid #e97c25;
padding: 2px 5px;
}
.whichSDs.nRF52 span,.whichnRF.nRF52 span {
color: #e97c25;
border-color: #e97c25;
}
.whichSDs.nRF52840 span,.whichnRF.nRF52840 span {
color: #0081B7;
border-color: #0081B7;
}
.whichSDs.nRF51 span,.whichnRF.nRF51 span {
color: #7f7f7f;
border-color: #7f7f7f;
}
div.whichnRF {
padding-bottom: 5px;
}
span.whichnRF{
font-size: 12px;
font-style: italic;
color: #e97c25;
border: 1px solid #e97c25;
padding: 2px 5px;
}
span.whichnRF.nRF52 {
color: #e97c25;
border-color: #e97c25;
}
span.whichnRF.nRF52840 {
color: #0081B7;
border-color: #0081B7;
}
span.whichnRF.nRF51 {
color: #7f7f7f;
border-color: #7f7f7f;
}
.orange {
color: #e97c25;
}
hr {
margin-top:20px;
border-top:1px solid #8EA7B0;
}
.directory td.entry {
white-space: normal;
width:50%;
}
/* overrides */
.topicfooter {
text-align: right;
// margin-top: 1px;
padding-right: 10px;
box-shadow: inset 0px 1px 0px 0px #e0e0e0;
font-size: 13px;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

+10
View File
@@ -0,0 +1,10 @@
<div id="nav-path" class="topicfooter">
<a href="https://github.com/NordicSemiconductor/nrfx/issues" target="_blank">nrfx feedback</a> | <a href="https://devzone.nordicsemi.com/" target="_blank">Nordic DevZone</a> | <a href="http://response.nordicsemi.com/subscribe-to-our-newsletters" target="_blank">Subscribe</a> | Updated <span id="date"/>
<script>
var date = new Date("$date" + " UTC");
document.getElementById("date").innerHTML = date.toJSON().slice(0, 10);
</script>
</div>
</body>
</html>
+58
View File
@@ -0,0 +1,58 @@
<!-- HTML header for doxygen 1.8.3.1-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen $doxygenversion"/>
<!--BEGIN PROJECT_NAME--><title>$projectname $projectnumber: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="$relpath^jquery.js"></script>
<script type="text/javascript" src="$relpath^dynsections.js"></script>
$treeview
$search
$mathjax
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet
<link href="$relpath^nordic.css" rel="stylesheet" type="text/css" />
<link rel="Shortcut icon" href="./favicon.ico" type="image/x-icon" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<!--BEGIN TITLEAREA-->
<div id="titlearea">
<table cellspacing="0" cellpadding="0" width="100%" class="blank">
<tbody>
<tr style="height: 56px;">
<!--BEGIN PROJECT_LOGO-->
<td id="projectlogo"><img alt="Nordic Semiconductor" src="$relpath^$projectlogo"/></td>
<!--END PROJECT_LOGO-->
<!--BEGIN PROJECT_NAME-->
<td style="padding-left: 0.5em;">
<div id="projectname">$projectname
<!--BEGIN PROJECT_NUMBER-->&#160;<span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
</div>
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
</td>
<!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME-->
<!--BEGIN PROJECT_BRIEF-->
<td style="padding-left: 0.5em;">
<div id="projectbrief">$projectbrief</div>
</td>
<!--END PROJECT_BRIEF-->
<!--END !PROJECT_NAME-->
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN SEARCHENGINE-->
<td>$searchbox</td>
<!--END SEARCHENGINE-->
<!--END DISABLE_INDEX-->
</tr>
</tbody>
</table>
</div>
<!--END TITLEAREA-->
<!-- end header part -->
+187
View File
@@ -0,0 +1,187 @@
<doxygenlayout version="1.0">
<!-- Navigation index tabs for HTML output -->
<navindex>
<tab type="mainpage" visible="yes" title="Home"/>
<tab type="pages" visible="yes" title="" intro=""/>
<tab type="modules" visible="yes" title="API Reference" intro=""/>
<tab type="namespaces" visible="no" title="">
<tab type="namespacelist" visible="yes" title="" intro=""/>
<tab type="namespacemembers" visible="yes" title="" intro=""/>
</tab>
<tab type="usergroup" visible="yes" title="Data Structures">
<tab type="classlist" visible="yes" title="" intro=""/>
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
<tab type="hierarchy" visible="no" title="" intro=""/>
<tab type="classmembers" visible="yes" title="" intro=""/>
</tab>
<tab type="files" visible="no" title="">
<tab type="filelist" visible="yes" title="" intro=""/>
<tab type="globals" visible="yes" title="" intro=""/>
</tab>
<tab type="examples" visible="yes" title="Source" intro=""/>
</navindex>
<!-- Layout definition for a class page -->
<class>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<inheritancegraph visible="$CLASS_GRAPH"/>
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
<memberdecl>
<nestedclasses visible="yes" title=""/>
<publictypes title=""/>
<publicslots title=""/>
<signals title=""/>
<publicmethods title=""/>
<publicstaticmethods title=""/>
<publicattributes title=""/>
<publicstaticattributes title=""/>
<protectedtypes title=""/>
<protectedslots title=""/>
<protectedmethods title=""/>
<protectedstaticmethods title=""/>
<protectedattributes title=""/>
<protectedstaticattributes title=""/>
<packagetypes title=""/>
<packagemethods title=""/>
<packagestaticmethods title=""/>
<packageattributes title=""/>
<packagestaticattributes title=""/>
<properties title=""/>
<events title=""/>
<privatetypes title=""/>
<privateslots title=""/>
<privatemethods title=""/>
<privatestaticmethods title=""/>
<privateattributes title=""/>
<privatestaticattributes title=""/>
<friends title=""/>
<related title="" subtitle=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<constructors title=""/>
<functions title=""/>
<related title=""/>
<variables title=""/>
<properties title=""/>
<events title=""/>
</memberdef>
<allmemberslink visible="yes"/>
<usedfiles visible="$SHOW_USED_FILES"/>
<authorsection visible="yes"/>
</class>
<!-- Layout definition for a namespace page -->
<namespace>
<briefdescription visible="yes"/>
<memberdecl>
<nestednamespaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection visible="yes"/>
</namespace>
<!-- Layout definition for a file page -->
<file>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<includegraph visible="$INCLUDE_GRAPH"/>
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
<sourcelink visible="yes"/>
<memberdecl>
<classes visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection/>
</file>
<!-- Layout definition for a group page -->
<group>
<briefdescription visible="yes"/>
<groupgraph visible="$GROUP_GRAPHS"/>
<memberdecl>
<nestedgroups visible="yes" title=""/>
<dirs visible="yes" title=""/>
<files visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<pagedocs/>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
</memberdef>
<authorsection visible="yes"/>
</group>
<!-- Layout definition for a directory page -->
<directory>
<briefdescription visible="yes"/>
<directorygraph visible="yes"/>
<memberdecl>
<dirs visible="yes"/>
<files visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
</directory>
</doxygenlayout>
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

+55
View File
@@ -0,0 +1,55 @@
/**
@page nrfx_drv_supp_matrix Driver support matrix
The following matrix shows which drivers are supported by specific Nordic SoCs.
@{
Driver | nRF51 Series | nRF52810/nRF52811 | nRF52820 | nRF52832 | nRF52833 | nRF52840 | nRF9160 |
-----------------|--------------|-------------------| -------------| -------------| -------------| -------------| -------------|
@ref nrf_aar |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_adc |@tagGreenTick |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |
@ref nrf_acl |@tagRedCross |@tagRedCross |@tagGreenTick |@tagRedCross |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_bprot |@tagRedCross |@tagGreenTick |@tagRedCross |@tagGreenTick |@tagRedCross |@tagRedCross |@tagRedCross |
@ref nrf_ccm |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_clock |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_comp |@tagRedCross |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_dppi |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagGreenTick |
@ref nrf_ecb |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_ficr |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_gpio |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_gpiote |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_i2s |@tagRedCross |@tagRedCross |@tagRedCross |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_kmu |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagGreenTick |
@ref nrf_lpcomp |@tagGreenTick |@tagRedCross |@tagRedCross |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_mpu |@tagGreenTick |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |
@ref nrf_mwu |@tagRedCross |@tagRedCross |@tagRedCross |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_nfct |@tagRedCross |@tagRedCross |@tagRedCross |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_nvmc |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_pdm |@tagRedCross |@tagGreenTick |@tagRedCross |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_power |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_ppi |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_pwm |@tagRedCross |@tagGreenTick |@tagRedCross |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_qdec |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_qspi |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagGreenTick |@tagRedCross |
@ref nrf_radio |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_rng |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_rtc |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_saadc |@tagRedCross |@tagGreenTick |@tagRedCross |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_spi |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_spim |@tagRedCross |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_spis |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_spu |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagGreenTick |
@ref nrf_systick |@tagRedCross |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_swi_egu |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_temp |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_timer |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_twi |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_twim |@tagRedCross |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_twis |@tagRedCross |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_uart |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_uarte |@tagRedCross |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@ref nrf_usbd |@tagRedCross |@tagRedCross |@tagGreenTick |@tagRedCross |@tagGreenTick |@tagGreenTick |@tagRedCross |
@ref nrf_vmc |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagRedCross |@tagGreenTick |
@ref nrf_wdt |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick |
@}
*/
+2
View File
@@ -0,0 +1,2 @@
del html\*.* /Q
doxygen nrfx.doxyfile
+2
View File
@@ -0,0 +1,2 @@
rm -rf html
doxygen nrfx.doxyfile
+89
View File
@@ -0,0 +1,89 @@
/**
@mainpage Introduction
@em nrfx is a standalone set of drivers for peripherals present in Nordic
Semiconductor's SoCs. It originated as an extract from the nRF5 SDK.
The intention was to provide drivers that can be used in various environments
without the necessity to integrate other parts of the SDK into them.
For the user's convenience, the drivers come with the MDK package. This package
contains definitions of register structures and bitfields for all supported
SoCs, as well as startup and initialization files for them.
Refer to the @ref nrfx_drv_supp_matrix to check which drivers are suitable
for a given SoC.
@section nrfx_integration Integration
The purpose of @em nrfx is to make it possible to use the same set of peripheral
drivers in various environments, from RTOSes to bare metal applications.
Hence, for a given host environment, a light integration layer must be provided
that implements certain specific routines, like interrupt management, critical
sections, assertions, or logging. This is done by filling a predefined set of
macros with proper implementations (or keeping some empty if desired) in files
named:
- @ref nrfx_glue
- @ref nrfx_log
Templates of these files are provided
in the <a href="../../templates/">templates</a> subfolder. Their customized
versions can be placed in any location within the host environment that the
used compiler can access via include paths.
In addition, the following locations should be specified as include paths
([nrfx] stands for the @em nrfx root folder location):
@code
[nrfx]/
[nrfx]/drivers/include
[nrfx]/mdk
@endcode
@section nrfx_irq_handlers IRQ handlers
The IRQ handlers in all drivers are implemented as ordinary API functions
named "nrfx_*_irq_handler". They can be bound to some structures or called in
a specific way according to the requirements of the host environment.
To install the handlers in the standard MDK way, you must only add the following
line to the @ref nrfx_glue file:
@code
#include <soc/nrfx_irqs.h>
@endcode
This will cause the preprocessor to properly rename all the IRQ handler
functions so that the linker could install them in the vector table.
@section nrfx_configuration Configuration
The drivers use both dynamic (run time) and static (compile time) configuration.
Dynamic configuration is done by specifying desired options in configuration
structures passed to the drivers during their initialization.
Refer to the API reference for a given driver to see the members of its
configuration structure.
Static configuration allows enabling and disabling (excluding their code from
compilation) particular drivers or in some cases their specific features,
defining default parameters for dynamic configuration, parametrization of
logging in particular drivers. It is done by specifying desired values of macros
in a file named:
- nrfx_config.h
This file, similarly to the integration files mentioned above, can be placed
in any suitable location within the host environment.
The <a href="../../templates/">templates</a> subfolder contains templates of
configuration files for all currently supported Nordic SoCs placed in respective
subfolders.
Refer to the "driver configuration" section in the API reference for a given
driver for more information regarding configuration options available for it.
@section nrfx_additional_reqs Additional requirements
Nordic SoCs are based on ARM® Cortex™-M series processors. Before you can
start developing with @em nrfx, you must add the CMSIS header files to include
paths during the compilation process. Download these files from the following
website:
- <a href="https://github.com/ARM-software/CMSIS"> ARM® CMSIS repository</a>
(CMSIS/Include directory)
*/
+56
View File
@@ -0,0 +1,56 @@
/**
@page nrf51_series_drivers nRF51 Series Drivers
@{
@ref nrf_aar
@ref nrf_adc
@ref nrf_ccm
@ref nrf_clock
@ref nrf_ecb
@ref nrf_ficr
@ref nrf_gpio
@ref nrf_gpiote
@ref nrf_lpcomp
@ref nrf_mpu
@ref nrf_nvmc
@ref nrf_power
@ref nrf_ppi
@ref nrf_qdec
@ref nrf_radio
@ref nrf_rng
@ref nrf_rtc
@ref nrf_spi
@ref nrf_spis
@ref nrf_swi_egu
@ref nrf_temp
@ref nrf_timer
@ref nrf_twi
@ref nrf_uart
@ref nrf_wdt
@}
*/
+70
View File
@@ -0,0 +1,70 @@
/**
@page nrf52810_drivers nRF52810/nRF52811 Drivers
@{
@ref nrf_aar
@ref nrf_bprot
@ref nrf_ccm
@ref nrf_clock
@ref nrf_comp
@ref nrf_ecb
@ref nrf_ficr
@ref nrf_gpio
@ref nrf_gpiote
@ref nrf_nvmc
@ref nrf_pdm
@ref nrf_power
@ref nrf_ppi
@ref nrf_pwm
@ref nrf_qdec
@ref nrf_radio
@ref nrf_rng
@ref nrf_rtc
@ref nrf_saadc
@ref nrf_spi
@ref nrf_spim
@ref nrf_spis
@ref nrf_systick
@ref nrf_swi_egu
@ref nrf_temp
@ref nrf_timer
@ref nrf_twi
@ref nrf_twim
@ref nrf_twis
@ref nrf_uart
@ref nrf_uarte
@ref nrf_wdt
@}
*/
+66
View File
@@ -0,0 +1,66 @@
/**
@page nrf52820_drivers nRF52820 Drivers
@{
@ref nrf_aar
@ref nrf_acl
@ref nrf_ccm
@ref nrf_clock
@ref nrf_comp
@ref nrf_ecb
@ref nrf_ficr
@ref nrf_gpio
@ref nrf_gpiote
@ref nrf_nvmc
@ref nrf_power
@ref nrf_ppi
@ref nrf_qdec
@ref nrf_radio
@ref nrf_rng
@ref nrf_rtc
@ref nrf_spi
@ref nrf_spim
@ref nrf_spis
@ref nrf_systick
@ref nrf_swi_egu
@ref nrf_temp
@ref nrf_timer
@ref nrf_twi
@ref nrf_twim
@ref nrf_twis
@ref nrf_uart
@ref nrf_uarte
@ref nrf_usbd
@ref nrf_wdt
@}
*/
+78
View File
@@ -0,0 +1,78 @@
/**
@page nrf52832_drivers nRF52832 Drivers
@{
@ref nrf_aar
@ref nrf_bprot
@ref nrf_ccm
@ref nrf_clock
@ref nrf_comp
@ref nrf_ecb
@ref nrf_ficr
@ref nrf_gpio
@ref nrf_gpiote
@ref nrf_i2s
@ref nrf_lpcomp
@ref nrf_mwu
@ref nrf_nfct
@ref nrf_nvmc
@ref nrf_pdm
@ref nrf_power
@ref nrf_ppi
@ref nrf_pwm
@ref nrf_qdec
@ref nrf_radio
@ref nrf_rng
@ref nrf_rtc
@ref nrf_saadc
@ref nrf_spi
@ref nrf_spim
@ref nrf_spis
@ref nrf_systick
@ref nrf_swi_egu
@ref nrf_temp
@ref nrf_timer
@ref nrf_twi
@ref nrf_twim
@ref nrf_twis
@ref nrf_uart
@ref nrf_uarte
@ref nrf_wdt
@}
*/
+80
View File
@@ -0,0 +1,80 @@
/**
@page nrf52833_drivers nRF52833 Drivers
@{
@ref nrf_aar
@ref nrf_acl
@ref nrf_ccm
@ref nrf_clock
@ref nrf_comp
@ref nrf_ecb
@ref nrf_ficr
@ref nrf_gpio
@ref nrf_gpiote
@ref nrf_i2s
@ref nrf_lpcomp
@ref nrf_mwu
@ref nrf_nfct
@ref nrf_nvmc
@ref nrf_pdm
@ref nrf_power
@ref nrf_ppi
@ref nrf_pwm
@ref nrf_qdec
@ref nrf_radio
@ref nrf_rng
@ref nrf_rtc
@ref nrf_saadc
@ref nrf_spi
@ref nrf_spim
@ref nrf_spis
@ref nrf_systick
@ref nrf_swi_egu
@ref nrf_temp
@ref nrf_timer
@ref nrf_twi
@ref nrf_twim
@ref nrf_twis
@ref nrf_uart
@ref nrf_uarte
@ref nrf_usbd
@ref nrf_wdt
@}
*/
+82
View File
@@ -0,0 +1,82 @@
/**
@page nrf52840_drivers nRF52840 Drivers
@{
@ref nrf_aar
@ref nrf_acl
@ref nrf_ccm
@ref nrf_clock
@ref nrf_comp
@ref nrf_ecb
@ref nrf_ficr
@ref nrf_gpio
@ref nrf_gpiote
@ref nrf_i2s
@ref nrf_lpcomp
@ref nrf_mwu
@ref nrf_nfct
@ref nrf_nvmc
@ref nrf_pdm
@ref nrf_power
@ref nrf_ppi
@ref nrf_pwm
@ref nrf_qdec
@ref nrf_qspi
@ref nrf_radio
@ref nrf_rng
@ref nrf_rtc
@ref nrf_saadc
@ref nrf_spi
@ref nrf_spim
@ref nrf_spis
@ref nrf_systick
@ref nrf_swi_egu
@ref nrf_temp
@ref nrf_timer
@ref nrf_twi
@ref nrf_twim
@ref nrf_twis
@ref nrf_uart
@ref nrf_uarte
@ref nrf_usbd
@ref nrf_wdt
@}
*/
+54
View File
@@ -0,0 +1,54 @@
/**
@page nrf9160_drivers nRF9160 drivers
@{
@ref nrf_clock
@ref nrf_systick
@ref nrf_dppi
@ref nrf_ficr
@ref nrf_gpio
@ref nrf_gpiote
@ref nrf_i2s
@ref nrf_kmu
@ref nrf_nvmc
@ref nrf_pdm
@ref nrf_power
@ref nrf_pwm
@ref nrf_rtc
@ref nrf_saadc
@ref nrf_spim
@ref nrf_spis
@ref nrf_spu
@ref nrf_swi_egu
@ref nrf_timer
@ref nrf_twim
@ref nrf_twis
@ref nrf_uarte
@ref nrf_vmc
@ref nrf_wdt
@}
*/
File diff suppressed because it is too large Load Diff
+98
View File
@@ -0,0 +1,98 @@
/**
@defgroup nrfx_drivers Drivers
@{
@brief List of all drivers available in nrfx.
@defgroup nrf_aar AAR
@defgroup nrf_adc ADC
@defgroup nrf_acl ACL
@defgroup nrf_bprot BPROT
@defgroup nrf_ccm CCM
@defgroup nrf_clock CLOCK
@defgroup nrf_comp COMP
@defgroup nrf_dppi DPPI
@defgroup nrf_ecb ECB
@defgroup nrf_ficr FICR
@defgroup nrf_gpio GPIO
@defgroup nrf_gpiote GPIOTE
@defgroup nrf_i2s I2S
@defgroup nrf_kmu KMU
@defgroup nrf_lpcomp LPCOMP
@defgroup nrf_mpu MPU
@defgroup nrf_mwu MWU
@defgroup nrf_nfct NFCT
@defgroup nrf_nvmc NVMC
@defgroup nrf_pdm PDM
@defgroup nrf_power POWER
@defgroup nrf_ppi PPI
@defgroup nrf_pwm PWM
@defgroup nrf_qdec QDEC
@defgroup nrf_qspi QSPI
@defgroup nrf_radio RADIO
@defgroup nrf_rng RNG
@defgroup nrf_rtc RTC
@defgroup nrf_saadc SAADC
@defgroup nrf_spi SPI
@defgroup nrf_spim SPIM
@defgroup nrf_spis SPIS
@defgroup nrf_spu SPU
@defgroup nrf_systick Cortex-M Systick
@defgroup nrf_swi_egu SWI/EGU
@defgroup nrf_temp TEMP
@defgroup nrf_timer TIMER
@defgroup nrf_twi TWI
@defgroup nrf_twim TWIM
@defgroup nrf_twis TWIS
@defgroup nrf_uart UART
@defgroup nrf_uarte UARTE
@defgroup nrf_usbd USBD
@defgroup nrf_vmc VMC
@defgroup nrf_wdt WDT
@}
@defgroup nrfx nrfx API
*/
+159
View File
@@ -0,0 +1,159 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_BITMASK_H
#define NRF_BITMASK_H
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_bitmask Bitmask module
* @{
* @ingroup nrfx
* @brief Bitmask managing module.
*/
/** @brief Macro for getting index of byte in byte stream where @c abs_bit is put. */
#define BITMASK_BYTE_GET(abs_bit) ((abs_bit)/8)
/** @brief Macro for getting relative index of bit in byte. */
#define BITMASK_RELBIT_GET(abs_bit) ((abs_bit) & 0x00000007)
/**
* @brief Function for checking if bit in the multi-byte bit mask is set.
*
* @param[in] bit Bit index.
* @param[in] p_mask Pointer to mask with bit fields.
*
* @return 0 if bit is not set, positive value otherwise.
*/
__STATIC_INLINE uint32_t nrf_bitmask_bit_is_set(uint32_t bit, void const * p_mask)
{
uint8_t const * p_mask8 = (uint8_t const *)p_mask;
uint32_t byte_idx = BITMASK_BYTE_GET(bit);
bit = BITMASK_RELBIT_GET(bit);
return (1 << bit) & p_mask8[byte_idx];
}
/**
* @brief Function for setting a bit in the multi-byte bit mask.
*
* @param[in] bit Bit index.
* @param[in] p_mask Pointer to mask with bit fields.
*/
__STATIC_INLINE void nrf_bitmask_bit_set(uint32_t bit, void * p_mask)
{
uint8_t * p_mask8 = (uint8_t *)p_mask;
uint32_t byte_idx = BITMASK_BYTE_GET(bit);
bit = BITMASK_RELBIT_GET(bit);
p_mask8[byte_idx] |= (1 << bit);
}
/**
* @brief Function for clearing a bit in the multi-byte bit mask.
*
* @param[in] bit Bit index.
* @param[in] p_mask Pointer to mask with bit fields.
*/
__STATIC_INLINE void nrf_bitmask_bit_clear(uint32_t bit, void * p_mask)
{
uint8_t * p_mask8 = (uint8_t *)p_mask;
uint32_t byte_idx = BITMASK_BYTE_GET(bit);
bit = BITMASK_RELBIT_GET(bit);
p_mask8[byte_idx] &= ~(1 << bit);
}
/**
* @brief Function for performing bitwise OR operation on two multi-byte bit masks.
*
* @param[in] p_mask1 Pointer to the first bit mask.
* @param[in] p_mask2 Pointer to the second bit mask.
* @param[in] p_out_mask Pointer to the output bit mask.
* @param[in] length Length of output mask in bytes.
*/
__STATIC_INLINE void nrf_bitmask_masks_or(void const * p_mask1,
void const * p_mask2,
void * p_out_mask,
uint32_t length)
{
uint8_t const * p_mask8_1 = (uint8_t const *)p_mask1;
uint8_t const * p_mask8_2 = (uint8_t const *)p_mask2;
uint8_t * p_mask8_out = (uint8_t *)p_out_mask;
uint32_t i;
for (i = 0; i < length; i++)
{
p_mask8_out[i] = p_mask8_1[i] | p_mask8_2[i];
}
}
/**
* @brief Function for performing bitwise AND operation on two multi-byte bit masks.
*
* @param[in] p_mask1 Pointer to the first bit mask.
* @param[in] p_mask2 Pointer to the second bit mask.
* @param[in] p_out_mask Pointer to the output bit mask.
* @param[in] length Length of output mask in bytes.
*/
__STATIC_INLINE void nrf_bitmask_masks_and(void const * p_mask1,
void const * p_mask2,
void * p_out_mask,
uint32_t length)
{
uint8_t const * p_mask8_1 = (uint8_t const *)p_mask1;
uint8_t const * p_mask8_2 = (uint8_t const *)p_mask2;
uint8_t * p_mask8_out = (uint8_t *)p_out_mask;
uint32_t i;
for (i = 0; i < length; i++)
{
p_mask8_out[i] = p_mask8_1[i] & p_mask8_2[i];
}
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_BITMASK_H
+206
View File
@@ -0,0 +1,206 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_CLOCK_H__
#define NRFX_CLOCK_H__
#include <nrfx.h>
#include <hal/nrf_clock.h>
#include <nrfx_power_clock.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_clock CLOCK driver
* @{
* @ingroup nrf_clock
* @brief CLOCK peripheral driver.
*/
/** @brief Clock events. */
typedef enum
{
NRFX_CLOCK_EVT_HFCLK_STARTED, ///< HFCLK has been started.
NRFX_CLOCK_EVT_LFCLK_STARTED, ///< LFCLK has been started.
NRFX_CLOCK_EVT_CTTO, ///< Calibration timeout.
NRFX_CLOCK_EVT_CAL_DONE ///< Calibration has been done.
} nrfx_clock_evt_type_t;
/**
* @brief Clock event handler.
*
* @param[in] event Event.
*/
typedef void (*nrfx_clock_event_handler_t)(nrfx_clock_evt_type_t event);
/**
* @brief Function for initializing internal structures in the nrfx_clock module.
*
* After initialization, the module is in power off state (clocks are not started).
*
* @param[in] event_handler Event handler provided by the user.
* Must not be NULL.
*
* @retval NRFX_SUCCESS The procedure is successful.
* @retval NRFX_ERROR_ALREADY_INITIALIZED The driver is already initialized.
*/
nrfx_err_t nrfx_clock_init(nrfx_clock_event_handler_t event_handler);
/** @brief Function for enabling interrupts in the clock module. */
void nrfx_clock_enable(void);
/** @brief Function for disabling interrupts in the clock module. */
void nrfx_clock_disable(void);
/** @brief Function for uninitializing the clock module. */
void nrfx_clock_uninit(void);
/** @brief Function for starting the LFCLK. */
void nrfx_clock_lfclk_start(void);
/** @brief Function for stopping the LFCLK. */
void nrfx_clock_lfclk_stop(void);
/**
* @brief Function for checking the LFCLK state.
*
* @retval true The LFCLK is running.
* @retval false The LFCLK is not running.
*/
__STATIC_INLINE bool nrfx_clock_lfclk_is_running(void);
/** @brief Function for starting the high-accuracy source HFCLK. */
void nrfx_clock_hfclk_start(void);
/** @brief Function for stopping the external high-accuracy source HFCLK. */
void nrfx_clock_hfclk_stop(void);
/**
* @brief Function for checking the HFCLK state.
*
* @retval true The HFCLK is running (XTAL source).
* @retval false The HFCLK is not running.
*/
__STATIC_INLINE bool nrfx_clock_hfclk_is_running(void);
/**
* @brief Function for starting the calibration of internal LFCLK.
*
* This function starts the calibration process. The process cannot be aborted. LFCLK and HFCLK
* must be running before this function is called.
*
* @retval NRFX_SUCCESS The procedure is successful.
* @retval NRFX_ERROR_INVALID_STATE The low-frequency of high-frequency clock is off.
* @retval NRFX_ERROR_BUSY Clock is in the calibration phase.
*/
nrfx_err_t nrfx_clock_calibration_start(void);
/**
* @brief Function for checking if calibration is in progress.
*
* This function indicates that the system is in calibration phase.
*
* @retval NRFX_SUCCESS The procedure is successful.
* @retval NRFX_ERROR_BUSY Clock is in the calibration phase.
*/
nrfx_err_t nrfx_clock_is_calibrating(void);
/**
* @brief Function for starting calibration timer.
*
* @param[in] interval Time after which the CTTO event and interrupt will be generated (in 0.25 s units).
*/
void nrfx_clock_calibration_timer_start(uint8_t interval);
/** @brief Function for stopping the calibration timer. */
void nrfx_clock_calibration_timer_stop(void);
/**@brief Function for returning a requested task address for the clock driver module.
*
* @param[in] task One of the peripheral tasks.
*
* @return Task address.
*/
__STATIC_INLINE uint32_t nrfx_clock_ppi_task_addr(nrf_clock_task_t task);
/**@brief Function for returning a requested event address for the clock driver module.
*
* @param[in] event One of the peripheral events.
*
* @return Event address.
*/
__STATIC_INLINE uint32_t nrfx_clock_ppi_event_addr(nrf_clock_event_t event);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE uint32_t nrfx_clock_ppi_task_addr(nrf_clock_task_t task)
{
return nrf_clock_task_address_get(task);
}
__STATIC_INLINE uint32_t nrfx_clock_ppi_event_addr(nrf_clock_event_t event)
{
return nrf_clock_event_address_get(event);
}
__STATIC_INLINE bool nrfx_clock_hfclk_is_running(void)
{
return nrf_clock_hf_is_running(NRF_CLOCK_HFCLK_HIGH_ACCURACY);
}
__STATIC_INLINE bool nrfx_clock_lfclk_is_running(void)
{
return nrf_clock_lf_is_running();
}
#endif //SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
void nrfx_clock_irq_handler(void);
#ifdef __cplusplus
}
#endif
#endif // NRFX_CLOCK_H__
+494
View File
@@ -0,0 +1,494 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_GPIOTE_H__
#define NRFX_GPIOTE_H__
#include <nrfx.h>
#include <hal/nrf_gpiote.h>
#include <hal/nrf_gpio.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_gpiote GPIOTE driver
* @{
* @ingroup nrf_gpiote
* @brief GPIO Task Event (GPIOTE) peripheral driver.
*/
/** @brief Input pin configuration. */
typedef struct
{
nrf_gpiote_polarity_t sense; /**< Transition that triggers the interrupt. */
nrf_gpio_pin_pull_t pull; /**< Pulling mode. */
bool is_watcher : 1; /**< True when the input pin is tracking an output pin. */
bool hi_accuracy : 1; /**< True when high accuracy (IN_EVENT) is used. */
bool skip_gpio_setup : 1; /**< Do not change GPIO configuration */
} nrfx_gpiote_in_config_t;
/**
* @brief Macro for configuring a pin to use a GPIO IN or PORT EVENT to detect low-to-high transition.
* @details Set hi_accu to true to use IN_EVENT.
*/
#define NRFX_GPIOTE_CONFIG_IN_SENSE_LOTOHI(hi_accu) \
{ \
.sense = NRF_GPIOTE_POLARITY_LOTOHI, \
.pull = NRF_GPIO_PIN_NOPULL, \
.is_watcher = false, \
.hi_accuracy = hi_accu, \
.skip_gpio_setup = false, \
}
/**
* @brief Macro for configuring a pin to use a GPIO IN or PORT EVENT to detect high-to-low transition.
* @details Set hi_accu to true to use IN_EVENT.
*/
#define NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(hi_accu) \
{ \
.sense = NRF_GPIOTE_POLARITY_HITOLO, \
.pull = NRF_GPIO_PIN_NOPULL, \
.is_watcher = false, \
.hi_accuracy = hi_accu, \
.skip_gpio_setup = false, \
}
/**
* @brief Macro for configuring a pin to use a GPIO IN or PORT EVENT to detect any change on the pin.
* @details Set hi_accu to true to use IN_EVENT.
*/
#define NRFX_GPIOTE_CONFIG_IN_SENSE_TOGGLE(hi_accu) \
{ \
.sense = NRF_GPIOTE_POLARITY_TOGGLE, \
.pull = NRF_GPIO_PIN_NOPULL, \
.is_watcher = false, \
.hi_accuracy = hi_accu, \
.skip_gpio_setup = false, \
}
/**
* @brief Macro for configuring a pin to use a GPIO IN or PORT EVENT to detect low-to-high transition.
* @details Set hi_accu to true to use IN_EVENT.
* @note This macro prepares configuration that skips the GPIO setup.
*/
#define NRFX_GPIOTE_RAW_CONFIG_IN_SENSE_LOTOHI(hi_accu) \
{ \
.sense = NRF_GPIOTE_POLARITY_LOTOHI, \
.pull = NRF_GPIO_PIN_NOPULL, \
.is_watcher = false, \
.hi_accuracy = hi_accu, \
.skip_gpio_setup = true, \
}
/**
* @brief Macro for configuring a pin to use a GPIO IN or PORT EVENT to detect high-to-low transition.
* @details Set hi_accu to true to use IN_EVENT.
* @note This macro prepares configuration that skips the GPIO setup.
*/
#define NRFX_GPIOTE_RAW_CONFIG_IN_SENSE_HITOLO(hi_accu) \
{ \
.sense = NRF_GPIOTE_POLARITY_HITOLO, \
.pull = NRF_GPIO_PIN_NOPULL, \
.is_watcher = false, \
.hi_accuracy = hi_accu, \
.skip_gpio_setup = true, \
}
/**
* @brief Macro for configuring a pin to use a GPIO IN or PORT EVENT to detect any change on the pin.
* @details Set hi_accu to true to use IN_EVENT.
* @note This macro prepares configuration that skips the GPIO setup.
*/
#define NRFX_GPIOTE_RAW_CONFIG_IN_SENSE_TOGGLE(hi_accu) \
{ \
.sense = NRF_GPIOTE_POLARITY_TOGGLE, \
.pull = NRF_GPIO_PIN_NOPULL, \
.is_watcher = false, \
.hi_accuracy = hi_accu, \
.skip_gpio_setup = true, \
}
/** @brief Output pin configuration. */
typedef struct
{
nrf_gpiote_polarity_t action; /**< Configuration of the pin task. */
nrf_gpiote_outinit_t init_state; /**< Initial state of the output pin. */
bool task_pin; /**< True if the pin is controlled by a GPIOTE task. */
} nrfx_gpiote_out_config_t;
/** @brief Macro for configuring a pin to use as output. GPIOTE is not used for the pin. */
#define NRFX_GPIOTE_CONFIG_OUT_SIMPLE(init_high) \
{ \
.action = NRF_GPIOTE_POLARITY_LOTOHI, \
.init_state = init_high ? NRF_GPIOTE_INITIAL_VALUE_HIGH : NRF_GPIOTE_INITIAL_VALUE_LOW, \
.task_pin = false, \
}
/**
* @brief Macro for configuring a pin to use the GPIO OUT TASK to change the state from high to low.
* @details The task will clear the pin. Therefore, the pin is set initially.
*/
#define NRFX_GPIOTE_CONFIG_OUT_TASK_LOW \
{ \
.init_state = NRF_GPIOTE_INITIAL_VALUE_HIGH, \
.task_pin = true, \
.action = NRF_GPIOTE_POLARITY_HITOLO, \
}
/**
* @brief Macro for configuring a pin to use the GPIO OUT TASK to change the state from low to high.
* @details The task will set the pin. Therefore, the pin is cleared initially.
*/
#define NRFX_GPIOTE_CONFIG_OUT_TASK_HIGH \
{ \
.action = NRF_GPIOTE_POLARITY_LOTOHI, \
.init_state = NRF_GPIOTE_INITIAL_VALUE_LOW, \
.task_pin = true, \
}
/**
* @brief Macro for configuring a pin to use the GPIO OUT TASK to toggle the pin state.
* @details The initial pin state must be provided.
*/
#define NRFX_GPIOTE_CONFIG_OUT_TASK_TOGGLE(init_high) \
{ \
.action = NRF_GPIOTE_POLARITY_TOGGLE, \
.init_state = init_high ? NRF_GPIOTE_INITIAL_VALUE_HIGH : NRF_GPIOTE_INITIAL_VALUE_LOW, \
.task_pin = true, \
}
/** @brief Pin. */
typedef uint32_t nrfx_gpiote_pin_t;
/**
* @brief Pin event handler prototype.
*
* @param[in] pin Pin that triggered this event.
* @param[in] action Action that led to triggering this event.
*/
typedef void (*nrfx_gpiote_evt_handler_t)(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action);
/**
* @brief Function for initializing the GPIOTE module.
*
* @details Only static configuration is supported to prevent the shared
* resource being customized by the initiator.
*
* @retval NRFX_SUCCESS Initialization was successful.
* @retval NRFX_ERROR_INVALID_STATE The driver was already initialized.
*/
nrfx_err_t nrfx_gpiote_init(void);
/**
* @brief Function for checking if the GPIOTE module is initialized.
*
* @details The GPIOTE module is a shared module. Therefore, check if
* the module is already initialized and skip initialization if it is.
*
* @retval true The module is already initialized.
* @retval false The module is not initialized.
*/
bool nrfx_gpiote_is_init(void);
/** @brief Function for uninitializing the GPIOTE module. */
void nrfx_gpiote_uninit(void);
/**
* @brief Function for initializing a GPIOTE output pin.
* @details The output pin can be controlled by the CPU or by PPI. The initial
* configuration specifies which mode is used. If PPI mode is used, the driver
* attempts to allocate one of the available GPIOTE channels. If no channel is
* available, an error is returned.
*
* @param[in] pin Pin.
* @param[in] p_config Initial configuration.
*
* @retval NRFX_SUCCESS Initialization was successful.
* @retval NRFX_ERROR_INVALID_STATE The driver is not initialized or the pin is already used.
* @retval NRFX_ERROR_NO_MEM No GPIOTE channel is available.
*/
nrfx_err_t nrfx_gpiote_out_init(nrfx_gpiote_pin_t pin,
nrfx_gpiote_out_config_t const * p_config);
/**
* @brief Function for uninitializing a GPIOTE output pin.
* @details The driver frees the GPIOTE channel if the output pin was using one.
*
* @param[in] pin Pin.
*/
void nrfx_gpiote_out_uninit(nrfx_gpiote_pin_t pin);
/**
* @brief Function for setting a GPIOTE output pin.
*
* @param[in] pin Pin.
*/
void nrfx_gpiote_out_set(nrfx_gpiote_pin_t pin);
/**
* @brief Function for clearing a GPIOTE output pin.
*
* @param[in] pin Pin.
*/
void nrfx_gpiote_out_clear(nrfx_gpiote_pin_t pin);
/**
* @brief Function for toggling a GPIOTE output pin.
*
* @param[in] pin Pin.
*/
void nrfx_gpiote_out_toggle(nrfx_gpiote_pin_t pin);
/**
* @brief Function for enabling a GPIOTE output pin task.
*
* @param[in] pin Pin.
*/
void nrfx_gpiote_out_task_enable(nrfx_gpiote_pin_t pin);
/**
* @brief Function for disabling a GPIOTE output pin task.
*
* @param[in] pin Pin.
*/
void nrfx_gpiote_out_task_disable(nrfx_gpiote_pin_t pin);
/**
* @brief Function for getting the OUT task for the specified output pin.
*
* @details The returned task identifier can be used within @ref nrf_gpiote_hal,
* for example, to configure a DPPI channel.
*
* @param[in] pin Pin.
*
* @return OUT task associated with the specified output pin.
*/
nrf_gpiote_tasks_t nrfx_gpiote_out_task_get(nrfx_gpiote_pin_t pin);
/**
* @brief Function for getting the address of the OUT task for the specified output pin.
*
* @param[in] pin Pin.
*
* @return Address of OUT task.
*/
uint32_t nrfx_gpiote_out_task_addr_get(nrfx_gpiote_pin_t pin);
#if defined(GPIOTE_FEATURE_SET_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for getting the SET task for the specified output pin.
*
* @details The returned task identifier can be used within @ref nrf_gpiote_hal,
* for example, to configure a DPPI channel.
*
* @param[in] pin Pin.
*
* @return SET task associated with the specified output pin.
*/
nrf_gpiote_tasks_t nrfx_gpiote_set_task_get(nrfx_gpiote_pin_t pin);
/**
* @brief Function for getting the address of the SET task for the specified output pin.
*
* @param[in] pin Pin.
*
* @return Address of SET task.
*/
uint32_t nrfx_gpiote_set_task_addr_get(nrfx_gpiote_pin_t pin);
#endif // defined(GPIOTE_FEATURE_SET_PRESENT) || defined(__NRFX_DOXYGEN__)
#if defined(GPIOTE_FEATURE_CLR_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for getting the CLR task for the specified output pin.
*
* @details The returned task identifier can be used within @ref nrf_gpiote_hal,
* for example, to configure a DPPI channel.
*
* @param[in] pin Pin.
*
* @return CLR task associated with the specified output pin.
*/
nrf_gpiote_tasks_t nrfx_gpiote_clr_task_get(nrfx_gpiote_pin_t pin);
/**
* @brief Function for getting the address of the SET task for the specified output pin.
*
* @param[in] pin Pin.
*
* @return Address of CLR task.
*/
uint32_t nrfx_gpiote_clr_task_addr_get(nrfx_gpiote_pin_t pin);
#endif // defined(GPIOTE_FEATURE_CLR_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for initializing a GPIOTE input pin.
* @details The input pin can act in two ways:
* - lower accuracy but low power (high frequency clock not needed)
* - higher accuracy (high frequency clock required)
*
* The initial configuration specifies which mode is used.
* If high-accuracy mode is used, the driver attempts to allocate one
* of the available GPIOTE channels. If no channel is
* available, an error is returned.
* In low accuracy mode SENSE feature is used. In this case, only one active pin
* can be detected at a time. It can be worked around by setting all of the used
* low accuracy pins to toggle mode.
* For more information about SENSE functionality, refer to Product Specification.
*
* @param[in] pin Pin.
* @param[in] p_config Initial configuration.
* @param[in] evt_handler User function to be called when the configured transition occurs.
*
* @retval NRFX_SUCCESS Initialization was successful.
* @retval NRFX_ERROR_INVALID_STATE The driver is not initialized or the pin is already used.
* @retval NRFX_ERROR_NO_MEM No GPIOTE channel is available.
*/
nrfx_err_t nrfx_gpiote_in_init(nrfx_gpiote_pin_t pin,
nrfx_gpiote_in_config_t const * p_config,
nrfx_gpiote_evt_handler_t evt_handler);
/**
* @brief Function for uninitializing a GPIOTE input pin.
* @details The driver frees the GPIOTE channel if the input pin was using one.
*
* @param[in] pin Pin.
*/
void nrfx_gpiote_in_uninit(nrfx_gpiote_pin_t pin);
/**
* @brief Function for enabling sensing of a GPIOTE input pin.
*
* @details If the input pin is configured as high-accuracy pin, the function
* enables an IN_EVENT. Otherwise, the function enables the GPIO sense mechanism.
* The PORT event is shared between multiple pins, therefore the interrupt is always enabled.
*
* @param[in] pin Pin.
* @param[in] int_enable True to enable the interrupt. Always valid for a high-accuracy pin.
*/
void nrfx_gpiote_in_event_enable(nrfx_gpiote_pin_t pin, bool int_enable);
/**
* @brief Function for disabling a GPIOTE input pin.
*
* @param[in] pin Pin.
*/
void nrfx_gpiote_in_event_disable(nrfx_gpiote_pin_t pin);
/**
* @brief Function for checking if a GPIOTE input pin is set.
*
* @param[in] pin Pin.
*
* @retval true The input pin is set.
* @retval false The input pin is not set.
*/
bool nrfx_gpiote_in_is_set(nrfx_gpiote_pin_t pin);
/**
* @brief Function for getting the GPIOTE event for the specified input pin.
*
* @details The returned event identifier can be used within @ref nrf_gpiote_hal,
* for example, to configure a DPPI channel.
* If the pin is configured to use low-accuracy mode, the PORT event
* is returned.
*
* @param[in] pin Pin.
*
* @return Event associated with the specified input pin.
*/
nrf_gpiote_events_t nrfx_gpiote_in_event_get(nrfx_gpiote_pin_t pin);
/**
* @brief Function for getting the address of a GPIOTE input pin event.
* @details If the pin is configured to use low-accuracy mode, the address of the PORT event is returned.
*
* @param[in] pin Pin.
*
* @return Address of the specified input pin event.
*/
uint32_t nrfx_gpiote_in_event_addr_get(nrfx_gpiote_pin_t pin);
/**
* @brief Function for forcing a specific state on the pin configured as task.
*
* @param[in] pin Pin.
* @param[in] state Pin state.
*/
void nrfx_gpiote_out_task_force(nrfx_gpiote_pin_t pin, uint8_t state);
/**
* @brief Function for triggering the task OUT manually.
*
* @param[in] pin Pin.
*/
void nrfx_gpiote_out_task_trigger(nrfx_gpiote_pin_t pin);
#if defined(GPIOTE_FEATURE_SET_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for triggering the task SET manually.
*
* @param[in] pin Pin.
*/
void nrfx_gpiote_set_task_trigger(nrfx_gpiote_pin_t pin);
#endif // defined(GPIOTE_FEATURE_SET_PRESENT) || defined(__NRFX_DOXYGEN__)
#if defined(GPIOTE_FEATURE_CLR_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for triggering the task CLR manually.
*
* @param[in] pin Pin.
*/
void nrfx_gpiote_clr_task_trigger(nrfx_gpiote_pin_t pin);
#endif // defined(GPIOTE_FEATURE_CLR_PRESENT) || defined(__NRFX_DOXYGEN__)
/** @} */
void nrfx_gpiote_irq_handler(void);
#ifdef __cplusplus
}
#endif
#endif // NRFX_GPIOTE_H__
+295
View File
@@ -0,0 +1,295 @@
/**
* Copyright (c) 2019 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_NVMC_H__
#define NRFX_NVMC_H__
#include <nrfx.h>
#include <hal/nrf_nvmc.h>
#include <hal/nrf_ficr.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_nvmc NVMC driver
* @{
* @ingroup nrf_nvmc
* @brief Non-Volatile Memory Controller (NVMC) peripheral driver.
*/
/**
* @brief Function for erasing a page in flash.
*
* This function blocks until the erase operation finishes.
*
* @note Depending on the source of the code being executed,
* the CPU may be halted during the operation.
* Refer to the Product Specification for more information.
*
* @param address Address of the first word in the page to erase.
*
* @retval NRFX_SUCCESS Page erase complete.
* @retval NRFX_ERROR_INVALID_ADDR Address is not aligned to the size of the page.
*/
nrfx_err_t nrfx_nvmc_page_erase(uint32_t address);
/**
* @brief Function for erasing the user information configuration register (UICR).
*
* @note Depending on the source of the code being executed,
* the CPU may be halted during the operation.
* Refer to the Product Specification for more information.
*
* @retval NRFX_SUCCESS UICR has been successfully erased.
* @retval NRFX_ERROR_NOT_SUPPORTED UICR erase is not supported.
*/
nrfx_err_t nrfx_nvmc_uicr_erase(void);
/**
* @brief Function for erasing the whole flash memory.
*
* @note All user code and UICR will be erased.
*/
void nrfx_nvmc_all_erase(void);
#if defined(NRF_NVMC_PARTIAL_ERASE_PRESENT)
/**
* @brief Function for initiating a complete page erase split into parts (also known as partial erase).
*
* This function initiates a partial erase with the specified duration.
* To execute each part of the partial erase, use @ref nrfx_nvmc_page_partial_erase_continue.
*
* @param address Address of the first word in the page to erase.
* @param duration_ms Time in milliseconds that each partial erase will take.
*
* @retval NRFX_SUCCESS Partial erase started.
* @retval NRFX_ERROR_INVALID_ADDR Address is not aligned to the size of the page.
*
* @sa nrfx_nvmc_page_partial_erase_continue()
*/
nrfx_err_t nrfx_nvmc_page_partial_erase_init(uint32_t address, uint32_t duration_ms);
/**
* @brief Function for performing a part of the complete page erase (also known as partial erase).
*
* This function must be called several times to erase the whole page, once for each erase part.
*
* @note The actual time needed to perform each part of the page erase is longer than the partial
* erase duration specified in the call to @ref nrfx_nvmc_page_partial_erase_init,
* since the NVMC peripheral needs certain additional amount of time to handle the process.
* For details regarding this additional time, see the "Electrical specification" section
* for the NVMC peripheral in the Product Specification.
*
* @note Using a page that was not completely erased leads to undefined behavior.
* Depending on the source of the code being executed,
* the CPU may be halted during the operation.
* Refer to the Product Specification for more information.
*
* @retval true Partial erase finished.
* @retval false Partial erase not finished.
* Call the function again to process the next part.
*/
bool nrfx_nvmc_page_partial_erase_continue(void);
#endif // defined(NRF_NVMC_PARTIAL_ERASE_PRESENT)
/**
* @brief Function for checking whether a byte is writable at the specified address.
*
* The NVMC is only able to write '0' to bits in the flash that are erased (set to '1').
* It cannot rewrite a bit back to '1'. This function checks if the value currently
* residing at the specified address can be transformed to the desired value
* without any '0' to '1' transitions.
*
* @param address Address to be checked.
* @param value Value to be checked.
*
* @retval true Byte can be written at the specified address.
* @retval false Byte cannot be written at the specified address.
* Erase the page or change the address.
*/
bool nrfx_nvmc_byte_writable_check(uint32_t address, uint8_t value);
/**
* @brief Function for writing a single byte to flash.
*
* To determine if the flash write has been completed, use @ref nrfx_nvmc_write_done_check().
*
* @note Depending on the source of the code being executed,
* the CPU may be halted during the operation.
* Refer to the Product Specification for more information.
*
* @param address Address to write to.
* @param value Value to write.
*/
void nrfx_nvmc_byte_write(uint32_t address, uint8_t value);
/**
* @brief Function for checking whether a word is writable at the specified address.
*
* The NVMC is only able to write '0' to bits in the Flash that are erased (set to '1').
* It cannot rewrite a bit back to '1'. This function checks if the value currently
* residing at the specified address can be transformed to the desired value
* without any '0' to '1' transitions.
*
* @param address Address to be checked. Must be word-aligned.
* @param value Value to be checked.
*
* @retval true Word can be written at the specified address.
* @retval false Word cannot be written at the specified address.
* Erase page or change address.
*/
bool nrfx_nvmc_word_writable_check(uint32_t address, uint32_t value);
/**
* @brief Function for writing a 32-bit word to flash.
*
* To determine if the flash write has been completed, use @ref nrfx_nvmc_write_done_check().
*
* @note Depending on the source of the code being executed,
* the CPU may be halted during the operation.
* Refer to the Product Specification for more information.
*
* @param address Address to write to. Must be word-aligned.
* @param value Value to write.
*/
void nrfx_nvmc_word_write(uint32_t address, uint32_t value);
/**
* @brief Function for writing consecutive bytes to flash.
*
* To determine if the last flash write has been completed, use @ref nrfx_nvmc_write_done_check().
*
* @note Depending on the source of the code being executed,
* the CPU may be halted during the operation.
* Refer to the Product Specification for more information.
*
* @param address Address to write to.
* @param src Pointer to the data to copy from.
* @param num_bytes Number of bytes to write.
*/
void nrfx_nvmc_bytes_write(uint32_t address, void const * src, uint32_t num_bytes);
/**
* @brief Function for writing consecutive words to flash.
*
* To determine if the last flash write has been completed, use @ref nrfx_nvmc_write_done_check().
*
* @note Depending on the source of the code being executed,
* the CPU may be halted during the operation.
* Refer to the Product Specification for more information.
*
* @param address Address to write to. Must be word-aligned.
* @param src Pointer to data to copy from. Must be word-aligned.
* @param num_words Number of words to write.
*/
void nrfx_nvmc_words_write(uint32_t address, void const * src, uint32_t num_words);
/**
* @brief Function for getting the total flash size in bytes.
*
* @return Flash total size in bytes.
*/
uint32_t nrfx_nvmc_flash_size_get(void);
/**
* @brief Function for getting the flash page size in bytes.
*
* @return Flash page size in bytes.
*/
uint32_t nrfx_nvmc_flash_page_size_get(void);
/**
* @brief Function for getting the flash page count.
*
* @return Flash page count.
*/
uint32_t nrfx_nvmc_flash_page_count_get(void);
/**
* @brief Function for checking if the last flash write has been completed.
*
* @retval true Last write completed successfully.
* @retval false Last write is still in progress.
*/
__STATIC_INLINE bool nrfx_nvmc_write_done_check(void);
#if defined(NRF_NVMC_ICACHE_PRESENT)
/**
* @brief Function for enabling the Instruction Cache (ICache).
*
* Enabling ICache reduces the amount of accesses to flash memory,
* which can boost performance and lower power consumption.
*/
__STATIC_INLINE void nrfx_nvmc_icache_enable(void);
/** @brief Function for disabling ICache. */
__STATIC_INLINE void nrfx_nvmc_icache_disable(void);
#endif // defined(NRF_NVMC_ICACHE_PRESENT)
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE bool nrfx_nvmc_write_done_check(void)
{
return nrf_nvmc_ready_check(NRF_NVMC);
}
#if defined(NRF_NVMC_ICACHE_PRESENT)
__STATIC_INLINE void nrfx_nvmc_icache_enable(void)
{
nrf_nvmc_icache_config_set(NRF_NVMC, NRF_NVMC_ICACHE_ENABLE_WITH_PROFILING);
}
__STATIC_INLINE void nrfx_nvmc_icache_disable(void)
{
nrf_nvmc_icache_config_set(NRF_NVMC, NRF_NVMC_ICACHE_DISABLE);
}
#endif // defined(NRF_NVMC_ICACHE_PRESENT)
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_NVMC_H__
+380
View File
@@ -0,0 +1,380 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_POWER_H__
#define NRFX_POWER_H__
#include <nrfx.h>
#include <hal/nrf_power.h>
#include <nrfx_power_clock.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_power POWER driver
* @{
* @ingroup nrf_power
* @brief POWER peripheral driver.
*/
/**
* @brief Power mode possible configurations
*/
typedef enum
{
NRFX_POWER_MODE_CONSTLAT, /**< Constant latency mode */
NRFX_POWER_MODE_LOWPWR /**< Low power mode */
}nrfx_power_mode_t;
#if NRF_POWER_HAS_SLEEPEVT || defined(__NRFX_DOXYGEN__)
/**
* @brief Events from power system
*/
typedef enum
{
NRFX_POWER_SLEEP_EVT_ENTER, /**< CPU entered WFI/WFE sleep
*
* Keep in mind that if this interrupt is enabled,
* it means that CPU was waken up just after WFI by this interrupt.
*/
NRFX_POWER_SLEEP_EVT_EXIT /**< CPU exited WFI/WFE sleep */
}nrfx_power_sleep_evt_t;
#endif /* NRF_POWER_HAS_SLEEPEVT */
#if NRF_POWER_HAS_USBREG || defined(__NRFX_DOXYGEN__)
/**
* @brief Events from USB power system
*/
typedef enum
{
NRFX_POWER_USB_EVT_DETECTED, /**< USB power detected on the connector (plugged in). */
NRFX_POWER_USB_EVT_REMOVED, /**< USB power removed from the connector. */
NRFX_POWER_USB_EVT_READY /**< USB power regulator ready. */
}nrfx_power_usb_evt_t;
/**
* @brief USB power state
*
* The single enumerator that holds all data about current state of USB
* related POWER.
*
* Organized this way that higher power state has higher numeric value
*/
typedef enum
{
NRFX_POWER_USB_STATE_DISCONNECTED, /**< No power on USB lines detected. */
NRFX_POWER_USB_STATE_CONNECTED, /**< The USB power is detected, but USB power regulator is not ready. */
NRFX_POWER_USB_STATE_READY /**< From the power viewpoint, USB is ready for working. */
}nrfx_power_usb_state_t;
#endif /* NRF_POWER_HAS_USBREG */
/**
* @name Callback types
*
* Defined types of callback functions.
* @{
*/
/**
* @brief Event handler for power failure warning.
*/
typedef void (*nrfx_power_pofwarn_event_handler_t)(void);
#if NRF_POWER_HAS_SLEEPEVT || defined(__NRFX_DOXYGEN__)
/**
* @brief Event handler for the sleep events.
*
* @param event Event type
*/
typedef void (*nrfx_power_sleep_event_handler_t)(nrfx_power_sleep_evt_t event);
#endif
#if NRF_POWER_HAS_USBREG || defined(__NRFX_DOXYGEN__)
/**
* @brief Event handler for the USB-related power events.
*
* @param event Event type
*/
typedef void (*nrfx_power_usb_event_handler_t)(nrfx_power_usb_evt_t event);
#endif
/** @} */
/**
* @brief General power configuration
*
* Parameters required to initialize power driver.
*/
typedef struct
{
/**
* @brief Enable main DCDC regulator.
*
* This bit only informs the driver that elements for DCDC regulator
* are installed and the regulator can be used.
* The regulator will be enabled or disabled automatically
* by the hardware, basing on current power requirement.
*/
bool dcdcen:1;
#if NRF_POWER_HAS_VDDH || defined(__NRFX_DOXYGEN__)
/**
* @brief Enable HV DCDC regulator.
*
* This bit only informs the driver that elements for DCDC regulator
* are installed and the regulator can be used.
* The regulator will be enabled or disabled automatically
* by the hardware, basing on current power requirement.
*/
bool dcdcenhv: 1;
#endif
}nrfx_power_config_t;
/**
* @brief The configuration for power failure comparator.
*
* Configuration used to enable and configure the power failure comparator.
*/
typedef struct
{
nrfx_power_pofwarn_event_handler_t handler; //!< Event handler.
#if NRF_POWER_HAS_POFCON || defined(__NRFX_DOXYGEN__)
nrf_power_pof_thr_t thr; //!< Threshold for power failure detection
#endif
#if NRF_POWER_HAS_VDDH || defined(__NRFX_DOXYGEN__)
nrf_power_pof_thrvddh_t thrvddh; //!< Threshold for power failure detection on the VDDH pin.
#endif
}nrfx_power_pofwarn_config_t;
#if NRF_POWER_HAS_SLEEPEVT || defined(__NRFX_DOXYGEN__)
/**
* @brief The configuration of sleep event processing.
*
* Configuration used to enable and configure sleep event handling.
*/
typedef struct
{
nrfx_power_sleep_event_handler_t handler; //!< Event handler.
bool en_enter:1; //!< Enable event on sleep entering.
bool en_exit :1; //!< Enable event on sleep exiting.
}nrfx_power_sleepevt_config_t;
#endif
#if NRF_POWER_HAS_USBREG || defined(__NRFX_DOXYGEN__)
/**
* @brief The configuration of the USB-related power events.
*
* Configuration used to enable and configure USB power event handling.
*/
typedef struct
{
nrfx_power_usb_event_handler_t handler; //!< Event processing.
}nrfx_power_usbevt_config_t;
#endif /* NRF_POWER_HAS_USBREG */
/**
* @brief Function for getting the handler of the power failure comparator.
* @return Handler of the power failure comparator.
*/
nrfx_power_pofwarn_event_handler_t nrfx_power_pof_handler_get(void);
#if NRF_POWER_HAS_USBREG || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for getting the handler of the USB power.
* @return Handler of the USB power.
*/
nrfx_power_usb_event_handler_t nrfx_power_usb_handler_get(void);
#endif
/**
* @brief Function for initializing the power module driver.
*
* Enabled power module driver processes all the interrupts from the power system.
*
* @param[in] p_config Pointer to the structure with the initial configuration.
*
* @retval NRFX_SUCCESS Successfully initialized.
* @retval NRFX_ERROR_ALREADY_INITIALIZED Module was already initialized.
*/
nrfx_err_t nrfx_power_init(nrfx_power_config_t const * p_config);
/**
* @brief Function for unintializing the power module driver.
*
* Disables all the interrupt handling in the module.
*
* @sa nrfx_power_init
*/
void nrfx_power_uninit(void);
#if NRF_POWER_HAS_POFCON || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for initializing the power failure comparator.
*
* Configures the power failure comparator. This function does not set it up and enable it.
* These steps can be done with functions @ref nrfx_power_pof_enable and @ref nrfx_power_pof_disable
* or with the SoftDevice API (when in use).
*
* @param[in] p_config Configuration with values and event handler.
* If event handler is set to NULL, the interrupt will be disabled.
*/
void nrfx_power_pof_init(nrfx_power_pofwarn_config_t const * p_config);
/**
* @brief Function for enabling the power failure comparator.
* Sets and enables the interrupt of the power failure comparator. This function cannot be in use
* when SoftDevice is enabled. If the event handler set in the init function is set to NULL, the interrupt
* will be disabled.
*
* @param[in] p_config Configuration with values and event handler.
*/
void nrfx_power_pof_enable(nrfx_power_pofwarn_config_t const * p_config);
/**
* @brief Function for disabling the power failure comparator.
*
* Disables the power failure comparator interrupt.
*/
void nrfx_power_pof_disable(void);
/**
* @brief Function for clearing the power failure comparator settings.
*
* Clears the settings of the power failure comparator.
*/
void nrfx_power_pof_uninit(void);
#endif // NRF_POWER_HAS_POFCON || defined(__NRFX_DOXYGEN__)
#if NRF_POWER_HAS_SLEEPEVT || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for initializing the processing of the sleep events.
*
* Configures and sets up the sleep event processing.
*
* @param[in] p_config Configuration with values and event handler.
*
* @sa nrfx_power_sleepevt_uninit
*
*/
void nrfx_power_sleepevt_init(nrfx_power_sleepevt_config_t const * p_config);
/**
* @brief Function for enabling the processing of the sleep events.
*
* @param[in] p_config Configuration with values and event handler.
*/
void nrfx_power_sleepevt_enable(nrfx_power_sleepevt_config_t const * p_config);
/** @brief Function for disabling the processing of the sleep events. */
void nrfx_power_sleepevt_disable(void);
/**
* @brief Function for uninitializing the processing of the sleep events.
*
* @sa nrfx_power_sleepevt_init
*/
void nrfx_power_sleepevt_uninit(void);
#endif /* NRF_POWER_HAS_SLEEPEVT */
#if NRF_POWER_HAS_USBREG || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for initializing the processing of USB power event.
*
* Configures and sets up the USB power event processing.
*
* @param[in] p_config Configuration with values and event handler.
*
* @sa nrfx_power_usbevt_uninit
*/
void nrfx_power_usbevt_init(nrfx_power_usbevt_config_t const * p_config);
/** @brief Function for enabling the processing of USB power event. */
void nrfx_power_usbevt_enable(void);
/** @brief Function for disabling the processing of USB power event. */
void nrfx_power_usbevt_disable(void);
/**
* @brief Function for uninitalizing the processing of USB power event.
*
* @sa nrfx_power_usbevt_init
*/
void nrfx_power_usbevt_uninit(void);
/**
* @brief Function for getting the status of USB power.
*
* @return Current USB power status.
*/
__STATIC_INLINE nrfx_power_usb_state_t nrfx_power_usbstatus_get(void);
#endif /* NRF_POWER_HAS_USBREG */
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
#if NRF_POWER_HAS_USBREG
__STATIC_INLINE nrfx_power_usb_state_t nrfx_power_usbstatus_get(void)
{
uint32_t status = nrf_power_usbregstatus_get();
if(0 == (status & NRF_POWER_USBREGSTATUS_VBUSDETECT_MASK))
{
return NRFX_POWER_USB_STATE_DISCONNECTED;
}
if(0 == (status & NRF_POWER_USBREGSTATUS_OUTPUTRDY_MASK))
{
return NRFX_POWER_USB_STATE_CONNECTED;
}
return NRFX_POWER_USB_STATE_READY;
}
#endif /* NRF_POWER_HAS_USBREG */
#endif /* SUPPRESS_INLINE_IMPLEMENTATION */
/** @} */
void nrfx_power_irq_handler(void);
#ifdef __cplusplus
}
#endif
#endif /* NRFX_POWER_H__ */
@@ -0,0 +1,92 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_POWER_CLOCK_H__
#define NRFX_POWER_CLOCK_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
__STATIC_INLINE void nrfx_power_clock_irq_init(void);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrfx_power_clock_irq_init(void)
{
uint8_t priority;
#if NRFX_CHECK(NRFX_POWER_ENABLED) && NRFX_CHECK(NRFX_CLOCK_ENABLED)
#if NRFX_POWER_CONFIG_IRQ_PRIORITY != NRFX_CLOCK_CONFIG_IRQ_PRIORITY
#error "IRQ priorities for POWER and CLOCK must be the same. Check <nrfx_config.h>."
#endif
priority = NRFX_POWER_CONFIG_IRQ_PRIORITY;
#elif NRFX_CHECK(NRFX_POWER_ENABLED)
priority = NRFX_POWER_CONFIG_IRQ_PRIORITY;
#elif NRFX_CHECK(NRFX_CLOCK_ENABLED)
priority = NRFX_CLOCK_CONFIG_IRQ_PRIORITY;
#else
#error "This code is not supposed to be compiled when neither POWER nor CLOCK is enabled."
#endif
if (!NRFX_IRQ_IS_ENABLED(nrfx_get_irq_number(NRF_CLOCK)))
{
NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(NRF_CLOCK), priority);
NRFX_IRQ_ENABLE(nrfx_get_irq_number(NRF_CLOCK));
}
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
#if NRFX_CHECK(NRFX_POWER_ENABLED) && NRFX_CHECK(NRFX_CLOCK_ENABLED)
void nrfx_power_clock_irq_handler(void);
#elif NRFX_CHECK(NRFX_POWER_ENABLED)
#define nrfx_power_irq_handler nrfx_power_clock_irq_handler
#elif NRFX_CHECK(NRFX_CLOCK_ENABLED)
#define nrfx_clock_irq_handler nrfx_power_clock_irq_handler
#endif
#ifdef __cplusplus
}
#endif
#endif // NRFX_POWER_CLOCK_H__
+331
View File
@@ -0,0 +1,331 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_PPI_H__
#define NRFX_PPI_H__
#include <nrfx.h>
#include <hal/nrf_ppi.h>
/**
* @defgroup nrfx_ppi PPI allocator
* @{
* @ingroup nrf_ppi
* @brief Programmable Peripheral Interconnect (PPI) allocator.
*/
#ifdef __cplusplus
extern "C" {
#endif
#if !defined (NRFX_PPI_CHANNELS_USED) || defined(__NRFX_DOXYGEN__)
/** @brief Bitfield representing PPI channels used by external modules. */
#define NRFX_PPI_CHANNELS_USED 0
#endif
#if !defined(NRFX_PPI_GROUPS_USED) || defined(__NRFX_DOXYGEN__)
/** @brief Bitfield representing PPI groups used by external modules. */
#define NRFX_PPI_GROUPS_USED 0
#endif
#if (PPI_CH_NUM > 16) || defined(__NRFX_DOXYGEN__)
/** @brief Bitfield representing all PPI channels available to the application. */
#define NRFX_PPI_ALL_APP_CHANNELS_MASK ((uint32_t)0xFFFFFFFFuL & ~(NRFX_PPI_CHANNELS_USED))
/** @brief Bitfield representing programmable PPI channels available to the application. */
#define NRFX_PPI_PROG_APP_CHANNELS_MASK ((uint32_t)0x000FFFFFuL & ~(NRFX_PPI_CHANNELS_USED))
#else
#define NRFX_PPI_ALL_APP_CHANNELS_MASK ((uint32_t)0xFFF0FFFFuL & ~(NRFX_PPI_CHANNELS_USED))
#define NRFX_PPI_PROG_APP_CHANNELS_MASK ((uint32_t)0x0000FFFFuL & ~(NRFX_PPI_CHANNELS_USED))
#endif
/** @brief Bitfield representing all PPI groups available to the application. */
#define NRFX_PPI_ALL_APP_GROUPS_MASK (((1uL << PPI_GROUP_NUM) - 1) & ~(NRFX_PPI_GROUPS_USED))
/**
* @brief Function for uninitializing the PPI module.
*
* This function disables all channels and clears the channel groups.
*/
void nrfx_ppi_free_all(void);
/**
* @brief Function for allocating a PPI channel.
* @details This function allocates the first unused PPI channel.
*
* @param[out] p_channel Pointer to the PPI channel that has been allocated.
*
* @retval NRFX_SUCCESS The channel was successfully allocated.
* @retval NRFX_ERROR_NO_MEM There is no available channel to be used.
*/
nrfx_err_t nrfx_ppi_channel_alloc(nrf_ppi_channel_t * p_channel);
/**
* @brief Function for freeing a PPI channel.
* @details This function also disables the chosen channel.
*
* @param[in] channel PPI channel to be freed.
*
* @retval NRFX_SUCCESS The channel was successfully freed.
* @retval NRFX_ERROR_INVALID_PARAM The channel is not user-configurable.
*/
nrfx_err_t nrfx_ppi_channel_free(nrf_ppi_channel_t channel);
/**
* @brief Function for assigning task and event endpoints to the PPI channel.
*
* @param[in] channel PPI channel to be assigned endpoints.
* @param[in] eep Event endpoint address.
* @param[in] tep Task endpoint address.
*
* @retval NRFX_SUCCESS The channel was successfully assigned.
* @retval NRFX_ERROR_INVALID_STATE The channel is not allocated for the user.
* @retval NRFX_ERROR_INVALID_PARAM The channel is not user-configurable.
*/
nrfx_err_t nrfx_ppi_channel_assign(nrf_ppi_channel_t channel, uint32_t eep, uint32_t tep);
/**
* @brief Function for assigning fork endpoint to the PPI channel or clearing it.
*
* @param[in] channel PPI channel to be assigned endpoints.
* @param[in] fork_tep Fork task endpoint address or 0 to clear.
*
* @retval NRFX_SUCCESS The channel was successfully assigned.
* @retval NRFX_ERROR_INVALID_STATE The channel is not allocated for the user.
* @retval NRFX_ERROR_NOT_SUPPORTED Function is not supported.
*/
nrfx_err_t nrfx_ppi_channel_fork_assign(nrf_ppi_channel_t channel, uint32_t fork_tep);
/**
* @brief Function for enabling a PPI channel.
*
* @param[in] channel PPI channel to be enabled.
*
* @retval NRFX_SUCCESS The channel was successfully enabled.
* @retval NRFX_ERROR_INVALID_STATE The user-configurable channel is not allocated.
* @retval NRFX_ERROR_INVALID_PARAM The channel cannot be enabled by the user.
*/
nrfx_err_t nrfx_ppi_channel_enable(nrf_ppi_channel_t channel);
/**
* @brief Function for disabling a PPI channel.
*
* @param[in] channel PPI channel to be disabled.
*
* @retval NRFX_SUCCESS The channel was successfully disabled.
* @retval NRFX_ERROR_INVALID_STATE The user-configurable channel is not allocated.
* @retval NRFX_ERROR_INVALID_PARAM The channel cannot be disabled by the user.
*/
nrfx_err_t nrfx_ppi_channel_disable(nrf_ppi_channel_t channel);
/**
* @brief Function for allocating a PPI channel group.
* @details This function allocates the first unused PPI group.
*
* @param[out] p_group Pointer to the PPI channel group that has been allocated.
*
* @retval NRFX_SUCCESS The channel group was successfully allocated.
* @retval NRFX_ERROR_NO_MEM There is no available channel group to be used.
*/
nrfx_err_t nrfx_ppi_group_alloc(nrf_ppi_channel_group_t * p_group);
/**
* @brief Function for freeing a PPI channel group.
* @details This function also disables the chosen group.
*
* @param[in] group PPI channel group to be freed.
*
* @retval NRFX_SUCCESS The channel group was successfully freed.
* @retval NRFX_ERROR_INVALID_PARAM The channel group is not user-configurable.
*/
nrfx_err_t nrfx_ppi_group_free(nrf_ppi_channel_group_t group);
/**
* @brief Compute a channel mask for NRF_PPI registers.
*
* @param[in] channel Channel number to transform to a mask.
*
* @return Channel mask.
*/
__STATIC_INLINE uint32_t nrfx_ppi_channel_to_mask(nrf_ppi_channel_t channel)
{
return (1uL << (uint32_t) channel);
}
/**
* @brief Function for including multiple PPI channels in a channel group.
*
* @param[in] channel_mask PPI channels to be added.
* @param[in] group Channel group in which to include the channels.
*
* @retval NRFX_SUCCESS The channels was successfully included.
* @retval NRFX_ERROR_INVALID_PARAM Group is not an application group or channels are not an
* application channels.
* @retval NRFX_ERROR_INVALID_STATE Group is not an allocated group.
*/
nrfx_err_t nrfx_ppi_channels_include_in_group(uint32_t channel_mask,
nrf_ppi_channel_group_t group);
/**
* @brief Function for including a PPI channel in a channel group.
*
* @param[in] channel PPI channel to be added.
* @param[in] group Channel group in which to include the channel.
*
* @retval NRFX_SUCCESS The channel was successfully included.
* @retval NRFX_ERROR_INVALID_PARAM Group is not an application group or channel is not an
* application channel.
* @retval NRFX_ERROR_INVALID_STATE Group is not an allocated group.
*/
__STATIC_INLINE nrfx_err_t nrfx_ppi_channel_include_in_group(nrf_ppi_channel_t channel,
nrf_ppi_channel_group_t group)
{
return nrfx_ppi_channels_include_in_group(nrfx_ppi_channel_to_mask(channel), group);
}
/**
* @brief Function for removing multiple PPI channels from a channel group.
*
* @param[in] channel_mask PPI channels to be removed.
* @param[in] group Channel group from which to remove the channels.
*
* @retval NRFX_SUCCESS The channel was successfully removed.
* @retval NRFX_ERROR_INVALID_PARAM Group is not an application group or channels are not an
* application channels.
* @retval NRFX_ERROR_INVALID_STATE Group is not an allocated group.
*/
nrfx_err_t nrfx_ppi_channels_remove_from_group(uint32_t channel_mask,
nrf_ppi_channel_group_t group);
/**
* @brief Function for removing a single PPI channel from a channel group.
*
* @param[in] channel PPI channel to be removed.
* @param[in] group Channel group from which to remove the channel.
*
* @retval NRFX_SUCCESS The channel was successfully removed.
* @retval NRFX_ERROR_INVALID_PARAM Group is not an application group or channel is not an
* application channel.
* @retval NRFX_ERROR_INVALID_STATE Group is not an allocated group.
*/
__STATIC_INLINE nrfx_err_t nrfx_ppi_channel_remove_from_group(nrf_ppi_channel_t channel,
nrf_ppi_channel_group_t group)
{
return nrfx_ppi_channels_remove_from_group(nrfx_ppi_channel_to_mask(channel), group);
}
/**
* @brief Function for clearing a PPI channel group.
*
* @param[in] group Channel group to be cleared.
*
* @retval NRFX_SUCCESS The group was successfully cleared.
* @retval NRFX_ERROR_INVALID_PARAM Group is not an application group.
* @retval NRFX_ERROR_INVALID_STATE Group is not an allocated group.
*/
__STATIC_INLINE nrfx_err_t nrfx_ppi_group_clear(nrf_ppi_channel_group_t group)
{
return nrfx_ppi_channels_remove_from_group(NRFX_PPI_ALL_APP_CHANNELS_MASK, group);
}
/**
* @brief Function for enabling a PPI channel group.
*
* @param[in] group Channel group to be enabled.
*
* @retval NRFX_SUCCESS The group was successfully enabled.
* @retval NRFX_ERROR_INVALID_PARAM Group is not an application group.
* @retval NRFX_ERROR_INVALID_STATE Group is not an allocated group.
*/
nrfx_err_t nrfx_ppi_group_enable(nrf_ppi_channel_group_t group);
/**
* @brief Function for disabling a PPI channel group.
*
* @param[in] group Channel group to be disabled.
*
* @retval NRFX_SUCCESS The group was successfully disabled.
* @retval NRFX_ERROR_INVALID_PARAM Group is not an application group.
* @retval NRFX_ERROR_INVALID_STATE Group is not an allocated group.
*/
nrfx_err_t nrfx_ppi_group_disable(nrf_ppi_channel_group_t group);
/**
* @brief Function for getting the address of a PPI task.
*
* @param[in] task Task.
*
* @return Task address.
*/
__STATIC_INLINE uint32_t nrfx_ppi_task_addr_get(nrf_ppi_task_t task)
{
return (uint32_t) nrf_ppi_task_address_get(task);
}
/**
* @brief Function for getting the address of the enable task of a PPI group.
*
* @param[in] group PPI channel group
*
* @return Task address.
*/
__STATIC_INLINE uint32_t nrfx_ppi_task_addr_group_enable_get(nrf_ppi_channel_group_t group)
{
return (uint32_t) nrf_ppi_task_group_enable_address_get(group);
}
/**
* @brief Function for getting the address of the enable task of a PPI group.
*
* @param[in] group PPI channel group
*
* @return Task address.
*/
__STATIC_INLINE uint32_t nrfx_ppi_task_addr_group_disable_get(nrf_ppi_channel_group_t group)
{
return (uint32_t) nrf_ppi_task_group_disable_address_get(group);
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRFX_PPI_H__
+476
View File
@@ -0,0 +1,476 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_PWM_H__
#define NRFX_PWM_H__
#include <nrfx.h>
#include <hal/nrf_pwm.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_pwm PWM driver
* @{
* @ingroup nrf_pwm
* @brief Pulse Width Modulation (PWM) peripheral driver.
*/
/** @brief PWM driver instance data structure. */
typedef struct
{
NRF_PWM_Type * p_registers; ///< Pointer to the structure with PWM peripheral instance registers.
uint8_t drv_inst_idx; ///< Index of the driver instance. For internal use only.
} nrfx_pwm_t;
/** @brief Macro for creating a PWM driver instance. */
#define NRFX_PWM_INSTANCE(id) \
{ \
.p_registers = NRFX_CONCAT_2(NRF_PWM, id), \
.drv_inst_idx = NRFX_CONCAT_3(NRFX_PWM, id, _INST_IDX), \
}
#ifndef __NRFX_DOXYGEN__
enum {
#if NRFX_CHECK(NRFX_PWM0_ENABLED)
NRFX_PWM0_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_PWM1_ENABLED)
NRFX_PWM1_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_PWM2_ENABLED)
NRFX_PWM2_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_PWM3_ENABLED)
NRFX_PWM3_INST_IDX,
#endif
NRFX_PWM_ENABLED_COUNT
};
#endif
/**
* @brief This value can be provided instead of a pin number for any channel
* to specify that its output is not used and therefore does not need
* to be connected to a pin.
*/
#define NRFX_PWM_PIN_NOT_USED 0xFF
/** @brief This value can be added to a pin number to invert its polarity (set idle state = 1). */
#define NRFX_PWM_PIN_INVERTED 0x80
/** @brief PWM driver configuration structure. */
typedef struct
{
uint8_t output_pins[NRF_PWM_CHANNEL_COUNT]; ///< Pin numbers for individual output channels (optional).
/**< Use @ref NRFX_PWM_PIN_NOT_USED
* if a given output channel is not needed. */
uint8_t irq_priority; ///< Interrupt priority.
nrf_pwm_clk_t base_clock; ///< Base clock frequency.
nrf_pwm_mode_t count_mode; ///< Operating mode of the pulse generator counter.
uint16_t top_value; ///< Value up to which the pulse generator counter counts.
nrf_pwm_dec_load_t load_mode; ///< Mode of loading sequence data from RAM.
nrf_pwm_dec_step_t step_mode; ///< Mode of advancing the active sequence.
} nrfx_pwm_config_t;
/** @brief PWM driver default configuration. */
#define NRFX_PWM_DEFAULT_CONFIG \
{ \
.output_pins = { NRFX_PWM_DEFAULT_CONFIG_OUT0_PIN, \
NRFX_PWM_DEFAULT_CONFIG_OUT1_PIN, \
NRFX_PWM_DEFAULT_CONFIG_OUT2_PIN, \
NRFX_PWM_DEFAULT_CONFIG_OUT3_PIN }, \
.irq_priority = NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY, \
.base_clock = (nrf_pwm_clk_t)NRFX_PWM_DEFAULT_CONFIG_BASE_CLOCK, \
.count_mode = (nrf_pwm_mode_t)NRFX_PWM_DEFAULT_CONFIG_COUNT_MODE, \
.top_value = NRFX_PWM_DEFAULT_CONFIG_TOP_VALUE, \
.load_mode = (nrf_pwm_dec_load_t)NRFX_PWM_DEFAULT_CONFIG_LOAD_MODE, \
.step_mode = (nrf_pwm_dec_step_t)NRFX_PWM_DEFAULT_CONFIG_STEP_MODE, \
}
/** @brief PWM flags that provide additional playback options. */
typedef enum
{
NRFX_PWM_FLAG_STOP = 0x01, /**< When the requested playback is finished,
the peripheral will be stopped.
@note The STOP task is triggered when
the last value of the final sequence is
loaded from RAM, and the peripheral stops
at the end of the current PWM period.
For sequences with configured repeating
of duty cycle values, this might result in
less than the requested number of repeats
of the last value. */
NRFX_PWM_FLAG_LOOP = 0x02, /**< When the requested playback is finished,
it will be started from the beginning.
This flag is ignored if used together
with @ref NRFX_PWM_FLAG_STOP.
@note The playback restart is done via a
shortcut configured in the PWM peripheral.
This shortcut triggers the proper starting
task when the final value of previous
playback is read from RAM and applied to
the pulse generator counter.
When this mechanism is used together with
the @ref NRF_PWM_STEP_TRIGGERED mode,
the playback restart will occur right
after switching to the final value (this
final value will be played only once). */
NRFX_PWM_FLAG_SIGNAL_END_SEQ0 = 0x04, /**< The event handler is to be
called when the last value
from sequence 0 is loaded. */
NRFX_PWM_FLAG_SIGNAL_END_SEQ1 = 0x08, /**< The event handler is to be
called when the last value
from sequence 1 is loaded. */
NRFX_PWM_FLAG_NO_EVT_FINISHED = 0x10, /**< The playback finished event
(enabled by default) is to be
suppressed. */
NRFX_PWM_FLAG_START_VIA_TASK = 0x80, /**< The playback must not be
started directly by the called
function. Instead, the function
must only prepare it and
return the address of the task
to be triggered to start the
playback. */
} nrfx_pwm_flag_t;
/** @brief PWM driver event type. */
typedef enum
{
NRFX_PWM_EVT_FINISHED, ///< Sequence playback finished.
NRFX_PWM_EVT_END_SEQ0, /**< End of sequence 0 reached. Its data can be
safely modified now. */
NRFX_PWM_EVT_END_SEQ1, /**< End of sequence 1 reached. Its data can be
safely modified now. */
NRFX_PWM_EVT_STOPPED, ///< The PWM peripheral has been stopped.
} nrfx_pwm_evt_type_t;
/** @brief PWM driver event handler type. */
typedef void (* nrfx_pwm_handler_t)(nrfx_pwm_evt_type_t event_type);
/**
* @brief Function for initializing the PWM driver.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_config Pointer to the structure with the initial configuration.
* @param[in] handler Event handler provided by the user. If NULL is passed
* instead, event notifications are not done and PWM
* interrupts are disabled.
*
* @retval NRFX_SUCCESS Initialization was successful.
* @retval NRFX_ERROR_INVALID_STATE The driver was already initialized.
*/
nrfx_err_t nrfx_pwm_init(nrfx_pwm_t const * const p_instance,
nrfx_pwm_config_t const * p_config,
nrfx_pwm_handler_t handler);
/**
* @brief Function for uninitializing the PWM driver.
*
* If any sequence playback is in progress, it is stopped immediately.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_pwm_uninit(nrfx_pwm_t const * const p_instance);
/**
* @brief Function for starting a single sequence playback.
*
* To take advantage of the looping mechanism in the PWM peripheral, both
* sequences must be used (single sequence can be played back only once by
* the peripheral). Therefore, the provided sequence is internally set and
* played back as both sequence 0 and sequence 1. Consequently, if the end of
* sequence notifications are required, events for both sequences must be
* used (that is, both the @ref NRFX_PWM_FLAG_SIGNAL_END_SEQ0 flag
* and the @ref NRFX_PWM_FLAG_SIGNAL_END_SEQ1 flag must be specified, and
* the @ref NRFX_PWM_EVT_END_SEQ0 event and the @ref NRFX_PWM_EVT_END_SEQ1
* event must be handled in the same way).
*
* Use the @ref NRFX_PWM_FLAG_START_VIA_TASK flag if you want the playback
* to be only prepared by this function, and you want to start it later by
* triggering a task (for example, by using PPI). The function will then return
* the address of the task to be triggered.
*
* @note The array containing the duty cycle values for the specified sequence
* must be in RAM and cannot be allocated on the stack.
* For detailed information, see @ref nrf_pwm_sequence_t.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_sequence Sequence to be played back.
* @param[in] playback_count Number of playbacks to be performed (must not be 0).
* @param[in] flags Additional options. Pass any combination of
* @ref nrfx_pwm_flag_t "playback flags", or 0
* for default settings.
*
* @return Address of the task to be triggered to start the playback if the @ref
* NRFX_PWM_FLAG_START_VIA_TASK flag was used, 0 otherwise.
*/
uint32_t nrfx_pwm_simple_playback(nrfx_pwm_t const * const p_instance,
nrf_pwm_sequence_t const * p_sequence,
uint16_t playback_count,
uint32_t flags);
/**
* @brief Function for starting a two-sequence playback.
*
* Use the @ref NRFX_PWM_FLAG_START_VIA_TASK flag if you want the playback
* to be only prepared by this function, and you want to start it later by
* triggering a task (using PPI for instance). The function will then return
* the address of the task to be triggered.
*
* @note The array containing the duty cycle values for the specified sequence
* must be in RAM and cannot be allocated on the stack.
* For detailed information, see @ref nrf_pwm_sequence_t.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_sequence_0 First sequence to be played back.
* @param[in] p_sequence_1 Second sequence to be played back.
* @param[in] playback_count Number of playbacks to be performed (must not be 0).
* @param[in] flags Additional options. Pass any combination of
* @ref nrfx_pwm_flag_t "playback flags", or 0
* for default settings.
*
* @return Address of the task to be triggered to start the playback if the @ref
* NRFX_PWM_FLAG_START_VIA_TASK flag was used, 0 otherwise.
*/
uint32_t nrfx_pwm_complex_playback(nrfx_pwm_t const * const p_instance,
nrf_pwm_sequence_t const * p_sequence_0,
nrf_pwm_sequence_t const * p_sequence_1,
uint16_t playback_count,
uint32_t flags);
/**
* @brief Function for advancing the active sequence.
*
* This function only applies to @ref NRF_PWM_STEP_TRIGGERED mode.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
__STATIC_INLINE void nrfx_pwm_step(nrfx_pwm_t const * const p_instance);
/**
* @brief Function for stopping the sequence playback.
*
* The playback is stopped at the end of the current PWM period.
* This means that if the active sequence is configured to repeat each duty
* cycle value for a certain number of PWM periods, the last played value
* might appear on the output less times than requested.
*
* @note This function can be instructed to wait until the playback is stopped
* (by setting @p wait_until_stopped to true). Depending on
* the length of the PMW period, this might take a significant amount of
* time. Alternatively, the @ref nrfx_pwm_is_stopped function can be
* used to poll the status, or the @ref NRFX_PWM_EVT_STOPPED event can
* be used to get the notification when the playback is stopped, provided
* the event handler is defined.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] wait_until_stopped If true, the function will not return until
* the playback is stopped.
*
* @retval true The PWM peripheral is stopped.
* @retval false The PWM peripheral is not stopped.
*/
bool nrfx_pwm_stop(nrfx_pwm_t const * const p_instance, bool wait_until_stopped);
/**
* @brief Function for checking the status of the PWM peripheral.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @retval true The PWM peripheral is stopped.
* @retval false The PWM peripheral is not stopped.
*/
bool nrfx_pwm_is_stopped(nrfx_pwm_t const * const p_instance);
/**
* @brief Function for updating the sequence data during playback.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] seq_id Identifier of the sequence (0 or 1).
* @param[in] p_sequence Pointer to the new sequence definition.
*/
__STATIC_INLINE void nrfx_pwm_sequence_update(nrfx_pwm_t const * const p_instance,
uint8_t seq_id,
nrf_pwm_sequence_t const * p_sequence);
/**
* @brief Function for updating the pointer to the duty cycle values
* in the specified sequence during playback.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] seq_id Identifier of the sequence (0 or 1).
* @param[in] values New pointer to the duty cycle values.
*/
__STATIC_INLINE void nrfx_pwm_sequence_values_update(nrfx_pwm_t const * const p_instance,
uint8_t seq_id,
nrf_pwm_values_t values);
/**
* @brief Function for updating the number of duty cycle values
* in the specified sequence during playback.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] seq_id Identifier of the sequence (0 or 1).
* @param[in] length New number of the duty cycle values.
*/
__STATIC_INLINE void nrfx_pwm_sequence_length_update(nrfx_pwm_t const * const p_instance,
uint8_t seq_id,
uint16_t length);
/**
* @brief Function for updating the number of repeats for duty cycle values
* in the specified sequence during playback.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] seq_id Identifier of the sequence (0 or 1).
* @param[in] repeats New number of repeats.
*/
__STATIC_INLINE void nrfx_pwm_sequence_repeats_update(nrfx_pwm_t const * const p_instance,
uint8_t seq_id,
uint32_t repeats);
/**
* @brief Function for updating the additional delay after the specified
* sequence during playback.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] seq_id Identifier of the sequence (0 or 1).
* @param[in] end_delay New end delay value (in PWM periods).
*/
__STATIC_INLINE void nrfx_pwm_sequence_end_delay_update(nrfx_pwm_t const * const p_instance,
uint8_t seq_id,
uint32_t end_delay);
/**
* @brief Function for returning the address of a specified PWM task that can
* be used in PPI module.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] task Requested task.
*
* @return Task address.
*/
__STATIC_INLINE uint32_t nrfx_pwm_task_address_get(nrfx_pwm_t const * const p_instance,
nrf_pwm_task_t task);
/**
* @brief Function for returning the address of a specified PWM event that can
* be used in PPI module.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] event Requested event.
*
* @return Event address.
*/
__STATIC_INLINE uint32_t nrfx_pwm_event_address_get(nrfx_pwm_t const * const p_instance,
nrf_pwm_event_t event);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrfx_pwm_step(nrfx_pwm_t const * const p_instance)
{
nrf_pwm_task_trigger(p_instance->p_registers, NRF_PWM_TASK_NEXTSTEP);
}
__STATIC_INLINE void nrfx_pwm_sequence_update(nrfx_pwm_t const * const p_instance,
uint8_t seq_id,
nrf_pwm_sequence_t const * p_sequence)
{
nrf_pwm_sequence_set(p_instance->p_registers, seq_id, p_sequence);
}
__STATIC_INLINE void nrfx_pwm_sequence_values_update(nrfx_pwm_t const * const p_instance,
uint8_t seq_id,
nrf_pwm_values_t values)
{
nrf_pwm_seq_ptr_set(p_instance->p_registers, seq_id, values.p_raw);
}
__STATIC_INLINE void nrfx_pwm_sequence_length_update(nrfx_pwm_t const * const p_instance,
uint8_t seq_id,
uint16_t length)
{
nrf_pwm_seq_cnt_set(p_instance->p_registers, seq_id, length);
}
__STATIC_INLINE void nrfx_pwm_sequence_repeats_update(nrfx_pwm_t const * const p_instance,
uint8_t seq_id,
uint32_t repeats)
{
nrf_pwm_seq_refresh_set(p_instance->p_registers, seq_id, repeats);
}
__STATIC_INLINE void nrfx_pwm_sequence_end_delay_update(nrfx_pwm_t const * const p_instance,
uint8_t seq_id,
uint32_t end_delay)
{
nrf_pwm_seq_end_delay_set(p_instance->p_registers, seq_id, end_delay);
}
__STATIC_INLINE uint32_t nrfx_pwm_task_address_get(nrfx_pwm_t const * const p_instance,
nrf_pwm_task_t task)
{
return nrf_pwm_task_address_get(p_instance->p_registers, task);
}
__STATIC_INLINE uint32_t nrfx_pwm_event_address_get(nrfx_pwm_t const * const p_instance,
nrf_pwm_event_t event)
{
return nrf_pwm_event_address_get(p_instance->p_registers, event);
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
void nrfx_pwm_0_irq_handler(void);
void nrfx_pwm_1_irq_handler(void);
void nrfx_pwm_2_irq_handler(void);
void nrfx_pwm_3_irq_handler(void);
#ifdef __cplusplus
}
#endif
#endif // NRFX_PWM_H__
+120
View File
@@ -0,0 +1,120 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_RNG_H__
#define NRFX_RNG_H__
#include <nrfx.h>
#include <hal/nrf_rng.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_rng RNG driver
* @{
* @ingroup nrf_rng
* @brief Random Number Generator (RNG) peripheral driver.
*/
/** @brief Struct for RNG configuration. */
typedef struct
{
bool error_correction : 1; /**< Error correction flag. */
uint8_t interrupt_priority; /**< Interrupt priority. */
} nrfx_rng_config_t;
/**
* @brief RNG default configuration.
* Basic usage:
* @code
* nrfx_rng_config_t config = NRFX_RNG_DEFAULT_CONFIG;
* if (nrfx_rng_init(&config, handler)
* { ...
* @endcode
*/
#define NRFX_RNG_DEFAULT_CONFIG \
{ \
.error_correction = NRFX_RNG_CONFIG_ERROR_CORRECTION, \
.interrupt_priority = NRFX_RNG_CONFIG_IRQ_PRIORITY, \
}
/** @brief RNG driver event handler type. */
typedef void (* nrfx_rng_evt_handler_t)(uint8_t rng_data);
/**
* @brief Function for initializing the nrfx_rng module.
*
* @param[in] p_config Pointer to the structure with the initial configuration.
* @param[in] handler Event handler provided by the user. Must not be NULL.
*
* @retval NRFX_SUCCESS Driver was successfully initialized.
* @retval NRFX_ERROR_ALREADY_INITIALIZED Driver was already initialized.
*/
nrfx_err_t nrfx_rng_init(nrfx_rng_config_t const * p_config, nrfx_rng_evt_handler_t handler);
/**
* @brief Function for starting the generation of random values.
*
* New data should be handled by handler passed to the @ref nrfx_rng_init() function.
*/
void nrfx_rng_start(void);
/**
* @brief Function for stopping the generation of random values.
*
* Function disables interrupts in peripheral and stops the generation of new random values.
*/
void nrfx_rng_stop(void);
/** @brief Function for uninitializing the nrfx_rng module. */
void nrfx_rng_uninit(void);
/** @} */
void nrfx_rng_irq_handler(void);
#ifdef __cplusplus
}
#endif
#endif // NRFX_RNG_H__
+378
View File
@@ -0,0 +1,378 @@
/**
* Copyright (c) 2014 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_RTC_H__
#define NRFX_RTC_H__
#include <nrfx.h>
#include <hal/nrf_rtc.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_rtc RTC driver
* @{
* @ingroup nrf_rtc
* @brief Real Timer Counter (RTC) peripheral driver.
*/
/** @brief Macro for converting microseconds into ticks. */
#define NRFX_RTC_US_TO_TICKS(us,freq) (((us) * (freq)) / 1000000U)
/** @brief RTC driver interrupt types. */
typedef enum
{
NRFX_RTC_INT_COMPARE0 = 0, /**< Interrupt from COMPARE0 event. */
NRFX_RTC_INT_COMPARE1 = 1, /**< Interrupt from COMPARE1 event. */
NRFX_RTC_INT_COMPARE2 = 2, /**< Interrupt from COMPARE2 event. */
NRFX_RTC_INT_COMPARE3 = 3, /**< Interrupt from COMPARE3 event. */
NRFX_RTC_INT_TICK = 4, /**< Interrupt from TICK event. */
NRFX_RTC_INT_OVERFLOW = 5 /**< Interrupt from OVERFLOW event. */
} nrfx_rtc_int_type_t;
/** @brief RTC driver instance structure. */
typedef struct
{
NRF_RTC_Type * p_reg; /**< Pointer to instance register set. */
IRQn_Type irq; /**< Instance IRQ ID. */
uint8_t instance_id; /**< Index of the driver instance. For internal use only. */
uint8_t cc_channel_count; /**< Number of capture/compare channels. */
} nrfx_rtc_t;
/** @brief Macro for creating an RTC driver instance. */
#define NRFX_RTC_INSTANCE(id) \
{ \
.p_reg = NRFX_CONCAT_2(NRF_RTC, id), \
.irq = NRFX_CONCAT_3(RTC, id, _IRQn), \
.instance_id = NRFX_CONCAT_3(NRFX_RTC, id, _INST_IDX), \
.cc_channel_count = NRF_RTC_CC_CHANNEL_COUNT(id), \
}
#ifndef __NRFX_DOXYGEN__
enum {
#if NRFX_CHECK(NRFX_RTC0_ENABLED)
NRFX_RTC0_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_RTC1_ENABLED)
NRFX_RTC1_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_RTC2_ENABLED)
NRFX_RTC2_INST_IDX,
#endif
NRFX_RTC_ENABLED_COUNT
};
#endif
/** @brief RTC driver instance configuration structure. */
typedef struct
{
uint16_t prescaler; /**< Prescaler. */
uint8_t interrupt_priority; /**< Interrupt priority. */
uint8_t tick_latency; /**< Maximum length of the interrupt handler in ticks (maximum 7.7 ms). */
bool reliable; /**< Reliable mode flag. */
} nrfx_rtc_config_t;
/** @brief RTC instance default configuration. */
#define NRFX_RTC_DEFAULT_CONFIG \
{ \
.prescaler = RTC_FREQ_TO_PRESCALER(NRFX_RTC_DEFAULT_CONFIG_FREQUENCY), \
.interrupt_priority = NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY, \
.tick_latency = NRFX_RTC_US_TO_TICKS(NRFX_RTC_MAXIMUM_LATENCY_US, \
NRFX_RTC_DEFAULT_CONFIG_FREQUENCY), \
.reliable = NRFX_RTC_DEFAULT_CONFIG_RELIABLE, \
}
/** @brief RTC driver instance handler type. */
typedef void (*nrfx_rtc_handler_t)(nrfx_rtc_int_type_t int_type);
/**
* @brief Function for initializing the RTC driver instance.
*
* After initialization, the instance is in power off state.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_config Pointer to the structure with the initial configuration.
* @param[in] handler Event handler provided by the user.
* Must not be NULL.
*
* @retval NRFX_SUCCESS Successfully initialized.
* @retval NRFX_ERROR_INVALID_STATE The instance is already initialized.
*/
nrfx_err_t nrfx_rtc_init(nrfx_rtc_t const * const p_instance,
nrfx_rtc_config_t const * p_config,
nrfx_rtc_handler_t handler);
/**
* @brief Function for uninitializing the RTC driver instance.
*
* After uninitialization, the instance is in idle state. The hardware should return to the state
* before initialization.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_rtc_uninit(nrfx_rtc_t const * const p_instance);
/**
* @brief Function for enabling the RTC driver instance.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_rtc_enable(nrfx_rtc_t const * const p_instance);
/**
* @brief Function for disabling the RTC driver instance.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_rtc_disable(nrfx_rtc_t const * const p_instance);
/**
* @brief Function for setting a compare channel.
*
* The function powers on the instance if the instance was in power off state.
*
* The driver is not entering a critical section when configuring RTC, which means that it can be
* preempted for a certain amount of time. When the driver was preempted and the value to be set
* is short in time, there is a risk that the driver sets a compare value that is
* behind. In this case, if the reliable mode is enabled for the specified instance,
* the risk is handled.
* However, to detect if the requested value is behind, this mode makes the following assumptions:
* - The maximum preemption time in ticks (8-bit value) is known and is less than 7.7 ms
* (for prescaler = 0, RTC frequency 32 kHz).
* - The requested absolute compare value is not bigger than (0x00FFFFFF)-tick_latency. It is
* the user's responsibility to ensure this.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] channel One of the channels of the instance.
* @param[in] val Absolute value to be set in the compare register.
* @param[in] enable_irq True to enable the interrupt. False to disable the interrupt.
*
* @retval NRFX_SUCCESS The procedure is successful.
* @retval NRFX_ERROR_TIMEOUT The compare is not set because the request value is behind the
* current counter value. This error can only be reported
* if the reliable mode is enabled.
*/
nrfx_err_t nrfx_rtc_cc_set(nrfx_rtc_t const * const p_instance,
uint32_t channel,
uint32_t val,
bool enable_irq);
/**
* @brief Function for disabling a channel.
*
* This function disables channel events and channel interrupts.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] channel One of the channels of the instance.
*
* @retval NRFX_SUCCESS The procedure is successful.
* @retval NRFX_ERROR_TIMEOUT Interrupt is pending on the requested channel.
*/
nrfx_err_t nrfx_rtc_cc_disable(nrfx_rtc_t const * const p_instance, uint32_t channel);
/**
* @brief Function for enabling the TICK event.
*
* This function enables the tick event and optionally the interrupt.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] enable_irq True to enable the interrupt. False to disable the interrupt.
*/
void nrfx_rtc_tick_enable(nrfx_rtc_t const * const p_instance, bool enable_irq);
/**
* @brief Function for disabling the TICK event.
*
* This function disables the TICK event and interrupt.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_rtc_tick_disable(nrfx_rtc_t const * const p_instance);
/**
* @brief Function for enabling overflow.
*
* This function enables the overflow event and optionally the interrupt.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] enable_irq True to enable the interrupt. False to disable the interrupt.
*/
void nrfx_rtc_overflow_enable(nrfx_rtc_t const * const p_instance, bool enable_irq);
/**
* @brief Function for disabling overflow.
*
* This function disables the overflow event and interrupt.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_rtc_overflow_disable(nrfx_rtc_t const * const p_instance);
/**
* @brief Function for getting the maximum relative tick value that can be set in the compare channel.
*
* When a stack (for example SoftDevice) is used and it occupies high priority interrupts,
* the application code can be interrupted at any moment for a certain period of time.
* If the reliable mode is enabled, the provided maximum latency is taken into account
* and the return value is smaller than the RTC counter resolution.
* If the reliable mode is disabled, the return value equals the counter resolution.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @return Maximum ticks value.
*/
uint32_t nrfx_rtc_max_ticks_get(nrfx_rtc_t const * const p_instance);
/**
* @brief Function for disabling all instance interrupts.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_mask Pointer to the location where the mask is filled.
*/
__STATIC_INLINE void nrfx_rtc_int_disable(nrfx_rtc_t const * const p_instance,
uint32_t * p_mask);
/**
* @brief Function for enabling instance interrupts.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] mask Mask of interrupts to enable.
*/
__STATIC_INLINE void nrfx_rtc_int_enable(nrfx_rtc_t const * const p_instance, uint32_t mask);
/**
* @brief Function for retrieving the current counter value.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @return Counter value.
*/
__STATIC_INLINE uint32_t nrfx_rtc_counter_get(nrfx_rtc_t const * const p_instance);
/**
* @brief Function for clearing the counter value.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
__STATIC_INLINE void nrfx_rtc_counter_clear(nrfx_rtc_t const * const p_instance);
/**
* @brief Function for returning a requested task address for the RTC driver instance.
*
* The task address can be used by the PPI module.
*
* @param[in] p_instance Pointer to the instance.
* @param[in] task One of the peripheral tasks.
*
* @return Address of task register.
*/
__STATIC_INLINE uint32_t nrfx_rtc_task_address_get(nrfx_rtc_t const * const p_instance,
nrf_rtc_task_t task);
/**
* @brief Function for returning a requested event address for the RTC driver instance.
*
* The event address can be used by the PPI module.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] event One of the peripheral events.
*
* @return Address of event register.
*/
__STATIC_INLINE uint32_t nrfx_rtc_event_address_get(nrfx_rtc_t const * const p_instance,
nrf_rtc_event_t event);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrfx_rtc_int_disable(nrfx_rtc_t const * const p_instance,
uint32_t * p_mask)
{
*p_mask = nrf_rtc_int_get(p_instance->p_reg);
nrf_rtc_int_disable(p_instance->p_reg, NRF_RTC_INT_TICK_MASK |
NRF_RTC_INT_OVERFLOW_MASK |
NRF_RTC_INT_COMPARE0_MASK |
NRF_RTC_INT_COMPARE1_MASK |
NRF_RTC_INT_COMPARE2_MASK |
NRF_RTC_INT_COMPARE3_MASK);
}
__STATIC_INLINE void nrfx_rtc_int_enable(nrfx_rtc_t const * const p_instance, uint32_t mask)
{
nrf_rtc_int_enable(p_instance->p_reg, mask);
}
__STATIC_INLINE uint32_t nrfx_rtc_counter_get(nrfx_rtc_t const * const p_instance)
{
return nrf_rtc_counter_get(p_instance->p_reg);
}
__STATIC_INLINE void nrfx_rtc_counter_clear(nrfx_rtc_t const * const p_instance)
{
nrf_rtc_task_trigger(p_instance->p_reg, NRF_RTC_TASK_CLEAR);
}
__STATIC_INLINE uint32_t nrfx_rtc_task_address_get(nrfx_rtc_t const * const p_instance,
nrf_rtc_task_t task)
{
return nrf_rtc_task_address_get(p_instance->p_reg, task);
}
__STATIC_INLINE uint32_t nrfx_rtc_event_address_get(nrfx_rtc_t const * const p_instance,
nrf_rtc_event_t event)
{
return nrf_rtc_event_address_get(p_instance->p_reg, event);
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
void nrfx_rtc_0_irq_handler(void);
void nrfx_rtc_1_irq_handler(void);
void nrfx_rtc_2_irq_handler(void);
#ifdef __cplusplus
}
#endif
#endif // NRFX_RTC_H__
+322
View File
@@ -0,0 +1,322 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_SAADC_H__
#define NRFX_SAADC_H__
#include <nrfx.h>
#include <hal/nrf_saadc.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(NRFX_SAADC_API_V2)
#include "nrfx_saadc_v2.h"
#else
/**
* @defgroup nrfx_saadc SAADC legacy driver
* @{
* @ingroup nrf_saadc
* @brief Successive Approximation Analog-to-Digital Converter (SAADC) peripheral legacy driver.
*/
/** @brief Value to be set as high limit to disable limit detection. */
#define NRFX_SAADC_LIMITH_DISABLED (2047)
/** @brief Value to be set as low limit to disable limit detection. */
#define NRFX_SAADC_LIMITL_DISABLED (-2048)
/** @brief Macro for setting @ref nrfx_saadc_config_t to default settings. */
#define NRFX_SAADC_DEFAULT_CONFIG \
{ \
.resolution = (nrf_saadc_resolution_t)NRFX_SAADC_CONFIG_RESOLUTION, \
.oversample = (nrf_saadc_oversample_t)NRFX_SAADC_CONFIG_OVERSAMPLE, \
.interrupt_priority = NRFX_SAADC_CONFIG_IRQ_PRIORITY, \
.low_power_mode = NRFX_SAADC_CONFIG_LP_MODE \
}
/**
* @brief Macro for setting @ref nrf_saadc_channel_config_t to default settings
* in single-ended mode.
*
* @param PIN_P Analog input.
*/
#define NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(PIN_P) \
{ \
.resistor_p = NRF_SAADC_RESISTOR_DISABLED, \
.resistor_n = NRF_SAADC_RESISTOR_DISABLED, \
.gain = NRF_SAADC_GAIN1_6, \
.reference = NRF_SAADC_REFERENCE_INTERNAL, \
.acq_time = NRF_SAADC_ACQTIME_10US, \
.mode = NRF_SAADC_MODE_SINGLE_ENDED, \
.burst = NRF_SAADC_BURST_DISABLED, \
.pin_p = (nrf_saadc_input_t)(PIN_P), \
.pin_n = NRF_SAADC_INPUT_DISABLED \
}
/**
* @brief Macro for setting @ref nrf_saadc_channel_config_t to default settings
* in differential mode.
*
* @param PIN_P Positive analog input.
* @param PIN_N Negative analog input.
*/
#define NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_DIFFERENTIAL(PIN_P, PIN_N) \
{ \
.resistor_p = NRF_SAADC_RESISTOR_DISABLED, \
.resistor_n = NRF_SAADC_RESISTOR_DISABLED, \
.gain = NRF_SAADC_GAIN1_6, \
.reference = NRF_SAADC_REFERENCE_INTERNAL, \
.acq_time = NRF_SAADC_ACQTIME_10US, \
.mode = NRF_SAADC_MODE_DIFFERENTIAL, \
.burst = NRF_SAADC_BURST_DISABLED, \
.pin_p = (nrf_saadc_input_t)(PIN_P), \
.pin_n = (nrf_saadc_input_t)(PIN_N) \
}
/** @brief SAADC driver configuration structure. */
typedef struct
{
nrf_saadc_resolution_t resolution; ///< Resolution configuration.
nrf_saadc_oversample_t oversample; ///< Oversampling configuration.
uint8_t interrupt_priority; ///< Interrupt priority.
bool low_power_mode; ///< Indicates if low power mode is active.
} nrfx_saadc_config_t;
/** @brief SAADC driver event types. */
typedef enum
{
NRFX_SAADC_EVT_DONE, ///< Event generated when the buffer is filled with samples.
NRFX_SAADC_EVT_LIMIT, ///< Event generated after one of the limits is reached.
NRFX_SAADC_EVT_CALIBRATEDONE ///< Event generated when the calibration is complete.
} nrfx_saadc_evt_type_t;
/** @brief SAADC driver done event data. */
typedef struct
{
nrf_saadc_value_t * p_buffer; ///< Pointer to buffer with converted samples.
uint16_t size; ///< Number of samples in the buffer.
} nrfx_saadc_done_evt_t;
/** @brief SAADC driver limit event data. */
typedef struct
{
uint8_t channel; ///< Channel on which the limit was detected.
nrf_saadc_limit_t limit_type; ///< Type of limit detected.
} nrfx_saadc_limit_evt_t;
/** @brief SAADC driver event structure. */
typedef struct
{
nrfx_saadc_evt_type_t type; ///< Event type.
union
{
nrfx_saadc_done_evt_t done; ///< Data for @ref NRFX_SAADC_EVT_DONE event.
nrfx_saadc_limit_evt_t limit; ///< Data for @ref NRFX_SAADC_EVT_LIMIT event.
} data; ///< Union to store event data.
} nrfx_saadc_evt_t;
/**
* @brief SAADC driver event handler.
*
* @param[in] p_event Pointer to an SAADC driver event. The event structure is allocated on
* the stack, so it is valid only within the context of the event handler.
*/
typedef void (* nrfx_saadc_event_handler_t)(nrfx_saadc_evt_t const * p_event);
/**
* @brief Function for initializing the SAADC.
*
* @param[in] p_config Pointer to the structure with initial configuration.
* @param[in] event_handler Event handler provided by the user.
* Must not be NULL.
*
* @retval NRFX_SUCCESS Initialization was successful.
* @retval NRFX_ERROR_INVALID_STATE The driver is already initialized.
*/
nrfx_err_t nrfx_saadc_init(nrfx_saadc_config_t const * p_config,
nrfx_saadc_event_handler_t event_handler);
/**
* @brief Function for uninitializing the SAADC.
*
* This function stops all ongoing conversions and disables all channels.
*/
void nrfx_saadc_uninit(void);
/**
* @brief Function for getting the address of a SAMPLE SAADC task.
*
* @return Task address.
*/
uint32_t nrfx_saadc_sample_task_get(void);
/**
* @brief Function for initializing an SAADC channel.
*
* This function configures and enables the channel.
*
* @param[in] channel Channel index.
* @param[in] p_config Pointer to the structure with the initial configuration.
*
* @retval NRFX_SUCCESS Initialization was successful.
* @retval NRFX_ERROR_INVALID_STATE The SAADC was not initialized.
* @retval NRFX_ERROR_NO_MEM The specified channel was already allocated.
*/
nrfx_err_t nrfx_saadc_channel_init(uint8_t channel,
nrf_saadc_channel_config_t const * const p_config);
/**
* @brief Function for uninitializing an SAADC channel.
*
* @param[in] channel Channel index.
*
* @retval NRFX_SUCCESS Uninitialization was successful.
* @retval NRFX_ERROR_BUSY The SAADC is busy.
*/
nrfx_err_t nrfx_saadc_channel_uninit(uint8_t channel);
/**
* @brief Function for starting the SAADC sampling.
*
* @retval NRFX_SUCCESS The SAADC sampling was triggered.
* @retval NRFX_ERROR_INVALID_STATE The SAADC is in idle state.
*/
nrfx_err_t nrfx_saadc_sample(void);
/**
* @brief Blocking function for executing a single SAADC conversion.
*
* This function selects the desired input, starts a single conversion,
* waits for it to finish, and returns the result.
*
* The function fails if the SAADC is busy.
*
* @param[in] channel Channel.
* @param[out] p_value Pointer to the location where the result is to be placed.
*
* @retval NRFX_SUCCESS The conversion was successful.
* @retval NRFX_ERROR_BUSY The SAADC driver is busy.
*/
nrfx_err_t nrfx_saadc_sample_convert(uint8_t channel, nrf_saadc_value_t * p_value);
/**
* @brief Function for issuing conversion of data to the buffer.
*
* This function is non-blocking. The application is notified about filling the buffer by the event
* handler. Conversion will be done on all enabled channels. If the SAADC is in idle state, the
* function will set up EasyDMA for the conversion. The SAADC will be ready for sampling and wait
* for the SAMPLE task. It can be triggered manually by the @ref nrfx_saadc_sample function
* or by PPI using the @ref NRF_SAADC_TASK_SAMPLE task. If one buffer is already set and the
* conversion is ongoing, calling this function will result in queuing the given buffer.
* The driver will start filling the issued buffer when the first one is completed.
* If the function is called again before the first buffer is filled or calibration
* is in progress, it will return with error.
*
* @param[in] buffer Result buffer.
* @param[in] size Buffer size in words.
*
* @retval NRFX_SUCCESS The conversion was successful.
* @retval NRFX_ERROR_BUSY The driver already has two buffers set or the calibration is in progress.
*/
nrfx_err_t nrfx_saadc_buffer_convert(nrf_saadc_value_t * buffer, uint16_t size);
/**
* @brief Function for triggering the SAADC offset calibration.
*
* This function is non-blocking. The application is notified about completion by the event handler.
* Calibration will also trigger DONE and RESULTDONE events.
*
* The function will fail if the SAADC is busy or calibration is already in progress.
*
* @retval NRFX_SUCCESS The calibration was started successfully.
* @retval NRFX_ERROR_BUSY The SAADC driver is busy.
*/
nrfx_err_t nrfx_saadc_calibrate_offset(void);
/**
* @brief Function for retrieving the SAADC state.
*
* @retval true The SAADC is busy.
* @retval false The SAADC is ready.
*/
bool nrfx_saadc_is_busy(void);
/**
* @brief Function for aborting the ongoing and buffered conversions.
*
* @note @ref NRFX_SAADC_EVT_DONE event will be generated if there is a conversion in progress.
* Event will contain number of words in the sample buffer.
*
* @warning This function must not be called from the context of event handler of the SAADC driver
* or from the context of interrupt with priority equal to or higher than priority
* of the SAADC interrupt.
*/
void nrfx_saadc_abort(void);
/**
* @brief Function for setting the SAADC channel limits.
* When limits are enabled and the result exceeds the defined bounds, the limit handler
* function is called.
*
* @param[in] channel SAADC channel number.
* @param[in] limit_low Lower limit (valid values from @ref NRFX_SAADC_LIMITL_DISABLED to
* @ref NRFX_SAADC_LIMITH_DISABLED). Conversion results below this value will
* trigger the handler function. Set to @ref NRFX_SAADC_LIMITL_DISABLED
* to disable this limit.
* @param[in] limit_high Upper limit (valid values from @ref NRFX_SAADC_LIMITL_DISABLED to
* @ref NRFX_SAADC_LIMITH_DISABLED). Conversion results above this value will
* trigger the handler function. Set to @ref NRFX_SAADC_LIMITH_DISABLED
* to disable this limit.
*/
void nrfx_saadc_limits_set(uint8_t channel, int16_t limit_low, int16_t limit_high);
/** @} */
#endif // defined(NRFX_SAADC_API_V2)
void nrfx_saadc_irq_handler(void);
#ifdef __cplusplus
}
#endif
#endif // NRFX_SAADC_H__
@@ -0,0 +1,382 @@
/**
* Copyright (c) 2019 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_SAADC_V2_H__
#define NRFX_SAADC_V2_H__
#ifndef NRFX_SAADC_H__
#error "This file should not be included directly. Include nrfx_saadc.h instead."
#endif
/**
* @defgroup nrfx_saadc_v2 SAADC v2 driver
* @{
* @ingroup nrf_saadc
* @brief Successive Approximation Analog-to-Digital Converter (SAADC) peripheral v2 driver.
* @details API description can be found <a href="../../drivers/include/nrfx_saadc_v2.h">here</a>.
* @}
*/
/**
* @brief SAADC channel default configuration for the single-ended mode.
*
* This configuration sets up single-ended SAADC channel with the following options:
* - resistor ladder disabled
* - gain: 1/6
* - reference voltage: internal 0.6 V
* - sample acquisition time: 10 us
* - burst disabled
*
* @param[in] _pin_p Positive input analog pin.
* @param[in] _index Channel index.
*
* @sa nrfx_saadc_channel_t
*/
#define NRFX_SAADC_DEFAULT_CHANNEL_SE(_pin_p, _index) \
{ \
.channel_config = \
{ \
.resistor_p = NRF_SAADC_RESISTOR_DISABLED, \
.resistor_n = NRF_SAADC_RESISTOR_DISABLED, \
.gain = NRF_SAADC_GAIN1_6, \
.reference = NRF_SAADC_REFERENCE_INTERNAL, \
.acq_time = NRF_SAADC_ACQTIME_10US, \
.mode = NRF_SAADC_MODE_SINGLE_ENDED, \
.burst = NRF_SAADC_BURST_DISABLED, \
}, \
.pin_p = (nrf_saadc_input_t)_pin_p, \
.pin_n = NRF_SAADC_INPUT_DISABLED, \
.channel_index = _index, \
}
/**
* @brief SAADC channel default configuration for the differential mode.
*
* This configuration sets up differential SAADC channel with the following options:
* - resistor ladder disabled
* - gain: 1/6
* - reference voltage: internal 0.6 V
* - sample acquisition time: 10 us
* - burst disabled
*
* @param[in] _pin_p Positive input analog pin.
* @param[in] _pin_n Negative input analog pin.
* @param[in] _index Channel index.
*
* @sa nrfx_saadc_channel_t
*/
#define NRFX_SAADC_DEFAULT_CHANNEL_DIFFERENTIAL(_pin_p, _pin_n, _index) \
{ \
.channel_config = \
{ \
.resistor_p = NRF_SAADC_RESISTOR_DISABLED, \
.resistor_n = NRF_SAADC_RESISTOR_DISABLED, \
.gain = NRF_SAADC_GAIN1_6, \
.reference = NRF_SAADC_REFERENCE_INTERNAL, \
.acq_time = NRF_SAADC_ACQTIME_10US, \
.mode = NRF_SAADC_MODE_DIFFERENTIAL, \
.burst = NRF_SAADC_BURST_DISABLED, \
}, \
.pin_p = (nrf_saadc_input_t)_pin_p, \
.pin_n = (nrf_saadc_input_t)_pin_n, \
.channel_index = _index, \
}
/**
* @brief SAADC driver advanced mode default configuration.
*
* This configuration sets up advanced mode of the SAADC driver with the following options:
* - oversampling disabled
* - burst disabled
* - internal sampling timer disabled
* - triggering of the START task on the END event disabled
*
* @param[in] _pin_p Positive input analog pin.
* @param[in] _pin_n Negative input analog pin.
* @param[in] _index Channel index.
*
* @sa nrfx_saadc_adv_config_t
*/
#define NRFX_SAADC_DEFAULT_ADV_CONFIG \
{ \
.oversampling = NRF_SAADC_OVERSAMPLE_DISABLED, \
.burst = NRF_SAADC_BURST_DISABLED, \
.internal_timer_cc = 0, \
.start_on_end = false, \
}
/** @brief SAADC channel configuration structure. */
typedef struct
{
nrf_saadc_channel_config_t channel_config; ///< Channel hardware configuration.
nrf_saadc_input_t pin_p; ///< Input positive pin selection.
nrf_saadc_input_t pin_n; ///< Input negative pin selection.
uint8_t channel_index; ///< Channel index.
} nrfx_saadc_channel_t;
/** @brief SAADC driver advanced mode configuration structure. */
typedef struct
{
nrf_saadc_oversample_t oversampling; ///< Oversampling configuration.
nrf_saadc_burst_t burst; ///< Burst configuration.
uint16_t internal_timer_cc; ///< Internal timer capture and compare value.
bool start_on_end; ///< Flag indicating if the START task is to be triggered on the END event.
} nrfx_saadc_adv_config_t;
/** @brief SAADC driver event types. */
typedef enum
{
NRFX_SAADC_EVT_DONE, ///< Event generated when the buffer is filled with samples.
NRFX_SAADC_EVT_LIMIT, ///< Event generated when one of the limits is reached.
NRFX_SAADC_EVT_CALIBRATEDONE, ///< Event generated when the calibration is complete.
NRFX_SAADC_EVT_BUF_REQ, ///< Event generated when the next buffer for continuous conversion is requested.
NRFX_SAADC_EVT_READY, ///< Event generated when the first buffer is acquired by the peripheral and sampling can be started.
NRFX_SAADC_EVT_FINISHED, ///< Event generated when all supplied buffers are filled with results.
} nrfx_saadc_evt_type_t;
/** @brief SAADC driver done event data. */
typedef struct
{
nrf_saadc_value_t * p_buffer; ///< Pointer to the buffer with converted samples.
uint16_t size; ///< Number of samples in the buffer.
} nrfx_saadc_done_evt_t;
/** @brief SAADC driver limit event data. */
typedef struct
{
uint8_t channel; ///< Channel on which the limit was detected.
nrf_saadc_limit_t limit_type; ///< Type of limit detected.
} nrfx_saadc_limit_evt_t;
/** @brief SAADC driver event structure. */
typedef struct
{
nrfx_saadc_evt_type_t type; ///< Event type.
union
{
nrfx_saadc_done_evt_t done; ///< Data for @ref NRFX_SAADC_EVT_DONE event.
nrfx_saadc_limit_evt_t limit; ///< Data for @ref NRFX_SAADC_EVT_LIMIT event.
} data; ///< Union to store event data.
} nrfx_saadc_evt_t;
/**
* @brief SAADC driver event handler.
*
* When operating in the advanced mode:
* - when the sampling is performed by the external timer, the external timer can be safely started
* on @ref NRFX_SAADC_EVT_READY and stopped on @ref NRFX_SAADC_EVT_FINISHED.
* - call the @ref nrfx_saadc_buffer_set() on @ref NRFX_SAADC_EVT_BUF_REQ to achieve the continuous conversion.
*
* @param[in] p_event Pointer to an SAADC driver event. The event structure is allocated on
* the stack, so it is valid only within the context of the event handler.
*/
typedef void (* nrfx_saadc_event_handler_t)(nrfx_saadc_evt_t const * p_event);
/**
* @brief Function for initializing the SAADC driver.
*
* @param[in] interrupt_priority Interrupt priority.
*
* @retval NRFX_SUCCESS Initialization was successful.
* @retval NRFX_ERROR_INVALID_STATE The driver is already initialized.
*/
nrfx_err_t nrfx_saadc_init(uint8_t interrupt_priority);
/**
* @brief Function for uninitializing the SAADC driver.
*
* This function stops all ongoing conversions and disables all channels.
*/
void nrfx_saadc_uninit(void);
/**
* @brief Function for configuring the SAADC channels.
*
* @note The values of the @ref nrf_saadc_channel_config_t.burst fields in channel configurations
* are ignored. They will be overridden with the value suitable for the selected driver
* operation mode.
* @note The desired mode (simple or advanced) must be set after the channels are configured.
*
* @param[in] p_channels Pointer to the array of channel configuration structures.
* @param[in] channel_count Number of channels to be configured.
*
* @retval NRFX_SUCCESS Configuration was successful.
* @retval NRFX_ERROR_BUSY There is a conversion or calibration ongoing.
* @retval NRFX_ERROR_INVALID_PARAM Attempt to configure the same channel more than once.
*/
nrfx_err_t nrfx_saadc_channels_config(nrfx_saadc_channel_t const * p_channels,
uint32_t channel_count);
/**
* @brief Function for setting the SAADC driver in the simple mode.
*
* The simple mode allows obtaining a single sample from each requested channel.
* The conversion can be done in a blocking or non-blocking manner.
* Sampling is initiated by calling @ref nrfx_saadc_mode_trigger() once.
*
* @param[in] channel_mask Bitmask of channels to be used in the simple mode.
* @param[in] resolution Resolution configuration.
* @param[in] oversampling Oversampling configuration.
* @param[in] event_handler Event handler provided by the user. In case of providing NULL,
* the conversion will be performed in the blocking manner.
*
* @retval NRFX_SUCCESS Initialization was successful.
* @retval NRFX_ERROR_BUSY There is a conversion or calibration ongoing.
* @retval NRFX_ERROR_INVALID_PARAM Attempt to activate channel that is not configured.
*/
nrfx_err_t nrfx_saadc_simple_mode_set(uint32_t channel_mask,
nrf_saadc_resolution_t resolution,
nrf_saadc_oversample_t oversampling,
nrfx_saadc_event_handler_t event_handler);
/**
* @brief Function for setting the SAADC driver in the advanced mode.
*
* The advanced mode allows performing double-buffered conversions of arbitrary length.
* The conversions can be done in a blocking or non-blocking manner. When performing conversions
* in the non-blocking manner and @ref nrfx_saadc_adv_config_t.internal_timer_cc is set to 0,
* sampling needs to be done by triggering @ref NRF_SAADC_TASK_SAMPLE externally
* (for example by using the TIMER and/or the PPI/DPPI).
* When performing conversions in the non-blocking manner and @ref nrfx_saadc_adv_config_t.start_on_end
* is false, the @ref NRF_SAADC_TASK_START needs to be triggered on @ref NRF_SAADC_EVENT_END
* externally (for example by using the PPI/DPPI).
* Sampling is initiated by calling @ref nrfx_saadc_mode_trigger(). In case of performing
* conversions in the blocking manner, @ref nrfx_saadc_mode_trigger() may need to be called several
* times as each call sample each requested channel once.
*
* @note The internal timer can only be used when a single input channel is enabled.
* @note The internal timer can only be used in the non-blocking mode.
*
* @param[in] channel_mask Bitmask of channels to be used in the advanced mode.
* @param[in] resolution Resolution configuration.
* @param[in] p_config Pointer to the structure with the advanced mode configuration.
* @param[in] event_handler Event handler provided by the user. In case of providing NULL,
* the conversion will be performed in the blocking manner.
*
* @retval NRFX_SUCCESS Initialization was successful.
* @retval NRFX_ERROR_BUSY There is a conversion or calibration ongoing.
* @retval NRFX_ERROR_INVALID_PARAM Attempt to activate channel that is not configured.
* @retval NRFX_ERROR_NOT_SUPPORTED Attempt to activate internal timer or oversampling without burst
* with multiple channels enabled.
*/
nrfx_err_t nrfx_saadc_advanced_mode_set(uint32_t channel_mask,
nrf_saadc_resolution_t resolution,
nrfx_saadc_adv_config_t const * p_config,
nrfx_saadc_event_handler_t event_handler);
/**
* @brief Function for supplying the buffer to be used in the next part of
* the conversion.
*
* @param[in] p_buffer Pointer to the buffer to be filled with conversion results.
* @param[in] size Number of @ref nrf_saadc_value_t samples in buffer.
*
* @retval NRFX_SUCCESS Buffer was supplied successfully.
* @retval NRFX_ERROR_INVALID_ADDR The provided buffer is not in the Data RAM region.
* @retval NRFX_ERROR_INVALID_LENGTH The provided buffer is not aligned to the number of activated channels
* or is too long for the EasyDMA to handle.
* @retval NRFX_ERROR_INVALID_STATE The driver is in the idle mode.
* @retval NRFX_ERROR_ALREADY_INITIALIZED Both buffers for double-buffered conversions are already set.
*/
nrfx_err_t nrfx_saadc_buffer_set(nrf_saadc_value_t * p_buffer, uint16_t size);
/**
* @brief Function for triggering the conversion in the configured mode.
*
* @retval NRFX_SUCCESS Operation finished successfully in the blocking manner or started
* successfully in the non-blocking manner.
* @retval NRFX_ERROR_BUSY The driver is performing the conversion in the advanced blocking mode.
* Call the function again to continue the conversion.
* @retval NRFX_ERROR_NO_MEM There is no buffer provided.
* Supply the buffer using @ref nrfx_saadc_buffer_set() and try again.
* @retval NRFX_ERROR_INVALID_STATE There is an ongoing conversion being performed in the non-blocking manner
* or the driver is in the idle mode.
*/
nrfx_err_t nrfx_saadc_mode_trigger(void);
/**
* @brief Function for aborting the ongoing and buffered conversions.
*
* @note @ref NRFX_SAADC_EVT_DONE event will be generated if there is a conversion in progress.
* Event will contain number of words in the sample buffer.
*/
void nrfx_saadc_abort(void);
/**
* @brief Function for setting the SAADC channel limits.
*
* When limits are enabled and the conversion result exceeds the defined bounds,
* the handler function is called with the corresponding event as parameter.
*
* @note Before the limits are set, the driver operation mode (simple or advanced) has
* to be configured. Only non-blocking conversions can be monitored.
*
* @note Changing of the driver operation mode disables all configured limits.
*
* @param[in] channel Channel index.
* @param[in] limit_low Limit low value to generate interrupt. Use @c INT16_MIN
* to disable interrupt generation.
* @param[in] limit_high Limit high value to generate interrupt. Use @c INT16_MAX
* to disable interrupt generation.
*
* @retval NRFX_SUCCESS Requested channel limits were set.
* @retval NRFX_ERROR_INVALID_PARAM Attempt to activate the limits on disabled channel.
* @retval NRFX_ERROR_FORBIDDEN Attempt to activate the limits for blocking conversions.
* @retval NRFX_ERROR_INVALID_STATE Attempt to activate the limits without configured mode.
*/
nrfx_err_t nrfx_saadc_limits_set(uint8_t channel, int16_t limit_low, int16_t limit_high);
/**
* @brief Function for starting the SAADC offset calibration.
*
* @note This function cancels the currently selected driver operation mode, if any.
* The desired mode (simple or advanced) must be set after the calibration process completes.
*
* @param[in] event_handler Event handler provided by the user. In case of providing NULL,
* the calibration will be performed in the blocking manner.
*
* @retval NRFX_SUCCESS Calibration finished successfully in the blocking manner
* or started successfully in the non-blocking manner.
* @retval NRFX_ERROR_BUSY There is a conversion or calibration ongoing.
*/
nrfx_err_t nrfx_saadc_offset_calibrate(nrfx_saadc_event_handler_t event_handler);
#endif // NRFX_SAADC_V2_H__
+255
View File
@@ -0,0 +1,255 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_SPI_H__
#define NRFX_SPI_H__
#include <nrfx.h>
#include <hal/nrf_spi.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_spi SPI driver
* @{
* @ingroup nrf_spi
* @brief Serial Peripheral Interface master (SPI) driver.
*/
/** @brief Data structure of the Serial Peripheral Interface master (SPI) driver instance. */
typedef struct
{
NRF_SPI_Type * p_reg; ///< Pointer to a structure with SPI registers.
uint8_t drv_inst_idx; ///< Index of the driver instance. For internal use only.
} nrfx_spi_t;
enum {
#if NRFX_CHECK(NRFX_SPI0_ENABLED)
NRFX_SPI0_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_SPI1_ENABLED)
NRFX_SPI1_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_SPI2_ENABLED)
NRFX_SPI2_INST_IDX,
#endif
NRFX_SPI_ENABLED_COUNT
};
/** @brief Macro for creating an instance of the SPI master driver. */
#define NRFX_SPI_INSTANCE(id) \
{ \
.p_reg = NRFX_CONCAT_2(NRF_SPI, id), \
.drv_inst_idx = NRFX_CONCAT_3(NRFX_SPI, id, _INST_IDX), \
}
/**
* @brief This value can be provided instead of a pin number for signals MOSI,
* MISO, and Slave Select to specify that the given signal is not used and
* therefore does not need to be connected to a pin.
*/
#define NRFX_SPI_PIN_NOT_USED 0xFF
/** @brief Configuration structure of the SPI master driver instance. */
typedef struct
{
uint8_t sck_pin; ///< SCK pin number.
uint8_t mosi_pin; ///< MOSI pin number (optional).
/**< Set to @ref NRFX_SPI_PIN_NOT_USED
* if this signal is not needed. */
uint8_t miso_pin; ///< MISO pin number (optional).
/**< Set to @ref NRFX_SPI_PIN_NOT_USED
* if this signal is not needed. */
uint8_t ss_pin; ///< Slave Select pin number (optional).
/**< Set to @ref NRFX_SPI_PIN_NOT_USED
* if this signal is not needed. The driver
* supports only active low for this signal.
* If the signal must be active high,
* it must be controlled externally. */
uint8_t irq_priority; ///< Interrupt priority.
uint8_t orc; ///< Overrun character.
/**< This character is used when all bytes from the TX buffer are sent,
but the transfer continues due to RX. */
nrf_spi_frequency_t frequency; ///< SPI frequency.
nrf_spi_mode_t mode; ///< SPI mode.
nrf_spi_bit_order_t bit_order; ///< SPI bit order.
} nrfx_spi_config_t;
/** @brief SPI master instance default configuration. */
#define NRFX_SPI_DEFAULT_CONFIG \
{ \
.sck_pin = NRFX_SPI_PIN_NOT_USED, \
.mosi_pin = NRFX_SPI_PIN_NOT_USED, \
.miso_pin = NRFX_SPI_PIN_NOT_USED, \
.ss_pin = NRFX_SPI_PIN_NOT_USED, \
.irq_priority = NRFX_SPI_DEFAULT_CONFIG_IRQ_PRIORITY, \
.orc = 0xFF, \
.frequency = NRF_SPI_FREQ_4M, \
.mode = NRF_SPI_MODE_0, \
.bit_order = NRF_SPI_BIT_ORDER_MSB_FIRST, \
}
/** @brief Single transfer descriptor structure. */
typedef struct
{
uint8_t const * p_tx_buffer; ///< Pointer to TX buffer.
size_t tx_length; ///< TX buffer length.
uint8_t * p_rx_buffer; ///< Pointer to RX buffer.
size_t rx_length; ///< RX buffer length.
}nrfx_spi_xfer_desc_t;
/**
* @brief Macro for setting up single transfer descriptor.
*
* This macro is for internal use only.
*/
#define NRFX_SPI_SINGLE_XFER(p_tx, tx_len, p_rx, rx_len) \
{ \
.p_tx_buffer = (uint8_t const *)(p_tx), \
.tx_length = (tx_len), \
.p_rx_buffer = (p_rx), \
.rx_length = (rx_len), \
}
/** @brief Macro for setting the duplex TX RX transfer. */
#define NRFX_SPI_XFER_TRX(p_tx_buf, tx_length, p_rx_buf, rx_length) \
NRFX_SPI_SINGLE_XFER(p_tx_buf, tx_length, p_rx_buf, rx_length)
/** @brief Macro for setting the TX transfer. */
#define NRFX_SPI_XFER_TX(p_buf, length) \
NRFX_SPI_SINGLE_XFER(p_buf, length, NULL, 0)
/** @brief Macro for setting the RX transfer. */
#define NRFX_SPI_XFER_RX(p_buf, length) \
NRFX_SPI_SINGLE_XFER(NULL, 0, p_buf, length)
/**
* @brief SPI master driver event types, passed to the handler routine provided
* during initialization.
*/
typedef enum
{
NRFX_SPI_EVENT_DONE, ///< Transfer done.
} nrfx_spi_evt_type_t;
/** @brief SPI master event description with transmission details. */
typedef struct
{
nrfx_spi_evt_type_t type; ///< Event type.
nrfx_spi_xfer_desc_t xfer_desc; ///< Transfer details.
} nrfx_spi_evt_t;
/** @brief SPI master driver event handler type. */
typedef void (* nrfx_spi_evt_handler_t)(nrfx_spi_evt_t const * p_event,
void * p_context);
/**
* @brief Function for initializing the SPI master driver instance.
*
* This function configures and enables the specified peripheral.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_config Pointer to the structure with the initial configuration.
* @param[in] handler Event handler provided by the user. If NULL, transfers
* will be performed in blocking mode.
* @param[in] p_context Context passed to the event handler.
*
* @retval NRFX_SUCCESS Initialization was successful.
* @retval NRFX_ERROR_INVALID_STATE The driver was already initialized.
* @retval NRFX_ERROR_BUSY Some other peripheral with the same
* instance ID is already in use. This is
* possible only if @ref nrfx_prs module
* is enabled.
*/
nrfx_err_t nrfx_spi_init(nrfx_spi_t const * const p_instance,
nrfx_spi_config_t const * p_config,
nrfx_spi_evt_handler_t handler,
void * p_context);
/**
* @brief Function for uninitializing the SPI master driver instance.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_spi_uninit(nrfx_spi_t const * const p_instance);
/**
* @brief Function for starting the SPI data transfer.
*
* If an event handler was provided in the @ref nrfx_spi_init call, this function
* returns immediately and the handler is called when the transfer is done.
* Otherwise, the transfer is performed in blocking mode, which means that this function
* returns when the transfer is finished.
*
* @param p_instance Pointer to the driver instance structure.
* @param p_xfer_desc Pointer to the transfer descriptor.
* @param flags Transfer options (0 for default settings).
* Currently, no additional flags are available.
*
* @retval NRFX_SUCCESS The procedure is successful.
* @retval NRFX_ERROR_BUSY The driver is not ready for a new transfer.
* @retval NRFX_ERROR_NOT_SUPPORTED The provided parameters are not supported.
*/
nrfx_err_t nrfx_spi_xfer(nrfx_spi_t const * const p_instance,
nrfx_spi_xfer_desc_t const * p_xfer_desc,
uint32_t flags);
/**
* @brief Function for aborting the ongoing transfer.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_spi_abort(nrfx_spi_t const * p_instance);
/** @} */
void nrfx_spi_0_irq_handler(void);
void nrfx_spi_1_irq_handler(void);
void nrfx_spi_2_irq_handler(void);
#ifdef __cplusplus
}
#endif
#endif // NRFX_SPI_H__
+385
View File
@@ -0,0 +1,385 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_SPIM_H__
#define NRFX_SPIM_H__
#include <nrfx.h>
#include <hal/nrf_spim.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_spim SPIM driver
* @{
* @ingroup nrf_spim
* @brief Serial Peripheral Interface Master with EasyDMA (SPIM) driver.
*/
/** @brief Data structure of the Serial Peripheral Interface Master with EasyDMA (SPIM) driver instance. */
typedef struct
{
NRF_SPIM_Type * p_reg; ///< Pointer to a structure with SPIM registers.
uint8_t drv_inst_idx; ///< Index of the driver instance. For internal use only.
} nrfx_spim_t;
#ifndef __NRFX_DOXYGEN__
enum {
#if NRFX_CHECK(NRFX_SPIM0_ENABLED)
NRFX_SPIM0_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_SPIM1_ENABLED)
NRFX_SPIM1_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_SPIM2_ENABLED)
NRFX_SPIM2_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_SPIM3_ENABLED)
NRFX_SPIM3_INST_IDX,
#endif
NRFX_SPIM_ENABLED_COUNT
};
#endif
/** @brief Macro for creating an instance of the SPIM driver. */
#define NRFX_SPIM_INSTANCE(id) \
{ \
.p_reg = NRFX_CONCAT_2(NRF_SPIM, id), \
.drv_inst_idx = NRFX_CONCAT_3(NRFX_SPIM, id, _INST_IDX), \
}
/**
* @brief This value can be provided instead of a pin number for signals MOSI,
* MISO, and Slave Select to specify that the given signal is not used and
* therefore does not need to be connected to a pin.
*/
#define NRFX_SPIM_PIN_NOT_USED 0xFF
/** @brief Configuration structure of the SPIM driver instance. */
typedef struct
{
uint8_t sck_pin; ///< SCK pin number.
uint8_t mosi_pin; ///< MOSI pin number (optional).
/**< Set to @ref NRFX_SPIM_PIN_NOT_USED
* if this signal is not needed. */
uint8_t miso_pin; ///< MISO pin number (optional).
/**< Set to @ref NRFX_SPIM_PIN_NOT_USED
* if this signal is not needed. */
uint8_t ss_pin; ///< Slave Select pin number (optional).
/**< Set to @ref NRFX_SPIM_PIN_NOT_USED
* if this signal is not needed. */
bool ss_active_high; ///< Polarity of the Slave Select pin during transmission.
uint8_t irq_priority; ///< Interrupt priority.
uint8_t orc; ///< Overrun character.
/**< This character is used when all bytes from the TX buffer are sent,
but the transfer continues due to RX. */
nrf_spim_frequency_t frequency; ///< SPIM frequency.
nrf_spim_mode_t mode; ///< SPIM mode.
nrf_spim_bit_order_t bit_order; ///< SPIM bit order.
#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) || defined(__NRFX_DOXYGEN__)
uint8_t dcx_pin; ///< D/CX pin number (optional).
uint8_t rx_delay; ///< Sample delay for input serial data on MISO.
/**< The value specifies the delay, in number of 64 MHz clock cycles
* (15.625 ns), from the the sampling edge of SCK (leading edge for
* CONFIG.CPHA = 0, trailing edge for CONFIG.CPHA = 1) until
* the input serial data is sampled. */
bool use_hw_ss; ///< Indication to use software or hardware controlled Slave Select pin.
uint8_t ss_duration; ///< Slave Select duration before and after transmission.
/**< Minimum duration between the edge of CSN and the edge of SCK and minimum
* duration of CSN must stay inactive between transactions.
* The value is specified in number of 64 MHz clock cycles (15.625 ns).
* Supported only for hardware-controlled Slave Select. */
#endif
} nrfx_spim_config_t;
#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) || defined(__NRFX_DOXYGEN__)
/**
* @brief Extended default configuration of the SPIM instance.
*/
#define NRFX_SPIM_DEFAULT_EXTENDED_CONFIG \
.dcx_pin = NRFX_SPIM_PIN_NOT_USED, \
.rx_delay = 0x02, \
.use_hw_ss = false, \
.ss_duration = 0x02,
#else
#define NRFX_SPIM_DEFAULT_EXTENDED_CONFIG
#endif
/** @brief The default configuration of the SPIM master instance. */
#define NRFX_SPIM_DEFAULT_CONFIG \
{ \
.sck_pin = NRFX_SPIM_PIN_NOT_USED, \
.mosi_pin = NRFX_SPIM_PIN_NOT_USED, \
.miso_pin = NRFX_SPIM_PIN_NOT_USED, \
.ss_pin = NRFX_SPIM_PIN_NOT_USED, \
.ss_active_high = false, \
.irq_priority = NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY, \
.orc = 0xFF, \
.frequency = NRF_SPIM_FREQ_4M, \
.mode = NRF_SPIM_MODE_0, \
.bit_order = NRF_SPIM_BIT_ORDER_MSB_FIRST, \
NRFX_SPIM_DEFAULT_EXTENDED_CONFIG \
}
/** @brief Flag indicating that TX buffer address will be incremented after transfer. */
#define NRFX_SPIM_FLAG_TX_POSTINC (1UL << 0)
/** @brief Flag indicating that RX buffer address will be incremented after transfer. */
#define NRFX_SPIM_FLAG_RX_POSTINC (1UL << 1)
/** @brief Flag indicating that the interrupt after each transfer will be suppressed, and the event handler will not be called. */
#define NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER (1UL << 2)
/** @brief Flag indicating that the transfer will be set up, but not started. */
#define NRFX_SPIM_FLAG_HOLD_XFER (1UL << 3)
/** @brief Flag indicating that the transfer will be executed multiple times. */
#define NRFX_SPIM_FLAG_REPEATED_XFER (1UL << 4)
/** @brief Single transfer descriptor structure. */
typedef struct
{
uint8_t const * p_tx_buffer; ///< Pointer to TX buffer.
size_t tx_length; ///< TX buffer length.
uint8_t * p_rx_buffer; ///< Pointer to RX buffer.
size_t rx_length; ///< RX buffer length.
} nrfx_spim_xfer_desc_t;
/**
* @brief Macro for setting up single transfer descriptor.
*
* This macro is for internal use only.
*/
#define NRFX_SPIM_SINGLE_XFER(p_tx, tx_len, p_rx, rx_len) \
{ \
.p_tx_buffer = (uint8_t const *)(p_tx), \
.tx_length = (tx_len), \
.p_rx_buffer = (p_rx), \
.rx_length = (rx_len), \
}
/** @brief Macro for setting the duplex TX RX transfer. */
#define NRFX_SPIM_XFER_TRX(p_tx_buf, tx_length, p_rx_buf, rx_length) \
NRFX_SPIM_SINGLE_XFER(p_tx_buf, tx_length, p_rx_buf, rx_length)
/** @brief Macro for setting the TX transfer. */
#define NRFX_SPIM_XFER_TX(p_buf, length) \
NRFX_SPIM_SINGLE_XFER(p_buf, length, NULL, 0)
/** @brief Macro for setting the RX transfer. */
#define NRFX_SPIM_XFER_RX(p_buf, length) \
NRFX_SPIM_SINGLE_XFER(NULL, 0, p_buf, length)
/**
* @brief SPIM master driver event types, passed to the handler routine provided
* during initialization.
*/
typedef enum
{
NRFX_SPIM_EVENT_DONE, ///< Transfer done.
} nrfx_spim_evt_type_t;
/** @brief SPIM event description with transmission details. */
typedef struct
{
nrfx_spim_evt_type_t type; ///< Event type.
nrfx_spim_xfer_desc_t xfer_desc; ///< Transfer details.
} nrfx_spim_evt_t;
/** @brief SPIM driver event handler type. */
typedef void (* nrfx_spim_evt_handler_t)(nrfx_spim_evt_t const * p_event,
void * p_context);
/**
* @brief Function for initializing the SPIM driver instance.
*
* This function configures and enables the specified peripheral.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_config Pointer to the structure with the initial configuration.
* @param[in] handler Event handler provided by the user. If NULL, transfers
* will be performed in blocking mode.
* @param[in] p_context Context passed to event handler.
*
* @retval NRFX_SUCCESS Initialization was successful.
* @retval NRFX_ERROR_INVALID_STATE The driver was already initialized.
* @retval NRFX_ERROR_BUSY Some other peripheral with the same
* instance ID is already in use. This is
* possible only if @ref nrfx_prs module
* is enabled.
* @retval NRFX_ERROR_NOT_SUPPORTED Requested configuration is not supported
* by the SPIM instance.
*/
nrfx_err_t nrfx_spim_init(nrfx_spim_t const * const p_instance,
nrfx_spim_config_t const * p_config,
nrfx_spim_evt_handler_t handler,
void * p_context);
/**
* @brief Function for uninitializing the SPIM driver instance.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_spim_uninit(nrfx_spim_t const * const p_instance);
/**
* @brief Function for starting the SPIM data transfer.
*
* Additional options are provided using the @c flags parameter:
*
* - @ref NRFX_SPIM_FLAG_TX_POSTINC and @ref NRFX_SPIM_FLAG_RX_POSTINC -
* Post-incrementation of buffer addresses.
* - @ref NRFX_SPIM_FLAG_HOLD_XFER - Driver is not starting the transfer. Use this
* flag if the transfer is triggered externally by PPI. Use
* @ref nrfx_spim_start_task_get to get the address of the start task.
* - @ref NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER - No user event handler after transfer
* completion. This also means no interrupt at the end of the transfer.
* If @ref NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER is used, the driver does not set the instance into
* busy state, so you must ensure that the next transfers are set up when SPIM is not active.
* @ref nrfx_spim_end_event_get function can be used to detect end of transfer. Option can be used
* together with @ref NRFX_SPIM_FLAG_REPEATED_XFER to prepare a sequence of SPI transfers
* without interruptions.
* - @ref NRFX_SPIM_FLAG_REPEATED_XFER - Prepare for repeated transfers. You can set
* up a number of transfers that will be triggered externally (for example by PPI). An example is
* a TXRX transfer with the options @ref NRFX_SPIM_FLAG_RX_POSTINC,
* @ref NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER, and @ref NRFX_SPIM_FLAG_REPEATED_XFER. After the
* transfer is set up, a set of transfers can be triggered by PPI that will read, for example,
* the same register of an external component and put it into a RAM buffer without any interrupts.
* @ref nrfx_spim_end_event_get can be used to get the address of the END event, which can be
* used to count the number of transfers. If @ref NRFX_SPIM_FLAG_REPEATED_XFER is used,
* the driver does not set the instance into busy state, so you must ensure that the next
* transfers are set up when SPIM is not active.
*
* @note Peripherals using EasyDMA (including SPIM) require the transfer buffers
* to be placed in the Data RAM region. If this condition is not met,
* this function will fail with the error code NRFX_ERROR_INVALID_ADDR.
*
* @param p_instance Pointer to the driver instance structure.
* @param p_xfer_desc Pointer to the transfer descriptor.
* @param flags Transfer options (0 for default settings).
*
* @retval NRFX_SUCCESS The procedure is successful.
* @retval NRFX_ERROR_BUSY The driver is not ready for a new transfer.
* @retval NRFX_ERROR_NOT_SUPPORTED The provided parameters are not supported.
* @retval NRFX_ERROR_INVALID_ADDR The provided buffers are not placed in the Data
* RAM region.
*/
nrfx_err_t nrfx_spim_xfer(nrfx_spim_t const * const p_instance,
nrfx_spim_xfer_desc_t const * p_xfer_desc,
uint32_t flags);
#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for starting the SPIM data transfer with DCX control.
*
* See @ref nrfx_spim_xfer for description of additional options of transfer
* provided by the @c flags parameter.
*
* @note Peripherals that use EasyDMA (including SPIM) require the transfer buffers
* to be placed in the Data RAM region. If this condition is not met,
* this function will fail with the error code NRFX_ERROR_INVALID_ADDR.
*
* @param p_instance Pointer to the driver instance structure.
* @param p_xfer_desc Pointer to the transfer descriptor.
* @param flags Transfer options (0 for default settings).
* @param cmd_length Length of the command bytes preceding the data
* bytes. The DCX line will be low during transmission
* of command bytes and high during transmission of data bytes.
* Maximum value available for dividing the transmitted bytes
* into command bytes and data bytes is @ref NRF_SPIM_DCX_CNT_ALL_CMD - 1.
* The @ref NRF_SPIM_DCX_CNT_ALL_CMD value passed as the
* @c cmd_length parameter causes all transmitted bytes
* to be marked as command bytes.
*
* @retval NRFX_SUCCESS The procedure is successful.
* @retval NRFX_ERROR_BUSY The driver is not ready for a new transfer.
* @retval NRFX_ERROR_NOT_SUPPORTED The provided parameters are not supported.
* @retval NRFX_ERROR_INVALID_ADDR The provided buffers are not placed in the Data
* RAM region.
*/
nrfx_err_t nrfx_spim_xfer_dcx(nrfx_spim_t const * const p_instance,
nrfx_spim_xfer_desc_t const * p_xfer_desc,
uint32_t flags,
uint8_t cmd_length);
#endif
/**
* @brief Function for returning the address of a SPIM start task.
*
* This function is to be used if @ref nrfx_spim_xfer was called with the flag @ref NRFX_SPIM_FLAG_HOLD_XFER.
* In that case, the transfer is not started by the driver, but it must be started externally by PPI.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @return Start task address.
*/
uint32_t nrfx_spim_start_task_get(nrfx_spim_t const * p_instance);
/**
* @brief Function for returning the address of a END SPIM event.
*
* The END event can be used to detect the end of a transfer
* if the @ref NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER option is used.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @return END event address.
*/
uint32_t nrfx_spim_end_event_get(nrfx_spim_t const * p_instance);
/**
* @brief Function for aborting ongoing transfer.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_spim_abort(nrfx_spim_t const * p_instance);
/** @} */
void nrfx_spim_0_irq_handler(void);
void nrfx_spim_1_irq_handler(void);
void nrfx_spim_2_irq_handler(void);
void nrfx_spim_3_irq_handler(void);
#ifdef __cplusplus
}
#endif
#endif // NRFX_SPIM_H__
+409
View File
@@ -0,0 +1,409 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_TIMER_H__
#define NRFX_TIMER_H__
#include <nrfx.h>
#include <hal/nrf_timer.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_timer Timer driver
* @{
* @ingroup nrf_timer
* @brief TIMER peripheral driver.
*/
/**
* @brief Timer driver instance data structure.
*/
typedef struct
{
NRF_TIMER_Type * p_reg; ///< Pointer to the structure with TIMER peripheral instance registers.
uint8_t instance_id; ///< Index of the driver instance. For internal use only.
uint8_t cc_channel_count; ///< Number of capture/compare channels.
} nrfx_timer_t;
/** @brief Macro for creating a timer driver instance. */
#define NRFX_TIMER_INSTANCE(id) \
{ \
.p_reg = NRFX_CONCAT_2(NRF_TIMER, id), \
.instance_id = NRFX_CONCAT_3(NRFX_TIMER, id, _INST_IDX), \
.cc_channel_count = NRF_TIMER_CC_CHANNEL_COUNT(id), \
}
#ifndef __NRFX_DOXYGEN__
enum {
#if NRFX_CHECK(NRFX_TIMER0_ENABLED)
NRFX_TIMER0_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_TIMER1_ENABLED)
NRFX_TIMER1_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_TIMER2_ENABLED)
NRFX_TIMER2_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_TIMER3_ENABLED)
NRFX_TIMER3_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_TIMER4_ENABLED)
NRFX_TIMER4_INST_IDX,
#endif
NRFX_TIMER_ENABLED_COUNT
};
#endif
/** @brief The configuration structure of the timer driver instance. */
typedef struct
{
nrf_timer_frequency_t frequency; ///< Frequency.
nrf_timer_mode_t mode; ///< Mode of operation.
nrf_timer_bit_width_t bit_width; ///< Bit width.
uint8_t interrupt_priority; ///< Interrupt priority.
void * p_context; ///< Context passed to interrupt handler.
} nrfx_timer_config_t;
/** @brief Timer driver instance default configuration. */
#define NRFX_TIMER_DEFAULT_CONFIG \
{ \
.frequency = (nrf_timer_frequency_t)NRFX_TIMER_DEFAULT_CONFIG_FREQUENCY,\
.mode = (nrf_timer_mode_t)NRFX_TIMER_DEFAULT_CONFIG_MODE, \
.bit_width = (nrf_timer_bit_width_t)NRFX_TIMER_DEFAULT_CONFIG_BIT_WIDTH,\
.interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY, \
.p_context = NULL \
}
/**
* @brief Timer driver event handler type.
*
* @param[in] event_type Timer event.
* @param[in] p_context General purpose parameter set during initialization of
* the timer. This parameter can be used to pass
* additional information to the handler function, for
* example, the timer ID.
*/
typedef void (* nrfx_timer_event_handler_t)(nrf_timer_event_t event_type,
void * p_context);
/**
* @brief Function for initializing the timer.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_config Pointer to the structure with the initial configuration.
* @param[in] timer_event_handler Event handler provided by the user.
* Must not be NULL.
*
* @retval NRFX_SUCCESS Initialization was successful.
* @retval NRFX_ERROR_INVALID_STATE The instance is already initialized.
*/
nrfx_err_t nrfx_timer_init(nrfx_timer_t const * const p_instance,
nrfx_timer_config_t const * p_config,
nrfx_timer_event_handler_t timer_event_handler);
/**
* @brief Function for uninitializing the timer.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_timer_uninit(nrfx_timer_t const * const p_instance);
/**
* @brief Function for turning on the timer.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_timer_enable(nrfx_timer_t const * const p_instance);
/**
* @brief Function for turning off the timer.
*
* The timer will allow to enter the lowest possible SYSTEM_ON state
* only after this function is called.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_timer_disable(nrfx_timer_t const * const p_instance);
/**
* @brief Function for checking the timer state.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @retval true Timer is enabled.
* @retval false Timer is not enabled.
*/
bool nrfx_timer_is_enabled(nrfx_timer_t const * const p_instance);
/**
* @brief Function for pausing the timer.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_timer_pause(nrfx_timer_t const * const p_instance);
/**
* @brief Function for resuming the timer.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_timer_resume(nrfx_timer_t const * const p_instance);
/**
* @brief Function for clearing the timer.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_timer_clear(nrfx_timer_t const * const p_instance);
/**
* @brief Function for incrementing the timer.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_timer_increment(nrfx_timer_t const * const p_instance);
/**
* @brief Function for returning the address of the specified timer task.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] timer_task Timer task.
*
* @return Task address.
*/
__STATIC_INLINE uint32_t nrfx_timer_task_address_get(nrfx_timer_t const * const p_instance,
nrf_timer_task_t timer_task);
/**
* @brief Function for returning the address of the specified timer capture task.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] channel Capture channel number.
*
* @return Task address.
*/
__STATIC_INLINE uint32_t nrfx_timer_capture_task_address_get(nrfx_timer_t const * const p_instance,
uint32_t channel);
/**
* @brief Function for returning the address of the specified timer event.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] timer_event Timer event.
*
* @return Event address.
*/
__STATIC_INLINE uint32_t nrfx_timer_event_address_get(nrfx_timer_t const * const p_instance,
nrf_timer_event_t timer_event);
/**
* @brief Function for returning the address of the specified timer compare event.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] channel Compare channel number.
*
* @return Event address.
*/
__STATIC_INLINE uint32_t nrfx_timer_compare_event_address_get(nrfx_timer_t const * const p_instance,
uint32_t channel);
/**
* @brief Function for capturing the timer value.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] cc_channel Capture channel number.
*
* @return Captured value.
*/
uint32_t nrfx_timer_capture(nrfx_timer_t const * const p_instance,
nrf_timer_cc_channel_t cc_channel);
/**
* @brief Function for returning the capture value from the specified channel.
*
* Use this function to read channel values when PPI is used for capturing.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] cc_channel Capture channel number.
*
* @return Captured value.
*/
__STATIC_INLINE uint32_t nrfx_timer_capture_get(nrfx_timer_t const * const p_instance,
nrf_timer_cc_channel_t cc_channel);
/**
* @brief Function for setting the timer channel in compare mode.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] cc_channel Compare channel number.
* @param[in] cc_value Compare value.
* @param[in] enable_int Enable or disable the interrupt for the compare channel.
*/
void nrfx_timer_compare(nrfx_timer_t const * const p_instance,
nrf_timer_cc_channel_t cc_channel,
uint32_t cc_value,
bool enable_int);
/**
* @brief Function for setting the timer channel in the extended compare mode.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] cc_channel Compare channel number.
* @param[in] cc_value Compare value.
* @param[in] timer_short_mask Shortcut between the compare event on the channel
* and the timer task (STOP or CLEAR).
* @param[in] enable_int Enable or disable the interrupt for the compare channel.
*/
void nrfx_timer_extended_compare(nrfx_timer_t const * const p_instance,
nrf_timer_cc_channel_t cc_channel,
uint32_t cc_value,
nrf_timer_short_mask_t timer_short_mask,
bool enable_int);
/**
* @brief Function for converting time in microseconds to timer ticks.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] time_us Time in microseconds.
*
* @return Number of ticks.
*/
__STATIC_INLINE uint32_t nrfx_timer_us_to_ticks(nrfx_timer_t const * const p_instance,
uint32_t time_us);
/**
* @brief Function for converting time in milliseconds to timer ticks.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] time_ms Time in milliseconds.
*
* @return Number of ticks.
*/
__STATIC_INLINE uint32_t nrfx_timer_ms_to_ticks(nrfx_timer_t const * const p_instance,
uint32_t time_ms);
/**
* @brief Function for enabling timer compare interrupt.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] channel Compare channel.
*/
void nrfx_timer_compare_int_enable(nrfx_timer_t const * const p_instance,
uint32_t channel);
/**
* @brief Function for disabling timer compare interrupt.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] channel Compare channel.
*/
void nrfx_timer_compare_int_disable(nrfx_timer_t const * const p_instance,
uint32_t channel);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE uint32_t nrfx_timer_task_address_get(nrfx_timer_t const * const p_instance,
nrf_timer_task_t timer_task)
{
return (uint32_t)nrf_timer_task_address_get(p_instance->p_reg, timer_task);
}
__STATIC_INLINE uint32_t nrfx_timer_capture_task_address_get(nrfx_timer_t const * const p_instance,
uint32_t channel)
{
NRFX_ASSERT(channel < p_instance->cc_channel_count);
return (uint32_t)nrf_timer_task_address_get(p_instance->p_reg,
nrf_timer_capture_task_get(channel));
}
__STATIC_INLINE uint32_t nrfx_timer_event_address_get(nrfx_timer_t const * const p_instance,
nrf_timer_event_t timer_event)
{
return (uint32_t)nrf_timer_event_address_get(p_instance->p_reg, timer_event);
}
__STATIC_INLINE uint32_t nrfx_timer_compare_event_address_get(nrfx_timer_t const * const p_instance,
uint32_t channel)
{
NRFX_ASSERT(channel < p_instance->cc_channel_count);
return (uint32_t)nrf_timer_event_address_get(p_instance->p_reg,
nrf_timer_compare_event_get(channel));
}
__STATIC_INLINE uint32_t nrfx_timer_capture_get(nrfx_timer_t const * const p_instance,
nrf_timer_cc_channel_t cc_channel)
{
return nrf_timer_cc_read(p_instance->p_reg, cc_channel);
}
__STATIC_INLINE uint32_t nrfx_timer_us_to_ticks(nrfx_timer_t const * const p_instance,
uint32_t timer_us)
{
return nrf_timer_us_to_ticks(timer_us, nrf_timer_frequency_get(p_instance->p_reg));
}
__STATIC_INLINE uint32_t nrfx_timer_ms_to_ticks(nrfx_timer_t const * const p_instance,
uint32_t timer_ms)
{
return nrf_timer_ms_to_ticks(timer_ms, nrf_timer_frequency_get(p_instance->p_reg));
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
void nrfx_timer_0_irq_handler(void);
void nrfx_timer_1_irq_handler(void);
void nrfx_timer_2_irq_handler(void);
void nrfx_timer_3_irq_handler(void);
void nrfx_timer_4_irq_handler(void);
#ifdef __cplusplus
}
#endif
#endif // NRFX_TIMER_H__
+407
View File
@@ -0,0 +1,407 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_TWI_H__
#define NRFX_TWI_H__
#include <nrfx.h>
#include <nrfx_twi_twim.h>
#include <hal/nrf_twi.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_twi TWI driver
* @{
* @ingroup nrf_twi
* @brief Two Wire Interface master (TWI) peripheral driver.
*/
/**
* @brief Structure for the TWI master driver instance.
*/
typedef struct
{
NRF_TWI_Type * p_twi; ///< Pointer to a structure with TWI registers.
uint8_t drv_inst_idx; ///< Index of the driver instance. For internal use only.
} nrfx_twi_t;
/** @brief Macro for creating a TWI master driver instance. */
#define NRFX_TWI_INSTANCE(id) \
{ \
.p_twi = NRFX_CONCAT_2(NRF_TWI, id), \
.drv_inst_idx = NRFX_CONCAT_3(NRFX_TWI, id, _INST_IDX), \
}
#ifndef __NRFX_DOXYGEN__
enum {
#if NRFX_CHECK(NRFX_TWI0_ENABLED)
NRFX_TWI0_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_TWI1_ENABLED)
NRFX_TWI1_INST_IDX,
#endif
NRFX_TWI_ENABLED_COUNT
};
#endif
/** @brief Structure for the configuration of the TWI master driver instance. */
typedef struct
{
uint32_t scl; ///< SCL pin number.
uint32_t sda; ///< SDA pin number.
nrf_twi_frequency_t frequency; ///< TWI frequency.
uint8_t interrupt_priority; ///< Interrupt priority.
bool hold_bus_uninit; ///< Hold pull up state on GPIO pins after uninit.
} nrfx_twi_config_t;
/** @brief The default configuration of the TWI master driver instance. */
#define NRFX_TWI_DEFAULT_CONFIG \
{ \
.frequency = (nrf_twi_frequency_t)NRFX_TWI_DEFAULT_CONFIG_FREQUENCY, \
.scl = 31, \
.sda = 31, \
.interrupt_priority = NRFX_TWI_DEFAULT_CONFIG_IRQ_PRIORITY, \
.hold_bus_uninit = NRFX_TWI_DEFAULT_CONFIG_HOLD_BUS_UNINIT, \
}
/** @brief Flag indicating that the interrupt after each transfer will be suppressed, and the event handler will not be called. */
#define NRFX_TWI_FLAG_NO_XFER_EVT_HANDLER (1UL << 2)
/** @brief Flag indicating that the TX transfer will not end with a stop condition. */
#define NRFX_TWI_FLAG_TX_NO_STOP (1UL << 5)
/** @brief Flag indicating that the transfer will be suspended. */
#define NRFX_TWI_FLAG_SUSPEND (1UL << 6)
/** @brief TWI master driver event types. */
typedef enum
{
NRFX_TWI_EVT_DONE, ///< Transfer completed event.
NRFX_TWI_EVT_ADDRESS_NACK, ///< Error event: NACK received after sending the address.
NRFX_TWI_EVT_DATA_NACK, ///< Error event: NACK received after sending a data byte.
NRFX_TWI_EVT_OVERRUN, ///< Error event: The unread data is replaced by new data.
NRFX_TWI_EVT_BUS_ERROR ///< Error event: An unexpected transition occurred on the bus.
} nrfx_twi_evt_type_t;
/** @brief TWI master driver transfer types. */
typedef enum
{
NRFX_TWI_XFER_TX, ///< TX transfer.
NRFX_TWI_XFER_RX, ///< RX transfer.
NRFX_TWI_XFER_TXRX, ///< TX transfer followed by RX transfer with repeated start.
NRFX_TWI_XFER_TXTX ///< TX transfer followed by TX transfer with repeated start.
} nrfx_twi_xfer_type_t;
/** @brief Structure for a TWI transfer descriptor. */
typedef struct
{
nrfx_twi_xfer_type_t type; ///< Type of transfer.
uint8_t address; ///< Slave address.
size_t primary_length; ///< Number of bytes transferred.
size_t secondary_length; ///< Number of bytes transferred.
uint8_t * p_primary_buf; ///< Pointer to transferred data.
uint8_t * p_secondary_buf; ///< Pointer to transferred data.
} nrfx_twi_xfer_desc_t;
/** @brief Macro for setting the TX transfer descriptor. */
#define NRFX_TWI_XFER_DESC_TX(addr, p_data, length) \
{ \
.type = NRFX_TWI_XFER_TX, \
.address = (addr), \
.primary_length = (length), \
.secondary_length = 0, \
.p_primary_buf = (p_data), \
.p_secondary_buf = NULL, \
}
/** @brief Macro for setting the RX transfer descriptor. */
#define NRFX_TWI_XFER_DESC_RX(addr, p_data, length) \
{ \
.type = NRFX_TWI_XFER_RX, \
.address = (addr), \
.primary_length = (length), \
.secondary_length = 0, \
.p_primary_buf = (p_data), \
.p_secondary_buf = NULL, \
}
/** @brief Macro for setting the TX-RX transfer descriptor. */
#define NRFX_TWI_XFER_DESC_TXRX(addr, p_tx, tx_len, p_rx, rx_len) \
{ \
.type = NRFX_TWI_XFER_TXRX, \
.address = (addr), \
.primary_length = (tx_len), \
.secondary_length = (rx_len), \
.p_primary_buf = (p_tx), \
.p_secondary_buf = (p_rx), \
}
/** @brief Macro for setting the TX-TX transfer descriptor. */
#define NRFX_TWI_XFER_DESC_TXTX(addr, p_tx, tx_len, p_tx2, tx_len2) \
{ \
.type = NRFX_TWI_XFER_TXTX, \
.address = (addr), \
.primary_length = (tx_len), \
.secondary_length = (tx_len2), \
.p_primary_buf = (p_tx), \
.p_secondary_buf = (p_tx2), \
}
/** @brief Structure for a TWI event. */
typedef struct
{
nrfx_twi_evt_type_t type; ///< Event type.
nrfx_twi_xfer_desc_t xfer_desc; ///< Transfer details.
} nrfx_twi_evt_t;
/** @brief TWI event handler prototype. */
typedef void (* nrfx_twi_evt_handler_t)(nrfx_twi_evt_t const * p_event,
void * p_context);
/**
* @brief Function for initializing the TWI driver instance.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_config Pointer to the structure with the initial configuration.
* @param[in] event_handler Event handler provided by the user. If NULL, blocking mode is enabled.
* @param[in] p_context Context passed to event handler.
*
* @retval NRFX_SUCCESS Initialization is successful.
* @retval NRFX_ERROR_INVALID_STATE The driver is in invalid state.
* @retval NRFX_ERROR_BUSY Some other peripheral with the same
* instance ID is already in use. This is
* possible only if @ref nrfx_prs module
* is enabled.
*/
nrfx_err_t nrfx_twi_init(nrfx_twi_t const * p_instance,
nrfx_twi_config_t const * p_config,
nrfx_twi_evt_handler_t event_handler,
void * p_context);
/**
* @brief Function for uninitializing the TWI instance.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_twi_uninit(nrfx_twi_t const * p_instance);
/**
* @brief Function for enabling the TWI instance.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_twi_enable(nrfx_twi_t const * p_instance);
/**
* @brief Function for disabling the TWI instance.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_twi_disable(nrfx_twi_t const * p_instance);
/**
* @brief Function for sending data to a TWI slave.
*
* The transmission will be stopped when an error occurs. If a transfer is ongoing,
* the function returns the error code @ref NRFX_ERROR_BUSY.
*
* @note This function is deprecated. Use @ref nrfx_twi_xfer instead.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] address Address of a specific slave device (only 7 LSB).
* @param[in] p_data Pointer to a transmit buffer.
* @param[in] length Number of bytes to send.
* @param[in] no_stop If set, the stop condition is not generated on the bus
* after the transfer has completed successfully (allowing
* for a repeated start in the next transfer).
*
* @retval NRFX_SUCCESS The procedure is successful.
* @retval NRFX_ERROR_BUSY The driver is not ready for a new transfer.
* @retval NRFX_ERROR_INTERNAL An error is detected by hardware.
* @retval NRFX_ERROR_INVALID_STATE RX transaction is suspended on bus.
* @retval NRFX_ERROR_DRV_TWI_ERR_ANACK Negative acknowledgement (NACK) is received after sending
* the address in polling mode.
* @retval NRFX_ERROR_DRV_TWI_ERR_DNACK Negative acknowledgement (NACK) is received after sending
* a data byte in polling mode.
*/
nrfx_err_t nrfx_twi_tx(nrfx_twi_t const * p_instance,
uint8_t address,
uint8_t const * p_data,
size_t length,
bool no_stop);
/**
* @brief Function for reading data from a TWI slave.
*
* The transmission will be stopped when an error occurs. If a transfer is ongoing,
* the function returns the error code @ref NRFX_ERROR_BUSY.
*
* @note This function is deprecated. Use @ref nrfx_twi_xfer instead.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] address Address of a specific slave device (only 7 LSB).
* @param[in] p_data Pointer to a receive buffer.
* @param[in] length Number of bytes to be received.
*
* @retval NRFX_SUCCESS The procedure is successful.
* @retval NRFX_ERROR_BUSY The driver is not ready for a new transfer.
* @retval NRFX_ERROR_INTERNAL An error is detected by hardware.
* @retval NRFX_ERROR_INVALID_STATE TX transaction is suspended on bus.
* @retval NRFX_ERROR_DRV_TWI_ERR_OVERRUN The unread data is replaced by new data.
* @retval NRFX_ERROR_DRV_TWI_ERR_ANACK Negative acknowledgement (NACK) is received after sending
* the address in polling mode.
* @retval NRFX_ERROR_DRV_TWI_ERR_DNACK Negative acknowledgement (NACK) is received after sending
* a data byte in polling mode.
*/
nrfx_err_t nrfx_twi_rx(nrfx_twi_t const * p_instance,
uint8_t address,
uint8_t * p_data,
size_t length);
/**
* @brief Function for performing a TWI transfer.
*
* The following transfer types can be configured (@ref nrfx_twi_xfer_desc_t::type):
* - @ref NRFX_TWI_XFER_TXRX - Write operation followed by a read operation (without STOP condition in between).
* - @ref NRFX_TWI_XFER_TXTX - Write operation followed by a write operation (without STOP condition in between).
* - @ref NRFX_TWI_XFER_TX - Write operation (with or without STOP condition).
* - @ref NRFX_TWI_XFER_RX - Read operation (with STOP condition).
*
* @note TX-RX and TX-TX transfers are supported only in non-blocking mode.
*
* Additional options are provided using the flags parameter:
* - @ref NRFX_TWI_FLAG_NO_XFER_EVT_HANDLER - No user event handler after transfer completion. In most cases, this also means no interrupt at the end of the transfer.
* - @ref NRFX_TWI_FLAG_TX_NO_STOP - No stop condition after TX transfer.
* - @ref NRFX_TWI_FLAG_SUSPEND - Transfer will be suspended. This allows for combining multiple transfers into one transaction.
* Only transactions with the same direction can be combined. To finish the transaction, call the function without this flag.
*
* @note
* Some flag combinations are invalid:
* - @ref NRFX_TWI_FLAG_TX_NO_STOP with @ref nrfx_twi_xfer_desc_t::type different than @ref NRFX_TWI_XFER_TX
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_xfer_desc Pointer to the transfer descriptor.
* @param[in] flags Transfer options (0 for default settings).
*
* @retval NRFX_SUCCESS The procedure is successful.
* @retval NRFX_ERROR_BUSY The driver is not ready for a new transfer.
* @retval NRFX_ERROR_NOT_SUPPORTED The provided parameters are not supported.
* @retval NRFX_ERROR_INTERNAL An unexpected transition occurred on the bus.
* @retval NRFX_ERROR_INVALID_STATE Other direction of transaction is suspended on the bus.
* @retval NRFX_ERROR_DRV_TWI_ERR_OVERRUN The unread data is replaced by new data (TXRX and RX)
* @retval NRFX_ERROR_DRV_TWI_ERR_ANACK Negative acknowledgement (NACK) is received after sending
* the address in polling mode.
* @retval NRFX_ERROR_DRV_TWI_ERR_DNACK Negative acknowledgement (NACK) is received after sending
* a data byte in polling mode.
*/
nrfx_err_t nrfx_twi_xfer(nrfx_twi_t const * p_instance,
nrfx_twi_xfer_desc_t const * p_xfer_desc,
uint32_t flags);
/**
* @brief Function for checking the TWI driver state.
*
* @param[in] p_instance TWI instance.
*
* @retval true The TWI driver is currently busy performing a transfer.
* @retval false The TWI driver is ready for a new transfer.
*/
bool nrfx_twi_is_busy(nrfx_twi_t const * p_instance);
/**
* @brief Function for getting the transferred data count.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @return Data count.
*/
size_t nrfx_twi_data_count_get(nrfx_twi_t const * const p_instance);
/**
* @brief Function for returning the address of a STOPPED TWI event.
*
* A STOPPED event can be used to detect the end of a transfer if the @ref NRFX_TWI_FLAG_NO_XFER_EVT_HANDLER
* option is used.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @return STOPPED event address.
*/
uint32_t nrfx_twi_stopped_event_get(nrfx_twi_t const * p_instance);
/**
* @brief Function for recovering the bus.
*
* This function checks if the bus is not stuck because of a slave holding the SDA line in the low state,
* and if needed it performs required number of pulses on the SCL line to make the slave release the SDA line.
* Finally, the function generates a STOP condition on the bus to put it into a known state.
*
* @note This function can be used only if the TWI driver is uninitialized.
*
* @param[in] scl_pin SCL pin number.
* @param[in] sda_pin SDA pin number.
*
* @retval NRFX_SUCCESS Bus recovery was successful.
* @retval NRFX_ERROR_INTERNAL Bus recovery failed.
*/
__STATIC_INLINE nrfx_err_t nrfx_twi_bus_recover(uint32_t scl_pin, uint32_t sda_pin);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE nrfx_err_t nrfx_twi_bus_recover(uint32_t scl_pin, uint32_t sda_pin)
{
return nrfx_twi_twim_bus_recover(scl_pin, sda_pin);
}
#endif
/** @} */
void nrfx_twi_0_irq_handler(void);
void nrfx_twi_1_irq_handler(void);
#ifdef __cplusplus
}
#endif
#endif // NRFX_TWI_H__
@@ -0,0 +1,56 @@
/**
* Copyright (c) 2019 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_TWI_TWIM_H
#define NRFX_TWI_TWIM_H
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
nrfx_err_t nrfx_twi_twim_bus_recover(uint32_t scl_pin, uint32_t sda_pin);
#ifdef __cplusplus
}
#endif
#endif // NRFX_TWI_TWIM_H
+448
View File
@@ -0,0 +1,448 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_TWIM_H__
#define NRFX_TWIM_H__
#include <nrfx.h>
#include <nrfx_twi_twim.h>
#include <hal/nrf_twim.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_twim TWIM driver
* @{
* @ingroup nrf_twim
* @brief Two Wire Interface Master with EasyDMA (TWIM) peripheral driver.
*/
/** @brief Structure for the TWI master driver instance. */
typedef struct
{
NRF_TWIM_Type * p_twim; ///< Pointer to a structure with TWIM registers.
uint8_t drv_inst_idx; ///< Index of the driver instance. For internal use only.
} nrfx_twim_t;
/** @brief Macro for creating a TWI master driver instance. */
#define NRFX_TWIM_INSTANCE(id) \
{ \
.p_twim = NRFX_CONCAT_2(NRF_TWIM, id), \
.drv_inst_idx = NRFX_CONCAT_3(NRFX_TWIM, id, _INST_IDX), \
}
#ifndef __NRFX_DOXYGEN__
enum {
#if NRFX_CHECK(NRFX_TWIM0_ENABLED)
NRFX_TWIM0_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_TWIM1_ENABLED)
NRFX_TWIM1_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_TWIM2_ENABLED)
NRFX_TWIM2_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_TWIM3_ENABLED)
NRFX_TWIM3_INST_IDX,
#endif
NRFX_TWIM_ENABLED_COUNT
};
#endif
/** @brief Structure for the TWI master driver instance configuration. */
typedef struct
{
uint32_t scl; ///< SCL pin number.
uint32_t sda; ///< SDA pin number.
nrf_twim_frequency_t frequency; ///< TWIM frequency.
uint8_t interrupt_priority; ///< Interrupt priority.
bool hold_bus_uninit; ///< Hold pull up state on GPIO pins after uninit.
} nrfx_twim_config_t;
/** @brief TWI master driver instance default configuration. */
#define NRFX_TWIM_DEFAULT_CONFIG \
{ \
.scl = 31, \
.sda = 31, \
.frequency = (nrf_twim_frequency_t)NRFX_TWIM_DEFAULT_CONFIG_FREQUENCY, \
.interrupt_priority = NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY, \
.hold_bus_uninit = NRFX_TWIM_DEFAULT_CONFIG_HOLD_BUS_UNINIT, \
}
/** @brief Flag indicating that TX buffer address will be incremented after the transfer. */
#define NRFX_TWIM_FLAG_TX_POSTINC (1UL << 0)
/** @brief Flag indicating that RX buffer address will be incremented after the transfer. */
#define NRFX_TWIM_FLAG_RX_POSTINC (1UL << 1)
/** @brief Flag indicating that the interrupt after each transfer will be suppressed, and the event handler will not be called. */
#define NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER (1UL << 2)
/** @brief Flag indicating that the transfer will be set up, but not started. */
#define NRFX_TWIM_FLAG_HOLD_XFER (1UL << 3)
/** @brief Flag indicating that the transfer will be executed multiple times. */
#define NRFX_TWIM_FLAG_REPEATED_XFER (1UL << 4)
/** @brief Flag indicating that the TX transfer will not end with a stop condition. */
#define NRFX_TWIM_FLAG_TX_NO_STOP (1UL << 5)
/** @brief Flag indicating that checks for spurious STOP condition will not be performed. */
#define NRFX_TWIM_FLAG_NO_SPURIOUS_STOP_CHECK (1UL << 6)
/** @brief TWI master driver event types. */
typedef enum
{
NRFX_TWIM_EVT_DONE, ///< Transfer completed event.
NRFX_TWIM_EVT_ADDRESS_NACK, ///< Error event: NACK received after sending the address.
NRFX_TWIM_EVT_DATA_NACK, ///< Error event: NACK received after sending a data byte.
NRFX_TWIM_EVT_OVERRUN, ///< Error event: The unread data is replaced by new data.
NRFX_TWIM_EVT_BUS_ERROR ///< Error event: An unexpected transition occurred on the bus.
} nrfx_twim_evt_type_t;
/** @brief TWI master driver transfer types. */
typedef enum
{
NRFX_TWIM_XFER_TX, ///< TX transfer.
NRFX_TWIM_XFER_RX, ///< RX transfer.
NRFX_TWIM_XFER_TXRX, ///< TX transfer followed by RX transfer with repeated start.
NRFX_TWIM_XFER_TXTX ///< TX transfer followed by TX transfer with repeated start.
} nrfx_twim_xfer_type_t;
/** @brief Structure for a TWI transfer descriptor. */
typedef struct
{
nrfx_twim_xfer_type_t type; ///< Type of transfer.
uint8_t address; ///< Slave address.
size_t primary_length; ///< Number of bytes transferred.
size_t secondary_length; ///< Number of bytes transferred.
uint8_t * p_primary_buf; ///< Pointer to transferred data.
uint8_t * p_secondary_buf; ///< Pointer to transferred data.
} nrfx_twim_xfer_desc_t;
/** @brief Macro for setting the TX transfer descriptor. */
#define NRFX_TWIM_XFER_DESC_TX(addr, p_data, length) \
{ \
.type = NRFX_TWIM_XFER_TX, \
.address = (addr), \
.primary_length = (length), \
.secondary_length = 0, \
.p_primary_buf = (p_data), \
.p_secondary_buf = NULL, \
}
/** @brief Macro for setting the RX transfer descriptor. */
#define NRFX_TWIM_XFER_DESC_RX(addr, p_data, length) \
{ \
.type = NRFX_TWIM_XFER_RX, \
.address = (addr), \
.primary_length = (length), \
.secondary_length = 0, \
.p_primary_buf = (p_data), \
.p_secondary_buf = NULL, \
}
/** @brief Macro for setting the TX-RX transfer descriptor. */
#define NRFX_TWIM_XFER_DESC_TXRX(addr, p_tx, tx_len, p_rx, rx_len) \
{ \
.type = NRFX_TWIM_XFER_TXRX, \
.address = (addr), \
.primary_length = (tx_len), \
.secondary_length = (rx_len), \
.p_primary_buf = (p_tx), \
.p_secondary_buf = (p_rx), \
}
/** @brief Macro for setting the TX-TX transfer descriptor. */
#define NRFX_TWIM_XFER_DESC_TXTX(addr, p_tx, tx_len, p_tx2, tx_len2) \
{ \
.type = NRFX_TWIM_XFER_TXTX, \
.address = (addr), \
.primary_length = (tx_len), \
.secondary_length = (tx_len2), \
.p_primary_buf = (p_tx), \
.p_secondary_buf = (p_tx2), \
}
/** @brief Structure for a TWI event. */
typedef struct
{
nrfx_twim_evt_type_t type; ///< Event type.
nrfx_twim_xfer_desc_t xfer_desc; ///< Transfer details.
} nrfx_twim_evt_t;
/** @brief TWI event handler prototype. */
typedef void (* nrfx_twim_evt_handler_t)(nrfx_twim_evt_t const * p_event,
void * p_context);
/**
* @brief Function for initializing the TWI driver instance.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_config Pointer to the structure with the initial configuration.
* @param[in] event_handler Event handler provided by the user. If NULL, blocking mode is enabled.
* @param[in] p_context Context passed to event handler.
*
* @retval NRFX_SUCCESS Initialization was successful.
* @retval NRFX_ERROR_INVALID_STATE The driver is in invalid state.
* @retval NRFX_ERROR_BUSY Some other peripheral with the same
* instance ID is already in use. This is
* possible only if @ref nrfx_prs module
* is enabled.
*/
nrfx_err_t nrfx_twim_init(nrfx_twim_t const * p_instance,
nrfx_twim_config_t const * p_config,
nrfx_twim_evt_handler_t event_handler,
void * p_context);
/**
* @brief Function for uninitializing the TWI instance.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_twim_uninit(nrfx_twim_t const * p_instance);
/**
* @brief Function for enabling the TWI instance.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_twim_enable(nrfx_twim_t const * p_instance);
/**
* @brief Function for disabling the TWI instance.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_twim_disable(nrfx_twim_t const * p_instance);
/**
* @brief Function for sending data to a TWI slave.
*
* The transmission will be stopped when an error occurs. If a transfer is ongoing,
* the function returns the error code @ref NRFX_ERROR_BUSY.
*
* @note This function is deprecated. Use @ref nrfx_twim_xfer instead.
*
* @note Peripherals using EasyDMA (including TWIM) require the transfer buffers
* to be placed in the Data RAM region. If this condition is not met,
* this function fails with the error code NRFX_ERROR_INVALID_ADDR.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] address Address of a specific slave device (only 7 LSB).
* @param[in] p_data Pointer to a transmit buffer.
* @param[in] length Number of bytes to send. Maximum possible length is
* dependent on the used SoC (see the MAXCNT register
* description in the Product Specification). The driver
* checks it with assertion.
* @param[in] no_stop If set, the stop condition is not generated on the bus
* after the transfer has completed successfully (allowing
* for a repeated start in the next transfer).
*
* @retval NRFX_SUCCESS The procedure is successful.
* @retval NRFX_ERROR_BUSY The driver is not ready for a new transfer.
* @retval NRFX_ERROR_INTERNAL An unexpected transition occurred on the bus.
* @retval NRFX_ERROR_INVALID_ADDR The provided buffer is not placed in the Data RAM region.
* @retval NRFX_ERROR_DRV_TWI_ERR_ANACK NACK is received after sending the address in polling mode.
* @retval NRFX_ERROR_DRV_TWI_ERR_DNACK NACK is received after sending a data byte in polling mode.
*/
nrfx_err_t nrfx_twim_tx(nrfx_twim_t const * p_instance,
uint8_t address,
uint8_t const * p_data,
size_t length,
bool no_stop);
/**
* @brief Function for reading data from a TWI slave.
*
* The transmission will be stopped when an error occurs. If a transfer is ongoing,
* the function returns the error code @ref NRFX_ERROR_BUSY.
*
* @note This function is deprecated. Use @ref nrfx_twim_xfer instead.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] address Address of a specific slave device (only 7 LSB).
* @param[in] p_data Pointer to a receive buffer.
* @param[in] length Number of bytes to be received. Maximum possible length
* is dependent on the used SoC (see the MAXCNT register
* description in the Product Specification). The driver
* checks it with assertion.
*
* @retval NRFX_SUCCESS The procedure is successful.
* @retval NRFX_ERROR_BUSY The driver is not ready for a new transfer.
* @retval NRFX_ERROR_INTERNAL An unexpected transition occurred on the bus.
* @retval NRFX_ERROR_DRV_TWI_ERR_OVERRUN The unread data is replaced by new data.
* @retval NRFX_ERROR_DRV_TWI_ERR_ANACK NACK is received after sending the address in polling mode.
* @retval NRFX_ERROR_DRV_TWI_ERR_DNACK NACK is received after sending a data byte in polling mode.
*/
nrfx_err_t nrfx_twim_rx(nrfx_twim_t const * p_instance,
uint8_t address,
uint8_t * p_data,
size_t length);
/**
* @brief Function for performing a TWI transfer.
*
* The following transfer types can be configured (@ref nrfx_twim_xfer_desc_t::type):
* - @ref NRFX_TWIM_XFER_TXRX - Write operation followed by a read operation (without STOP condition in between).
* - @ref NRFX_TWIM_XFER_TXTX - Write operation followed by a write operation (without STOP condition in between).
* - @ref NRFX_TWIM_XFER_TX - Write operation (with or without STOP condition).
* - @ref NRFX_TWIM_XFER_RX - Read operation (with STOP condition).
*
* @note TX-RX and TX-TX transfers are supported only in non-blocking mode.
*
* Additional options are provided using the flags parameter:
* - @ref NRFX_TWIM_FLAG_TX_POSTINC and @ref NRFX_TWIM_FLAG_RX_POSTINC - Post-incrementation of buffer addresses.
* - @ref NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER - No user event handler after the transfer completion. In most cases, this also means no interrupt at the end of the transfer.
* - @ref NRFX_TWIM_FLAG_HOLD_XFER - Driver is not starting the transfer. Use this flag if the transfer is triggered externally by PPI.
* Use @ref nrfx_twim_start_task_get to get the address of the start task.
* - @ref NRFX_TWIM_FLAG_REPEATED_XFER - Prepare for repeated transfers. You can set up a number of transfers that will be triggered externally (for example by PPI).
* An example is a TXRX transfer with the options @ref NRFX_TWIM_FLAG_RX_POSTINC, @ref NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER, and @ref NRFX_TWIM_FLAG_REPEATED_XFER.
* After the transfer is set up, a set of transfers can be triggered by PPI that will read, for example, the same register of an
* external component and put it into a RAM buffer without any interrupts. @ref nrfx_twim_stopped_event_get can be used to get the
* address of the STOPPED event, which can be used to count the number of transfers. If @ref NRFX_TWIM_FLAG_REPEATED_XFER is used,
* the driver does not set the driver instance into busy state, so you must ensure that the next transfers are set up
* when TWIM is not active.
* - @ref NRFX_TWIM_FLAG_TX_NO_STOP - No stop condition after the TX transfer.
* - @ref NRFX_TWIM_FLAG_NO_SPURIOUS_STOP_CHECK - Checks for spurious STOP conditions are disabled.
* Used together with @ref NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER can result in lower power consumption
* when transfers are triggered externally and CPU is sleeping.
* Use only with I2C standard-compliant slave devices.
*
* @note
* Some flag combinations are invalid:
* - @ref NRFX_TWIM_FLAG_TX_NO_STOP with @ref nrfx_twim_xfer_desc_t::type different than @ref NRFX_TWIM_XFER_TX
* - @ref NRFX_TWIM_FLAG_REPEATED_XFER with @ref nrfx_twim_xfer_desc_t::type set to @ref NRFX_TWIM_XFER_TXTX
*
* If @ref nrfx_twim_xfer_desc_t::type is set to @ref NRFX_TWIM_XFER_TX and the @ref NRFX_TWIM_FLAG_TX_NO_STOP and @ref NRFX_TWIM_FLAG_REPEATED_XFER
* flags are set, two tasks must be used to trigger a transfer: TASKS_RESUME followed by TASKS_STARTTX. If no stop condition is generated,
* TWIM is in SUSPENDED state. Therefore, it must be resumed before the transfer can be started.
*
* @note Peripherals using EasyDMA (including TWIM) require the transfer buffers
* to be placed in the Data RAM region. If this condition is not met,
* this function will fail with the error code NRFX_ERROR_INVALID_ADDR.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_xfer_desc Pointer to the transfer descriptor.
* @param[in] flags Transfer options (0 for default settings).
*
* @retval NRFX_SUCCESS The procedure is successful.
* @retval NRFX_ERROR_BUSY The driver is not ready for a new transfer.
* @retval NRFX_ERROR_NOT_SUPPORTED The provided parameters are not supported.
* @retval NRFX_ERROR_INTERNAL An unexpected transition occurred on the bus.
* @retval NRFX_ERROR_INVALID_ADDR The provided buffers are not placed in the Data RAM region.
* @retval NRFX_ERROR_DRV_TWI_ERR_OVERRUN The unread data is replaced by new data.
* @retval NRFX_ERROR_DRV_TWI_ERR_ANACK NACK is received after sending the address.
* @retval NRFX_ERROR_DRV_TWI_ERR_DNACK NACK is received after sending a data byte.
*/
nrfx_err_t nrfx_twim_xfer(nrfx_twim_t const * p_instance,
nrfx_twim_xfer_desc_t const * p_xfer_desc,
uint32_t flags);
/**
* @brief Function for checking the TWI driver state.
*
* @param[in] p_instance TWI instance.
*
* @retval true The TWI driver is currently busy performing a transfer.
* @retval false The TWI driver is ready for a new transfer.
*/
bool nrfx_twim_is_busy(nrfx_twim_t const * p_instance);
/**
* @brief Function for returning the address of a TWIM start task.
*
* This function is to be used if @ref nrfx_twim_xfer was called with the flag @ref NRFX_TWIM_FLAG_HOLD_XFER.
* In that case, the transfer is not started by the driver, but it must be started externally by PPI.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] xfer_type Transfer type used in the last call of the @ref nrfx_twim_xfer function.
*
* @return Start task address (TX or RX) depending on the value of xfer_type.
*/
uint32_t nrfx_twim_start_task_get(nrfx_twim_t const * p_instance, nrfx_twim_xfer_type_t xfer_type);
/**
* @brief Function for returning the address of a STOPPED TWIM event.
*
* A STOPPED event can be used to detect the end of a transfer if the @ref NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER
* option is used.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @return STOPPED event address.
*/
uint32_t nrfx_twim_stopped_event_get(nrfx_twim_t const * p_instance);
/**
* @brief Function for recovering the bus.
*
* This function checks if the bus is not stuck because of a slave holding the SDA line in the low state,
* and if needed it performs required number of pulses on the SCL line to make the slave release the SDA line.
* Finally, the function generates a STOP condition on the bus to put it into a known state.
*
* @note This function can be used only if the TWIM driver is uninitialized.
*
* @param[in] scl_pin SCL pin number.
* @param[in] sda_pin SDA pin number.
*
* @retval NRFX_SUCCESS Bus recovery was successful.
* @retval NRFX_ERROR_INTERNAL Bus recovery failed.
*/
__STATIC_INLINE nrfx_err_t nrfx_twim_bus_recover(uint32_t scl_pin, uint32_t sda_pin);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE nrfx_err_t nrfx_twim_bus_recover(uint32_t scl_pin, uint32_t sda_pin)
{
return nrfx_twi_twim_bus_recover(scl_pin, sda_pin);
}
#endif
/** @} */
void nrfx_twim_0_irq_handler(void);
void nrfx_twim_1_irq_handler(void);
void nrfx_twim_2_irq_handler(void);
void nrfx_twim_3_irq_handler(void);
#ifdef __cplusplus
}
#endif
#endif // NRFX_TWIM_H__
+360
View File
@@ -0,0 +1,360 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_UART_H__
#define NRFX_UART_H__
#include <nrfx.h>
#include <hal/nrf_uart.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_uart UART driver
* @{
* @ingroup nrf_uart
* @brief UART peripheral driver.
*/
/** @brief Data structure of the UART driver instance. */
typedef struct
{
NRF_UART_Type * p_reg; ///< Pointer to a structure with UART registers.
uint8_t drv_inst_idx; ///< Index of the driver instance. For internal use only.
} nrfx_uart_t;
#ifndef __NRFX_DOXYGEN__
enum {
#if NRFX_CHECK(NRFX_UART0_ENABLED)
NRFX_UART0_INST_IDX,
#endif
NRFX_UART_ENABLED_COUNT
};
#endif
/** @brief Macro for creating a UART driver instance. */
#define NRFX_UART_INSTANCE(id) \
{ \
.p_reg = NRFX_CONCAT_2(NRF_UART, id), \
.drv_inst_idx = NRFX_CONCAT_3(NRFX_UART, id, _INST_IDX), \
}
/** @brief Types of UART driver events. */
typedef enum
{
NRFX_UART_EVT_TX_DONE, ///< Requested TX transfer completed.
NRFX_UART_EVT_RX_DONE, ///< Requested RX transfer completed.
NRFX_UART_EVT_ERROR, ///< Error reported by UART peripheral.
} nrfx_uart_evt_type_t;
/** @brief Structure for the UART configuration. */
typedef struct
{
uint32_t pseltxd; ///< TXD pin number.
uint32_t pselrxd; ///< RXD pin number.
uint32_t pselcts; ///< CTS pin number.
uint32_t pselrts; ///< RTS pin number.
void * p_context; ///< Context passed to interrupt handler.
nrf_uart_hwfc_t hwfc; ///< Flow control configuration.
nrf_uart_parity_t parity; ///< Parity configuration.
nrf_uart_baudrate_t baudrate; ///< Baud rate.
uint8_t interrupt_priority; ///< Interrupt priority.
} nrfx_uart_config_t;
/** @brief UART default configuration. */
#define NRFX_UART_DEFAULT_CONFIG \
{ \
.pseltxd = NRF_UART_PSEL_DISCONNECTED, \
.pselrxd = NRF_UART_PSEL_DISCONNECTED, \
.pselcts = NRF_UART_PSEL_DISCONNECTED, \
.pselrts = NRF_UART_PSEL_DISCONNECTED, \
.p_context = NULL, \
.hwfc = (nrf_uart_hwfc_t)NRFX_UART_DEFAULT_CONFIG_HWFC, \
.parity = (nrf_uart_parity_t)NRFX_UART_DEFAULT_CONFIG_PARITY, \
.baudrate = (nrf_uart_baudrate_t)NRFX_UART_DEFAULT_CONFIG_BAUDRATE, \
.interrupt_priority = NRFX_UART_DEFAULT_CONFIG_IRQ_PRIORITY, \
}
/** @brief Structure for the UART transfer completion event. */
typedef struct
{
uint8_t * p_data; ///< Pointer to memory used for transfer.
uint32_t bytes; ///< Number of bytes transfered.
} nrfx_uart_xfer_evt_t;
/** @brief Structure for the UART error event. */
typedef struct
{
nrfx_uart_xfer_evt_t rxtx; ///< Transfer details, including number of bytes transferred.
uint32_t error_mask; ///< Mask of error flags that generated the event.
} nrfx_uart_error_evt_t;
/** @brief Structure for the UART event. */
typedef struct
{
nrfx_uart_evt_type_t type; ///< Event type.
union
{
nrfx_uart_xfer_evt_t rxtx; ///< Data provided for transfer completion events.
nrfx_uart_error_evt_t error; ///< Data provided for error event.
} data; ///< Union to store event data.
} nrfx_uart_event_t;
/**
* @brief UART interrupt event handler.
*
* @param[in] p_event Pointer to event structure. Event is allocated on the stack so it is available
* only within the context of the event handler.
* @param[in] p_context Context passed to the interrupt handler, set on initialization.
*/
typedef void (*nrfx_uart_event_handler_t)(nrfx_uart_event_t const * p_event,
void * p_context);
/**
* @brief Function for initializing the UART driver.
*
* This function configures and enables UART. After this function GPIO pins are controlled by UART.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_config Pointer to the structure with the initial configuration.
* @param[in] event_handler Event handler provided by the user. If not provided, the driver works in
* blocking mode.
*
* @retval NRFX_SUCCESS Initialization is successful.
* @retval NRFX_ERROR_INVALID_STATE The driver is already initialized.
* @retval NRFX_ERROR_BUSY Some other peripheral with the same
* instance ID is already in use. This is
* possible only if @ref nrfx_prs module
* is enabled.
*/
nrfx_err_t nrfx_uart_init(nrfx_uart_t const * p_instance,
nrfx_uart_config_t const * p_config,
nrfx_uart_event_handler_t event_handler);
/**
* @brief Function for uninitializing the UART driver.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_uart_uninit(nrfx_uart_t const * p_instance);
/**
* @brief Function for getting the address of the specified UART task.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] task Task.
*
* @return Task address.
*/
__STATIC_INLINE uint32_t nrfx_uart_task_address_get(nrfx_uart_t const * p_instance,
nrf_uart_task_t task);
/**
* @brief Function for getting the address of the specified UART event.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] event Event.
*
* @return Event address.
*/
__STATIC_INLINE uint32_t nrfx_uart_event_address_get(nrfx_uart_t const * p_instance,
nrf_uart_event_t event);
/**
* @brief Function for sending data over UART.
*
* If an event handler was provided in nrfx_uart_init() call, this function
* returns immediately and the handler is called when the transfer is done.
* Otherwise, the transfer is performed in blocking mode, that is this function
* returns when the transfer is finished. Blocking mode is not using interrupt
* so there is no context switching inside the function.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_data Pointer to data.
* @param[in] length Number of bytes to send.
*
* @retval NRFX_SUCCESS Initialization was successful.
* @retval NRFX_ERROR_BUSY Driver is already transferring.
* @retval NRFX_ERROR_FORBIDDEN The transfer was aborted from a different context
* (blocking mode only).
*/
nrfx_err_t nrfx_uart_tx(nrfx_uart_t const * p_instance,
uint8_t const * p_data,
size_t length);
/**
* @brief Function for checking if UART is currently transmitting.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @retval true The UART is transmitting.
* @retval false The UART is not transmitting.
*/
bool nrfx_uart_tx_in_progress(nrfx_uart_t const * p_instance);
/**
* @brief Function for aborting any ongoing transmission.
* @note @ref NRFX_UART_EVT_TX_DONE event will be generated in non-blocking mode.
* It will contain number of bytes sent until the abort was called. The event
* handler will be called from the function context.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_uart_tx_abort(nrfx_uart_t const * p_instance);
/**
* @brief Function for receiving data over UART.
*
* If an event handler is provided in the nrfx_uart_init() call, this function
* returns immediately and the handler is called when the transfer is done.
* Otherwise, the transfer is performed in blocking mode, that is this function
* returns when the transfer is finished. Blocking mode is not using interrupt so
* there is no context switching inside the function.
* The receive buffer pointer is double-buffered in non-blocking mode. The secondary
* buffer can be set immediately after starting the transfer and will be filled
* when the primary buffer is full. The double-buffering feature allows
* receiving data continuously.
*
* If this function is used without a previous call to @ref nrfx_uart_rx_enable, the reception
* will be stopped on error or when the supplied buffer fills up. In both cases,
* RX FIFO gets disabled. This means that, in case of error, the bytes that follow are lost.
* If this nrfx_uart_rx() function is used with the previous call to @ref nrfx_uart_rx_enable,
* the reception is stopped in case of error, but FIFO is still ongoing. The receiver is still
* working, so after handling the error, an immediate repeated call to this nrfx_uart_rx()
* function with fresh data buffer will re-establish reception. To disable the receiver,
* you must call @ref nrfx_uart_rx_disable explicitly.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_data Pointer to data.
* @param[in] length Number of bytes to receive.
*
* @retval NRFX_SUCCESS Reception is complete (in case of blocking mode) or it is
* successfully started (in case of non-blocking mode).
* @retval NRFX_ERROR_BUSY The driver is already receiving
* (and the secondary buffer has already been set
* in non-blocking mode).
* @retval NRFX_ERROR_FORBIDDEN The transfer was aborted from a different context
* (blocking mode only, also see @ref nrfx_uart_rx_disable).
* @retval NRFX_ERROR_INTERNAL The UART peripheral reported an error.
*/
nrfx_err_t nrfx_uart_rx(nrfx_uart_t const * p_instance,
uint8_t * p_data,
size_t length);
/**
* @brief Function for testing the receiver state in blocking mode.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @retval true The receiver has at least one byte of data to get.
* @retval false The receiver is empty.
*/
bool nrfx_uart_rx_ready(nrfx_uart_t const * p_instance);
/**
* @brief Function for enabling the receiver.
*
* UART has a 6-byte-long RX FIFO and it is used to store incoming data. If a user does not call the
* UART receive function before the FIFO is filled, an overrun error will appear. The receiver must be
* explicitly closed by the user @sa nrfx_uart_rx_disable.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_uart_rx_enable(nrfx_uart_t const * p_instance);
/**
* @brief Function for disabling the receiver.
*
* This function must be called to close the receiver after it has been explicitly enabled by
* @sa nrfx_uart_rx_enable.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_uart_rx_disable(nrfx_uart_t const * p_instance);
/**
* @brief Function for aborting any ongoing reception.
* @note @ref NRFX_UART_EVT_TX_DONE event will be generated in non-blocking mode.
* It will contain number of bytes received until the abort was called. The event
* handler will be called from the UART interrupt context.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_uart_rx_abort(nrfx_uart_t const * p_instance);
/**
* @brief Function for reading error source mask. Mask contains values from @ref nrf_uart_error_mask_t.
* @note Function must be used in blocking mode only. In case of non-blocking mode, an error event is
* generated. Function clears error sources after reading.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @return Mask of reported errors.
*/
uint32_t nrfx_uart_errorsrc_get(nrfx_uart_t const * p_instance);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE uint32_t nrfx_uart_task_address_get(nrfx_uart_t const * p_instance,
nrf_uart_task_t task)
{
return nrf_uart_task_address_get(p_instance->p_reg, task);
}
__STATIC_INLINE uint32_t nrfx_uart_event_address_get(nrfx_uart_t const * p_instance,
nrf_uart_event_t event)
{
return nrf_uart_event_address_get(p_instance->p_reg, event);
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
void nrfx_uart_0_irq_handler(void);
#ifdef __cplusplus
}
#endif
#endif // NRFX_UART_H__
+359
View File
@@ -0,0 +1,359 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_UARTE_H__
#define NRFX_UARTE_H__
#include <nrfx.h>
#include <hal/nrf_uarte.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_uarte UARTE driver
* @{
* @ingroup nrf_uarte
* @brief UARTE peripheral driver.
*/
/** @brief Structure for the UARTE driver instance. */
typedef struct
{
NRF_UARTE_Type * p_reg; ///< Pointer to a structure with UARTE registers.
uint8_t drv_inst_idx; ///< Index of the driver instance. For internal use only.
} nrfx_uarte_t;
#ifndef __NRFX_DOXYGEN__
enum {
#if NRFX_CHECK(NRFX_UARTE0_ENABLED)
NRFX_UARTE0_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_UARTE1_ENABLED)
NRFX_UARTE1_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_UARTE2_ENABLED)
NRFX_UARTE2_INST_IDX,
#endif
#if NRFX_CHECK(NRFX_UARTE3_ENABLED)
NRFX_UARTE3_INST_IDX,
#endif
NRFX_UARTE_ENABLED_COUNT
};
#endif
/** @brief Macro for creating a UARTE driver instance. */
#define NRFX_UARTE_INSTANCE(id) \
{ \
.p_reg = NRFX_CONCAT_2(NRF_UARTE, id), \
.drv_inst_idx = NRFX_CONCAT_3(NRFX_UARTE, id, _INST_IDX), \
}
/** @brief Types of UARTE driver events. */
typedef enum
{
NRFX_UARTE_EVT_TX_DONE, ///< Requested TX transfer completed.
NRFX_UARTE_EVT_RX_DONE, ///< Requested RX transfer completed.
NRFX_UARTE_EVT_ERROR, ///< Error reported by UART peripheral.
} nrfx_uarte_evt_type_t;
/** @brief Structure for the UARTE configuration. */
typedef struct
{
uint32_t pseltxd; ///< TXD pin number.
uint32_t pselrxd; ///< RXD pin number.
uint32_t pselcts; ///< CTS pin number.
uint32_t pselrts; ///< RTS pin number.
void * p_context; ///< Context passed to interrupt handler.
nrf_uarte_hwfc_t hwfc; ///< Flow control configuration.
nrf_uarte_parity_t parity; ///< Parity configuration.
nrf_uarte_baudrate_t baudrate; ///< Baud rate.
uint8_t interrupt_priority; ///< Interrupt priority.
} nrfx_uarte_config_t;
/** @brief UARTE default configuration. */
#define NRFX_UARTE_DEFAULT_CONFIG \
{ \
.pseltxd = NRF_UARTE_PSEL_DISCONNECTED, \
.pselrxd = NRF_UARTE_PSEL_DISCONNECTED, \
.pselcts = NRF_UARTE_PSEL_DISCONNECTED, \
.pselrts = NRF_UARTE_PSEL_DISCONNECTED, \
.p_context = NULL, \
.hwfc = (nrf_uarte_hwfc_t)NRFX_UARTE_DEFAULT_CONFIG_HWFC, \
.parity = (nrf_uarte_parity_t)NRFX_UARTE_DEFAULT_CONFIG_PARITY, \
.baudrate = (nrf_uarte_baudrate_t)NRFX_UARTE_DEFAULT_CONFIG_BAUDRATE, \
.interrupt_priority = NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY, \
}
/** @brief Structure for the UARTE transfer completion event. */
typedef struct
{
uint8_t * p_data; ///< Pointer to memory used for transfer.
size_t bytes; ///< Number of bytes transfered.
} nrfx_uarte_xfer_evt_t;
/** @brief Structure for UARTE error event. */
typedef struct
{
nrfx_uarte_xfer_evt_t rxtx; ///< Transfer details, including number of bytes transferred.
uint32_t error_mask; ///< Mask of error flags that generated the event.
} nrfx_uarte_error_evt_t;
/** @brief Structure for UARTE event. */
typedef struct
{
nrfx_uarte_evt_type_t type; ///< Event type.
union
{
nrfx_uarte_xfer_evt_t rxtx; ///< Data provided for transfer completion events.
nrfx_uarte_error_evt_t error; ///< Data provided for error event.
} data; ///< Union to store event data.
} nrfx_uarte_event_t;
/**
* @brief UARTE interrupt event handler.
*
* @param[in] p_event Pointer to event structure. Event is allocated on the stack so it is available
* only within the context of the event handler.
* @param[in] p_context Context passed to the interrupt handler, set on initialization.
*/
typedef void (*nrfx_uarte_event_handler_t)(nrfx_uarte_event_t const * p_event,
void * p_context);
/**
* @brief Function for initializing the UARTE driver.
*
* This function configures and enables UARTE. After this function GPIO pins are controlled by UARTE.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_config Pointer to the structure with the initial configuration.
* @param[in] event_handler Event handler provided by the user. If not provided driver works in
* blocking mode.
*
* @retval NRFX_SUCCESS Initialization was successful.
* @retval NRFX_ERROR_INVALID_STATE Driver is already initialized.
* @retval NRFX_ERROR_BUSY Some other peripheral with the same
* instance ID is already in use. This is
* possible only if @ref nrfx_prs module
* is enabled.
*/
nrfx_err_t nrfx_uarte_init(nrfx_uarte_t const * p_instance,
nrfx_uarte_config_t const * p_config,
nrfx_uarte_event_handler_t event_handler);
/**
* @brief Function for uninitializing the UARTE driver.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_uarte_uninit(nrfx_uarte_t const * p_instance);
/**
* @brief Function for getting the address of the specified UARTE task.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] task Task.
*
* @return Task address.
*/
__STATIC_INLINE uint32_t nrfx_uarte_task_address_get(nrfx_uarte_t const * p_instance,
nrf_uarte_task_t task);
/**
* @brief Function for getting the address of the specified UARTE event.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] event Event.
*
* @return Event address.
*/
__STATIC_INLINE uint32_t nrfx_uarte_event_address_get(nrfx_uarte_t const * p_instance,
nrf_uarte_event_t event);
/**
* @brief Function for sending data over UARTE.
*
* If an event handler is provided in nrfx_uarte_init() call, this function
* returns immediately and the handler is called when the transfer is done.
* Otherwise, the transfer is performed in blocking mode, that is this function
* returns when the transfer is finished. Blocking mode is not using interrupt
* so there is no context switching inside the function.
*
* @note Peripherals using EasyDMA (including UARTE) require the transfer buffers
* to be placed in the Data RAM region. If this condition is not met,
* this function will fail with the error code NRFX_ERROR_INVALID_ADDR.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_data Pointer to data.
* @param[in] length Number of bytes to send. Maximum possible length is
* dependent on the used SoC (see the MAXCNT register
* description in the Product Specification). The driver
* checks it with assertion.
*
* @retval NRFX_SUCCESS Initialization was successful.
* @retval NRFX_ERROR_BUSY Driver is already transferring.
* @retval NRFX_ERROR_FORBIDDEN The transfer was aborted from a different context
* (blocking mode only).
* @retval NRFX_ERROR_INVALID_ADDR p_data does not point to RAM buffer.
*/
nrfx_err_t nrfx_uarte_tx(nrfx_uarte_t const * p_instance,
uint8_t const * p_data,
size_t length);
/**
* @brief Function for checking if UARTE is currently transmitting.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @retval true The UARTE is transmitting.
* @retval false The UARTE is not transmitting.
*/
bool nrfx_uarte_tx_in_progress(nrfx_uarte_t const * p_instance);
/**
* @brief Function for aborting any ongoing transmission.
* @note @ref NRFX_UARTE_EVT_TX_DONE event will be generated in non-blocking mode.
* It will contain number of bytes sent until the abort was called. The event
* handler will be called from the UARTE interrupt context.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_uarte_tx_abort(nrfx_uarte_t const * p_instance);
/**
* @brief Function for receiving data over UARTE.
*
* If an event handler is provided in the nrfx_uarte_init() call, this function
* returns immediately and the handler is called when the transfer is done.
* Otherwise, the transfer is performed in blocking mode, that is this function
* returns when the transfer is finished. Blocking mode is not using interrupt so
* there is no context switching inside the function.
* The receive buffer pointer is double-buffered in non-blocking mode. The secondary
* buffer can be set immediately after starting the transfer and will be filled
* when the primary buffer is full. The double-buffering feature allows
* receiving data continuously.
*
* @note Peripherals using EasyDMA (including UARTE) require the transfer buffers
* to be placed in the Data RAM region. If this condition is not met,
* this function fails with the error code NRFX_ERROR_INVALID_ADDR.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_data Pointer to data.
* @param[in] length Number of bytes to receive. Maximum possible length is
* dependent on the used SoC (see the MAXCNT register
* description in the Product Specification). The driver
* checks it with assertion.
*
* @retval NRFX_SUCCESS Initialization is successful.
* @retval NRFX_ERROR_BUSY The driver is already receiving
* (and the secondary buffer has already been set
* in non-blocking mode).
* @retval NRFX_ERROR_FORBIDDEN The transfer is aborted from a different context
* (blocking mode only).
* @retval NRFX_ERROR_INTERNAL The UARTE peripheral reports an error.
* @retval NRFX_ERROR_INVALID_ADDR p_data does not point to RAM buffer.
*/
nrfx_err_t nrfx_uarte_rx(nrfx_uarte_t const * p_instance,
uint8_t * p_data,
size_t length);
/**
* @brief Function for testing the receiver state in blocking mode.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @retval true The receiver has at least one byte of data to get.
* @retval false The receiver is empty.
*/
bool nrfx_uarte_rx_ready(nrfx_uarte_t const * p_instance);
/**
* @brief Function for aborting any ongoing reception.
* @note @ref NRFX_UARTE_EVT_RX_DONE event will be generated in non-blocking mode.
* It will contain number of bytes received until the abort was called. The event
* handler will be called from the UARTE interrupt context.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrfx_uarte_rx_abort(nrfx_uarte_t const * p_instance);
/**
* @brief Function for reading error source mask. Mask contains values from @ref nrf_uarte_error_mask_t.
* @note Function must be used in the blocking mode only. In case of non-blocking mode, an error event is
* generated. Function clears error sources after reading.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @return Mask of reported errors.
*/
uint32_t nrfx_uarte_errorsrc_get(nrfx_uarte_t const * p_instance);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE uint32_t nrfx_uarte_task_address_get(nrfx_uarte_t const * p_instance,
nrf_uarte_task_t task)
{
return nrf_uarte_task_address_get(p_instance->p_reg, task);
}
__STATIC_INLINE uint32_t nrfx_uarte_event_address_get(nrfx_uarte_t const * p_instance,
nrf_uarte_event_t event)
{
return nrf_uarte_event_address_get(p_instance->p_reg, event);
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
void nrfx_uarte_0_irq_handler(void);
void nrfx_uarte_1_irq_handler(void);
void nrfx_uarte_2_irq_handler(void);
void nrfx_uarte_3_irq_handler(void);
#ifdef __cplusplus
}
#endif
#endif // NRFX_UARTE_H__
+168
View File
@@ -0,0 +1,168 @@
/**
* Copyright (c) 2014 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_WDT_H__
#define NRFX_WDT_H__
#include <nrfx.h>
#include <hal/nrf_wdt.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_wdt WDT driver
* @{
* @ingroup nrf_wdt
* @brief Watchdog Timer (WDT) peripheral driver.
*/
#if !NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ) || defined(__NRFX_DOXYGEN__)
/** @brief WDT instance interrupt priority configuration. */
#define NRFX_WDT_IRQ_CONFIG .interrupt_priority = NRFX_WDT_CONFIG_IRQ_PRIORITY
#else
#define NRFX_WDT_IRQ_CONFIG
#endif
/**@brief Struct for WDT initialization. */
typedef struct
{
nrf_wdt_behaviour_t behaviour; /**< WDT behaviour when CPU in sleep/halt mode. */
uint32_t reload_value; /**< WDT reload value in ms. */
#if !NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ) || defined(__NRFX_DOXYGEN__)
uint8_t interrupt_priority; /**< WDT interrupt priority */
#endif
} nrfx_wdt_config_t;
/** @brief WDT event handler function type. */
typedef void (*nrfx_wdt_event_handler_t)(void);
/** @brief WDT channel ID type. */
typedef nrf_wdt_rr_register_t nrfx_wdt_channel_id;
/** @brief WDT driver default configuration. */
#define NRFX_WDT_DEAFULT_CONFIG \
{ \
.behaviour = (nrf_wdt_behaviour_t)NRFX_WDT_CONFIG_BEHAVIOUR, \
.reload_value = NRFX_WDT_CONFIG_RELOAD_VALUE, \
NRFX_WDT_IRQ_CONFIG \
}
/**
* @brief This function initializes the watchdog.
*
* @param[in] p_config Pointer to the structure with the initial configuration.
* @param[in] wdt_event_handler Event handler provided by the user. Ignored when
* @ref NRFX_WDT_CONFIG_NO_IRQ option is enabled.
*
* @return NRFX_SUCCESS on success, otherwise an error code.
*/
nrfx_err_t nrfx_wdt_init(nrfx_wdt_config_t const * p_config,
nrfx_wdt_event_handler_t wdt_event_handler);
/**
* @brief Function for allocating a watchdog channel.
*
* @note This function can not be called after nrfx_wdt_start(void).
*
* @param[out] p_channel_id ID of granted channel.
*
* @return NRFX_SUCCESS on success, otherwise an error code.
*/
nrfx_err_t nrfx_wdt_channel_alloc(nrfx_wdt_channel_id * p_channel_id);
/**
* @brief Function for starting the watchdog.
*
* @note After calling this function the watchdog is started, so the user needs to feed all allocated
* watchdog channels to avoid reset. At least one watchdog channel must be allocated.
*/
void nrfx_wdt_enable(void);
/**
* @brief Function for feeding the watchdog.
*
* @details Function feeds all allocated watchdog channels.
*/
void nrfx_wdt_feed(void);
/**
* @brief Function for feeding an invidual watchdog channel.
*
* @param[in] channel_id ID of watchdog channel.
*/
void nrfx_wdt_channel_feed(nrfx_wdt_channel_id channel_id);
/**
* @brief Function for returning a requested task address for the WDT driver module.
*
* @param[in] task One of the peripheral tasks.
*
* @return Task address.
*/
__STATIC_INLINE uint32_t nrfx_wdt_ppi_task_addr(nrf_wdt_task_t task)
{
return nrf_wdt_task_address_get(task);
}
/**
* @brief Function for returning a requested event address for the wdt driver module.
*
* @param[in] event One of the peripheral events.
*
* @return Event address.
*/
__STATIC_INLINE uint32_t nrfx_wdt_ppi_event_addr(nrf_wdt_event_t event)
{
return nrf_wdt_event_address_get(event);
}
/** @} */
void nrfx_wdt_irq_handler(void);
#ifdef __cplusplus
}
#endif
#endif
+342
View File
@@ -0,0 +1,342 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_COMMON_H__
#define NRFX_COMMON_H__
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <nrf.h>
#include <nrf_peripherals.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_common Common module
* @{
* @ingroup nrfx
* @brief Common module.
*/
/**
* @brief Macro for checking if the specified identifier is defined and it has
* a non-zero value.
*
* Normally, preprocessors treat all undefined identifiers as having the value
* zero. However, some tools, like static code analyzers, can issue a warning
* when such identifier is evaluated. This macro gives the possibility to suppress
* such warnings only in places where this macro is used for evaluation, not in
* the whole analyzed code.
*/
#define NRFX_CHECK(module_enabled) (module_enabled)
/**
* @brief Macro for concatenating two tokens in macro expansion.
*
* @note This macro is expanded in two steps so that tokens given as macros
* themselves are fully expanded before they are merged.
*
* @param[in] p1 First token.
* @param[in] p2 Second token.
*
* @return The two tokens merged into one, unless they cannot together form
* a valid token (in such case, the preprocessor issues a warning and
* does not perform the concatenation).
*
* @sa NRFX_CONCAT_3
*/
#define NRFX_CONCAT_2(p1, p2) NRFX_CONCAT_2_(p1, p2)
/** @brief Internal macro used by @ref NRFX_CONCAT_2 to perform the expansion in two steps. */
#define NRFX_CONCAT_2_(p1, p2) p1 ## p2
/**
* @brief Macro for concatenating three tokens in macro expansion.
*
* @note This macro is expanded in two steps so that tokens given as macros
* themselves are fully expanded before they are merged.
*
* @param[in] p1 First token.
* @param[in] p2 Second token.
* @param[in] p3 Third token.
*
* @return The three tokens merged into one, unless they cannot together form
* a valid token (in such case, the preprocessor issues a warning and
* does not perform the concatenation).
*
* @sa NRFX_CONCAT_2
*/
#define NRFX_CONCAT_3(p1, p2, p3) NRFX_CONCAT_3_(p1, p2, p3)
/** @brief Internal macro used by @ref NRFX_CONCAT_3 to perform the expansion in two steps. */
#define NRFX_CONCAT_3_(p1, p2, p3) p1 ## p2 ## p3
/**
* @brief Macro for performing rounded integer division (as opposed to
* truncating the result).
*
* @param[in] a Numerator.
* @param[in] b Denominator.
*
* @return Rounded (integer) result of dividing @c a by @c b.
*/
#define NRFX_ROUNDED_DIV(a, b) (((a) + ((b) / 2)) / (b))
/**
* @brief Macro for performing integer division, making sure the result is rounded up.
*
* @details A typical use case for this macro is to compute the number of objects
* with size @c b required to hold @c a number of bytes.
*
* @param[in] a Numerator.
* @param[in] b Denominator.
*
* @return Integer result of dividing @c a by @c b, rounded up.
*/
#define NRFX_CEIL_DIV(a, b) ((((a) - 1) / (b)) + 1)
/**
* @brief Macro for getting the number of elements in an array.
*
* @param[in] array Name of the array.
*
* @return Array element count.
*/
#define NRFX_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
/**
* @brief Macro for getting the offset (in bytes) from the beginning of a structure
* of the specified type to its specified member.
*
* @param[in] type Structure type.
* @param[in] member Structure member whose offset is searched for.
*
* @return Member offset in bytes.
*/
#define NRFX_OFFSETOF(type, member) ((size_t)&(((type *)0)->member))
/**@brief Macro for checking if given lengths of EasyDMA transfers do not exceed
* the limit of the specified peripheral.
*
* @param[in] peripheral Peripheral to check the lengths against.
* @param[in] length1 First length to be checked.
* @param[in] length2 Second length to be checked (pass 0 if not needed).
*
* @retval true The length of buffers does not exceed the limit of the specified peripheral.
* @retval false The length of buffers exceeds the limit of the specified peripheral.
*/
#define NRFX_EASYDMA_LENGTH_VALIDATE(peripheral, length1, length2) \
(((length1) < (1U << NRFX_CONCAT_2(peripheral, _EASYDMA_MAXCNT_SIZE))) && \
((length2) < (1U << NRFX_CONCAT_2(peripheral, _EASYDMA_MAXCNT_SIZE))))
/**
* @brief Macro for waiting until condition is met.
*
* @param[in] condition Condition to meet.
* @param[in] attempts Maximum number of condition checks. Must not be 0.
* @param[in] delay_us Delay between consecutive checks, in microseconds.
* @param[out] result Boolean variable to store the result of the wait process.
* Set to true if the condition is met or false otherwise.
*/
#define NRFX_WAIT_FOR(condition, attempts, delay_us, result) \
do { \
result = false; \
uint32_t remaining_attempts = (attempts); \
do { \
if (condition) \
{ \
result = true; \
break; \
} \
NRFX_DELAY_US(delay_us); \
} while (--remaining_attempts); \
} while(0)
/**
* @brief Macro for getting the ID number of the specified peripheral.
*
* For peripherals in Nordic SoCs, there is a direct relationship between their
* ID numbers and their base addresses. See the chapter "Peripheral interface"
* (section "Peripheral ID") in the Product Specification.
*
* @param[in] base_addr Peripheral base address or pointer.
*
* @return ID number associated with the specified peripheral.
*/
#define NRFX_PERIPHERAL_ID_GET(base_addr) (uint8_t)((uint32_t)(base_addr) >> 12)
/**
* @brief Macro for getting the interrupt number assigned to a specific
* peripheral.
*
* For peripherals in Nordic SoCs, the IRQ number assigned to a peripheral is
* equal to its ID number. See the chapter "Peripheral interface" (sections
* "Peripheral ID" and "Interrupts") in the Product Specification.
*
* @param[in] base_addr Peripheral base address or pointer.
*
* @return Interrupt number associated with the specified peripheral.
*/
#define NRFX_IRQ_NUMBER_GET(base_addr) NRFX_PERIPHERAL_ID_GET(base_addr)
/** @brief IRQ handler type. */
typedef void (* nrfx_irq_handler_t)(void);
/** @brief Driver state. */
typedef enum
{
NRFX_DRV_STATE_UNINITIALIZED, ///< Uninitialized.
NRFX_DRV_STATE_INITIALIZED, ///< Initialized but powered off.
NRFX_DRV_STATE_POWERED_ON, ///< Initialized and powered on.
} nrfx_drv_state_t;
/**
* @brief Function for checking if an object is placed in the Data RAM region.
*
* Several peripherals (the ones using EasyDMA) require the transfer buffers
* to be placed in the Data RAM region. This function can be used to check if
* this condition is met.
*
* @param[in] p_object Pointer to an object whose location is to be checked.
*
* @retval true The pointed object is located in the Data RAM region.
* @retval false The pointed object is not located in the Data RAM region.
*/
__STATIC_INLINE bool nrfx_is_in_ram(void const * p_object);
/**
* @brief Function for checking if an object is aligned to a 32-bit word
*
* Several peripherals (the ones using EasyDMA) require the transfer buffers
* to be aligned to a 32-bit word. This function can be used to check if
* this condition is met.
*
* @param[in] p_object Pointer to an object whose location is to be checked.
*
* @retval true The pointed object is aligned to a 32-bit word.
* @retval false The pointed object is not aligned to a 32-bit word.
*/
__STATIC_INLINE bool nrfx_is_word_aligned(void const * p_object);
/**
* @brief Function for getting the interrupt number for the specified peripheral.
*
* @param[in] p_reg Peripheral base pointer.
*
* @return Interrupt number associated with the pointed peripheral.
*/
__STATIC_INLINE IRQn_Type nrfx_get_irq_number(void const * p_reg);
/**
* @brief Function for converting an INTEN register bit position to the
* corresponding event identifier.
*
* The event identifier is the offset between the event register address and
* the peripheral base address, and is equal (thus, can be directly cast) to
* the corresponding value of the enumerated type from HAL (nrf_*_event_t).
*
* @param[in] bit INTEN register bit position.
*
* @return Event identifier.
*
* @sa nrfx_event_to_bitpos
*/
__STATIC_INLINE uint32_t nrfx_bitpos_to_event(uint32_t bit);
/**
* @brief Function for converting an event identifier to the corresponding
* INTEN register bit position.
*
* The event identifier is the offset between the event register address and
* the peripheral base address, and is equal (thus, can be directly cast) to
* the corresponding value of the enumerated type from HAL (nrf_*_event_t).
*
* @param[in] event Event identifier.
*
* @return INTEN register bit position.
*
* @sa nrfx_bitpos_to_event
*/
__STATIC_INLINE uint32_t nrfx_event_to_bitpos(uint32_t event);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE bool nrfx_is_in_ram(void const * p_object)
{
return ((((uint32_t)p_object) & 0xE0000000u) == 0x20000000u);
}
__STATIC_INLINE bool nrfx_is_word_aligned(void const * p_object)
{
return ((((uint32_t)p_object) & 0x3u) == 0u);
}
__STATIC_INLINE IRQn_Type nrfx_get_irq_number(void const * p_reg)
{
return (IRQn_Type)NRFX_IRQ_NUMBER_GET(p_reg);
}
__STATIC_INLINE uint32_t nrfx_bitpos_to_event(uint32_t bit)
{
static const uint32_t event_reg_offset = 0x100u;
return event_reg_offset + (bit * sizeof(uint32_t));
}
__STATIC_INLINE uint32_t nrfx_event_to_bitpos(uint32_t event)
{
static const uint32_t event_reg_offset = 0x100u;
return (event - event_reg_offset) / sizeof(uint32_t);
}
#endif
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRFX_COMMON_H__
+85
View File
@@ -0,0 +1,85 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_ERRORS_H__
#define NRFX_ERRORS_H__
#if !NRFX_CHECK(NRFX_CUSTOM_ERROR_CODES)
/**
* @defgroup nrfx_error_codes Global Error Codes
* @{
* @ingroup nrfx
*
* @brief Global error code definitions.
*/
/** @brief Base number of error codes. */
#define NRFX_ERROR_BASE_NUM 0x0BAD0000
/** @brief Base number of driver error codes. */
#define NRFX_ERROR_DRIVERS_BASE_NUM (NRFX_ERROR_BASE_NUM + 0x10000)
/** @brief Enumerated type for error codes. */
typedef enum {
NRFX_SUCCESS = (NRFX_ERROR_BASE_NUM + 0), ///< Operation performed successfully.
NRFX_ERROR_INTERNAL = (NRFX_ERROR_BASE_NUM + 1), ///< Internal error.
NRFX_ERROR_NO_MEM = (NRFX_ERROR_BASE_NUM + 2), ///< No memory for operation.
NRFX_ERROR_NOT_SUPPORTED = (NRFX_ERROR_BASE_NUM + 3), ///< Not supported.
NRFX_ERROR_INVALID_PARAM = (NRFX_ERROR_BASE_NUM + 4), ///< Invalid parameter.
NRFX_ERROR_INVALID_STATE = (NRFX_ERROR_BASE_NUM + 5), ///< Invalid state, operation disallowed in this state.
NRFX_ERROR_INVALID_LENGTH = (NRFX_ERROR_BASE_NUM + 6), ///< Invalid length.
NRFX_ERROR_TIMEOUT = (NRFX_ERROR_BASE_NUM + 7), ///< Operation timed out.
NRFX_ERROR_FORBIDDEN = (NRFX_ERROR_BASE_NUM + 8), ///< Operation is forbidden.
NRFX_ERROR_NULL = (NRFX_ERROR_BASE_NUM + 9), ///< Null pointer.
NRFX_ERROR_INVALID_ADDR = (NRFX_ERROR_BASE_NUM + 10), ///< Bad memory address.
NRFX_ERROR_BUSY = (NRFX_ERROR_BASE_NUM + 11), ///< Busy.
NRFX_ERROR_ALREADY_INITIALIZED = (NRFX_ERROR_BASE_NUM + 12), ///< Module already initialized.
NRFX_ERROR_DRV_TWI_ERR_OVERRUN = (NRFX_ERROR_DRIVERS_BASE_NUM + 0), ///< TWI error: Overrun.
NRFX_ERROR_DRV_TWI_ERR_ANACK = (NRFX_ERROR_DRIVERS_BASE_NUM + 1), ///< TWI error: Address not acknowledged.
NRFX_ERROR_DRV_TWI_ERR_DNACK = (NRFX_ERROR_DRIVERS_BASE_NUM + 2) ///< TWI error: Data not acknowledged.
} nrfx_err_t;
/** @} */
#endif // !NRFX_CHECK(NRFX_CUSTOM_ERROR_CODES)
#endif // NRFX_ERRORS_H__
+395
View File
@@ -0,0 +1,395 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_CLOCK_ENABLED)
#include <nrfx_clock.h>
#define NRFX_LOG_MODULE CLOCK
#include <nrfx_log.h>
#if NRFX_CHECK(NRFX_POWER_ENABLED)
extern bool nrfx_power_irq_enabled;
#endif
#define EVT_TO_STR(event) \
(event == NRF_CLOCK_EVENT_HFCLKSTARTED ? "NRF_CLOCK_EVENT_HFCLKSTARTED" : \
(event == NRF_CLOCK_EVENT_LFCLKSTARTED ? "NRF_CLOCK_EVENT_LFCLKSTARTED" : \
(event == NRF_CLOCK_EVENT_DONE ? "NRF_CLOCK_EVENT_DONE" : \
(event == NRF_CLOCK_EVENT_CTTO ? "NRF_CLOCK_EVENT_CTTO" : \
"UNKNOWN EVENT"))))
#if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
#if (NRF_CLOCK_HAS_CALIBRATION == 0)
#error "Calibration is not available in the SoC that is used."
#endif
#if (NRFX_CLOCK_CONFIG_LF_SRC != CLOCK_LFCLKSRC_SRC_RC)
#error "Calibration can be performed only for the RC Oscillator."
#endif
#endif
#if !defined(USE_WORKAROUND_FOR_ANOMALY_132) && \
(defined(NRF52832_XXAA) || defined(NRF52832_XXAB))
// ANOMALY 132 - LFCLK needs to avoid frame from 66us to 138us after LFCLK stop. This solution
// applies delay of 138us before starting LFCLK.
#define USE_WORKAROUND_FOR_ANOMALY_132 1
// Convert time to cycles (nRF52832 is clocked with 64 MHz, use delay of 138 us).
#define ANOMALY_132_DELAY_CYCLES (64UL * 138)
#endif
#if !defined(USE_WORKAROUND_FOR_ANOMALY_192) && \
(defined(NRF52810_XXAA) || \
defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || \
defined(NRF52840_XXAA))
// Enable workaround for nRF52 anomaly 192 (LFRC oscillator frequency is wrong
// after calibration, exceeding 500 ppm).
#define USE_WORKAROUND_FOR_ANOMALY_192 1
#endif
#if !defined(USE_WORKAROUND_FOR_ANOMALY_201) && \
(defined(NRF52810_XXAA) || \
defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || \
defined(NRF52840_XXAA))
// Enable workaround for nRF52 anomaly 201 (EVENTS_HFCLKSTARTED might be generated twice).
#define USE_WORKAROUND_FOR_ANOMALY_201 1
#endif
#if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
typedef enum
{
CAL_STATE_IDLE,
CAL_STATE_CAL
} nrfx_clock_cal_state_t;
#endif
/**@brief CLOCK control block. */
typedef struct
{
nrfx_clock_event_handler_t event_handler;
bool module_initialized; /*< Indicate the state of module */
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_201)
bool hfclk_started; /*< Anomaly 201 workaround. */
#endif
#if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
volatile nrfx_clock_cal_state_t cal_state;
#endif
} nrfx_clock_cb_t;
static nrfx_clock_cb_t m_clock_cb;
/**
* This variable is used to check whether common POWER_CLOCK common interrupt
* should be disabled or not if @ref nrfx_power tries to disable the interrupt.
*/
#if NRFX_CHECK(NRFX_POWER_ENABLED)
bool nrfx_clock_irq_enabled;
#endif
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_132)
/**
* @brief Function for applying delay of 138us before starting LFCLK.
*/
static void nrfx_clock_anomaly_132(void)
{
uint32_t cyccnt_inital;
uint32_t core_debug;
uint32_t dwt_ctrl;
// Preserve DEMCR register to do not influence into its configuration. Enable the trace and
// debug blocks. It is required to read and write data to DWT block.
core_debug = CoreDebug->DEMCR;
CoreDebug->DEMCR = core_debug | CoreDebug_DEMCR_TRCENA_Msk;
// Preserve CTRL register in DWT block to do not influence into its configuration. Make sure
// that cycle counter is enabled.
dwt_ctrl = DWT->CTRL;
DWT->CTRL = dwt_ctrl | DWT_CTRL_CYCCNTENA_Msk;
// Store start value of cycle counter.
cyccnt_inital = DWT->CYCCNT;
// Delay required time.
while ((DWT->CYCCNT - cyccnt_inital) < ANOMALY_132_DELAY_CYCLES)
{}
// Restore preserved registers.
DWT->CTRL = dwt_ctrl;
CoreDebug->DEMCR = core_debug;
}
#endif // NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_132)
nrfx_err_t nrfx_clock_init(nrfx_clock_event_handler_t event_handler)
{
NRFX_ASSERT(event_handler);
nrfx_err_t err_code = NRFX_SUCCESS;
if (m_clock_cb.module_initialized)
{
err_code = NRFX_ERROR_ALREADY_INITIALIZED;
}
else
{
#if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
m_clock_cb.cal_state = CAL_STATE_IDLE;
#endif
m_clock_cb.event_handler = event_handler;
m_clock_cb.module_initialized = true;
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_201)
m_clock_cb.hfclk_started = false;
#endif
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
void nrfx_clock_enable(void)
{
NRFX_ASSERT(m_clock_cb.module_initialized);
nrfx_power_clock_irq_init();
nrf_clock_lf_src_set((nrf_clock_lfclk_t)NRFX_CLOCK_CONFIG_LF_SRC);
#if NRFX_CHECK(NRFX_POWER_ENABLED)
nrfx_clock_irq_enabled = true;
#endif
NRFX_LOG_INFO("Module enabled.");
}
void nrfx_clock_disable(void)
{
NRFX_ASSERT(m_clock_cb.module_initialized);
#if NRFX_CHECK(NRFX_POWER_ENABLED)
NRFX_ASSERT(nrfx_clock_irq_enabled);
if (!nrfx_power_irq_enabled)
#endif
{
NRFX_IRQ_DISABLE(nrfx_get_irq_number(NRF_CLOCK));
}
nrf_clock_int_disable(CLOCK_INTENSET_HFCLKSTARTED_Msk |
CLOCK_INTENSET_LFCLKSTARTED_Msk |
#if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
CLOCK_INTENSET_DONE_Msk |
CLOCK_INTENSET_CTTO_Msk |
#endif
0);
#if NRFX_CHECK(NRFX_POWER_ENABLED)
nrfx_clock_irq_enabled = false;
#endif
NRFX_LOG_INFO("Module disabled.");
}
void nrfx_clock_uninit(void)
{
NRFX_ASSERT(m_clock_cb.module_initialized);
nrfx_clock_lfclk_stop();
nrfx_clock_hfclk_stop();
m_clock_cb.module_initialized = false;
NRFX_LOG_INFO("Uninitialized.");
}
void nrfx_clock_lfclk_start(void)
{
NRFX_ASSERT(m_clock_cb.module_initialized);
nrf_clock_event_clear(NRF_CLOCK_EVENT_LFCLKSTARTED);
nrf_clock_int_enable(NRF_CLOCK_INT_LF_STARTED_MASK);
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_132)
nrfx_clock_anomaly_132();
#endif
nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART);
}
void nrfx_clock_lfclk_stop(void)
{
NRFX_ASSERT(m_clock_cb.module_initialized);
nrf_clock_int_disable(NRF_CLOCK_INT_LF_STARTED_MASK);
nrf_clock_event_clear(NRF_CLOCK_EVENT_LFCLKSTARTED);
nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTOP);
while (nrf_clock_lf_is_running())
{}
}
void nrfx_clock_hfclk_start(void)
{
NRFX_ASSERT(m_clock_cb.module_initialized);
nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED);
nrf_clock_int_enable(NRF_CLOCK_INT_HF_STARTED_MASK);
nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTART);
}
void nrfx_clock_hfclk_stop(void)
{
NRFX_ASSERT(m_clock_cb.module_initialized);
nrf_clock_int_disable(NRF_CLOCK_INT_HF_STARTED_MASK);
nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED);
nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTOP);
while (nrf_clock_hf_is_running(NRF_CLOCK_HFCLK_HIGH_ACCURACY))
{}
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_201)
m_clock_cb.hfclk_started = false;
#endif
}
nrfx_err_t nrfx_clock_calibration_start(void)
{
nrfx_err_t err_code = NRFX_SUCCESS;
#if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
if (nrfx_clock_hfclk_is_running() == false)
{
return NRFX_ERROR_INVALID_STATE;
}
if (nrfx_clock_lfclk_is_running() == false)
{
return NRFX_ERROR_INVALID_STATE;
}
if (m_clock_cb.cal_state == CAL_STATE_IDLE)
{
nrf_clock_event_clear(NRF_CLOCK_EVENT_DONE);
nrf_clock_int_enable(NRF_CLOCK_INT_DONE_MASK);
m_clock_cb.cal_state = CAL_STATE_CAL;
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_192)
*(volatile uint32_t *)0x40000C34 = 0x00000002;
#endif
nrf_clock_task_trigger(NRF_CLOCK_TASK_CAL);
}
else
{
err_code = NRFX_ERROR_BUSY;
}
#endif // NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_clock_is_calibrating(void)
{
#if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
if (m_clock_cb.cal_state == CAL_STATE_CAL)
{
return NRFX_ERROR_BUSY;
}
#endif
return NRFX_SUCCESS;
}
void nrfx_clock_calibration_timer_start(uint8_t interval)
{
#if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
nrf_clock_cal_timer_timeout_set(interval);
nrf_clock_event_clear(NRF_CLOCK_EVENT_CTTO);
nrf_clock_int_enable(NRF_CLOCK_INT_CTTO_MASK);
nrf_clock_task_trigger(NRF_CLOCK_TASK_CTSTART);
#endif
}
void nrfx_clock_calibration_timer_stop(void)
{
#if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
nrf_clock_int_disable(NRF_CLOCK_INT_CTTO_MASK);
nrf_clock_task_trigger(NRF_CLOCK_TASK_CTSTOP);
#endif
}
void nrfx_clock_irq_handler(void)
{
if (nrf_clock_event_check(NRF_CLOCK_EVENT_HFCLKSTARTED))
{
nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED);
NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_CLOCK_EVENT_HFCLKSTARTED));
nrf_clock_int_disable(NRF_CLOCK_INT_HF_STARTED_MASK);
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_201)
if (!m_clock_cb.hfclk_started)
{
m_clock_cb.hfclk_started = true;
m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLK_STARTED);
}
#else
m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLK_STARTED);
#endif
}
if (nrf_clock_event_check(NRF_CLOCK_EVENT_LFCLKSTARTED))
{
nrf_clock_event_clear(NRF_CLOCK_EVENT_LFCLKSTARTED);
NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_CLOCK_EVENT_LFCLKSTARTED));
nrf_clock_int_disable(NRF_CLOCK_INT_LF_STARTED_MASK);
m_clock_cb.event_handler(NRFX_CLOCK_EVT_LFCLK_STARTED);
}
#if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
if (nrf_clock_event_check(NRF_CLOCK_EVENT_CTTO))
{
nrf_clock_event_clear(NRF_CLOCK_EVENT_CTTO);
NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_CLOCK_EVENT_CTTO));
nrf_clock_int_disable(NRF_CLOCK_INT_CTTO_MASK);
m_clock_cb.event_handler(NRFX_CLOCK_EVT_CTTO);
}
if (nrf_clock_event_check(NRF_CLOCK_EVENT_DONE))
{
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_192)
*(volatile uint32_t *)0x40000C34 = 0x00000000;
#endif
nrf_clock_event_clear(NRF_CLOCK_EVENT_DONE);
NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_CLOCK_EVENT_DONE));
nrf_clock_int_disable(NRF_CLOCK_INT_DONE_MASK);
m_clock_cb.cal_state = CAL_STATE_IDLE;
m_clock_cb.event_handler(NRFX_CLOCK_EVT_CAL_DONE);
}
#endif // NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
}
#endif // NRFX_CHECK(NRFX_CLOCK_ENABLED)
+937
View File
@@ -0,0 +1,937 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_GPIOTE_ENABLED)
#include <nrfx_gpiote.h>
#include "nrf_bitmask.h"
#include <string.h>
#define NRFX_LOG_MODULE GPIOTE
#include <nrfx_log.h>
#if (GPIO_COUNT == 1)
#define MAX_PIN_NUMBER 32
#elif (GPIO_COUNT == 2)
#define MAX_PIN_NUMBER (32 + P1_PIN_NUM)
#else
#error "Not supported."
#endif
#define FORBIDDEN_HANDLER_ADDRESS ((nrfx_gpiote_evt_handler_t)UINT32_MAX)
#define PIN_NOT_USED (-1)
#define PIN_USED (-2)
#define NO_CHANNELS (-1)
#define POLARITY_FIELD_POS (6)
#define POLARITY_FIELD_MASK (0xC0)
/* Check if every pin can be encoded on provided number of bits. */
NRFX_STATIC_ASSERT(MAX_PIN_NUMBER <= (1 << POLARITY_FIELD_POS));
/**
* @brief Macro for converting task-event index to an address of an event register.
*
* Macro utilizes the fact that registers are grouped together in ascending order.
*/
#define TE_IDX_TO_EVENT_ADDR(idx) (nrf_gpiote_events_t)((uint32_t)NRF_GPIOTE_EVENTS_IN_0 + \
(sizeof(uint32_t) * (idx)))
/**
* @brief Macro for converting task-event index of OUT task to an address of a task register.
*
* Macro utilizes the fact that registers are grouped together in ascending order.
*/
#define TE_OUT_IDX_TO_TASK_ADDR(idx) (nrf_gpiote_tasks_t)((uint32_t)NRF_GPIOTE_TASKS_OUT_0 + \
(sizeof(uint32_t) * (idx)))
#if defined(GPIOTE_FEATURE_SET_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Macro for converting task-event index of SET task to an address of a task register.
*
* Macro utilizes the fact that registers are grouped together in ascending order.
*/
#define TE_SET_IDX_TO_TASK_ADDR(idx) (nrf_gpiote_tasks_t)((uint32_t)NRF_GPIOTE_TASKS_SET_0 + \
(sizeof(uint32_t) * (idx)))
#endif // defined(GPIOTE_FEATURE_SET_PRESENT) || defined(__NRFX_DOXYGEN__)
#if defined(GPIOTE_FEATURE_CLR_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Macro for converting task-event index of CLR task to an address of a task register.
*
* Macro utilizes the fact that registers are grouped together in ascending order.
*/
#define TE_CLR_IDX_TO_TASK_ADDR(idx) (nrf_gpiote_tasks_t)((uint32_t)NRF_GPIOTE_TASKS_CLR_0 + \
(sizeof(uint32_t) * (idx)))
#endif // defined(GPIOTE_FEATURE_CLR_PRESENT) || defined(__NRFX_DOXYGEN__)
/*lint -save -e571*/ /* Suppress "Warning 571: Suspicious cast" */
typedef struct
{
nrfx_gpiote_evt_handler_t handlers[GPIOTE_CH_NUM + NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS];
int8_t pin_assignments[MAX_PIN_NUMBER];
int8_t port_handlers_pins[NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS];
uint8_t configured_pins[((MAX_PIN_NUMBER)+7) / 8];
nrfx_drv_state_t state;
} gpiote_control_block_t;
static gpiote_control_block_t m_cb;
__STATIC_INLINE bool pin_in_use(uint32_t pin)
{
return (m_cb.pin_assignments[pin] != PIN_NOT_USED);
}
__STATIC_INLINE bool pin_in_use_as_non_task_out(uint32_t pin)
{
return (m_cb.pin_assignments[pin] == PIN_USED);
}
__STATIC_INLINE bool pin_in_use_by_te(uint32_t pin)
{
return (m_cb.pin_assignments[pin] >= 0 && m_cb.pin_assignments[pin] < GPIOTE_CH_NUM) ?
true : false;
}
__STATIC_INLINE bool pin_in_use_by_port(uint32_t pin)
{
return (m_cb.pin_assignments[pin] >= GPIOTE_CH_NUM);
}
__STATIC_INLINE bool pin_in_use_by_gpiote(uint32_t pin)
{
return (m_cb.pin_assignments[pin] >= 0);
}
__STATIC_INLINE void pin_in_use_by_te_set(uint32_t pin,
uint32_t channel_id,
nrfx_gpiote_evt_handler_t handler,
bool is_channel)
{
m_cb.pin_assignments[pin] = channel_id;
m_cb.handlers[channel_id] = handler;
if (!is_channel)
{
m_cb.port_handlers_pins[channel_id - GPIOTE_CH_NUM] = (int8_t)pin;
}
}
__STATIC_INLINE void pin_in_use_set(uint32_t pin)
{
m_cb.pin_assignments[pin] = PIN_USED;
}
__STATIC_INLINE void pin_in_use_clear(uint32_t pin)
{
m_cb.pin_assignments[pin] = PIN_NOT_USED;
}
__STATIC_INLINE void pin_configured_set(uint32_t pin)
{
nrf_bitmask_bit_set(pin, m_cb.configured_pins);
}
__STATIC_INLINE void pin_configured_clear(uint32_t pin)
{
nrf_bitmask_bit_clear(pin, m_cb.configured_pins);
}
__STATIC_INLINE bool pin_configured_check(uint32_t pin)
{
return 0 != nrf_bitmask_bit_is_set(pin, m_cb.configured_pins);
}
__STATIC_INLINE int8_t channel_port_get(uint32_t pin)
{
return m_cb.pin_assignments[pin];
}
__STATIC_INLINE nrfx_gpiote_evt_handler_t channel_handler_get(uint32_t channel)
{
return m_cb.handlers[channel];
}
static nrfx_gpiote_pin_t port_handler_pin_get(uint32_t handler_idx)
{
uint8_t pin_and_polarity = (uint8_t)m_cb.port_handlers_pins[handler_idx];
return (nrfx_gpiote_pin_t)(pin_and_polarity & ~POLARITY_FIELD_MASK);
}
static nrf_gpiote_polarity_t port_handler_polarity_get(uint32_t handler_idx)
{
uint8_t pin_and_polarity = (uint8_t)m_cb.port_handlers_pins[handler_idx];
return (nrf_gpiote_polarity_t)((pin_and_polarity & POLARITY_FIELD_MASK) >> POLARITY_FIELD_POS);
}
static int8_t channel_port_alloc(uint32_t pin, nrfx_gpiote_evt_handler_t handler, bool channel)
{
int8_t channel_id = NO_CHANNELS;
uint32_t i;
uint32_t start_idx = channel ? 0 : GPIOTE_CH_NUM;
uint32_t end_idx =
channel ? GPIOTE_CH_NUM : (GPIOTE_CH_NUM + NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS);
// critical section
for (i = start_idx; i < end_idx; i++)
{
if (m_cb.handlers[i] == FORBIDDEN_HANDLER_ADDRESS)
{
pin_in_use_by_te_set(pin, i, handler, channel);
channel_id = i;
break;
}
}
// critical section
return channel_id;
}
static void channel_free(uint8_t channel_id)
{
m_cb.handlers[channel_id] = FORBIDDEN_HANDLER_ADDRESS;
if (channel_id >= GPIOTE_CH_NUM)
{
m_cb.port_handlers_pins[channel_id - GPIOTE_CH_NUM] = (int8_t)PIN_NOT_USED;
}
}
nrfx_err_t nrfx_gpiote_init(void)
{
nrfx_err_t err_code;
if (m_cb.state != NRFX_DRV_STATE_UNINITIALIZED)
{
err_code = NRFX_ERROR_INVALID_STATE;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
uint8_t i;
for (i = 0; i < MAX_PIN_NUMBER; i++)
{
if (nrf_gpio_pin_present_check(i))
{
pin_in_use_clear(i);
}
}
for (i = 0; i < (GPIOTE_CH_NUM + NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS); i++)
{
channel_free(i);
}
memset(m_cb.configured_pins, 0, sizeof(m_cb.configured_pins));
NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(NRF_GPIOTE), NRFX_GPIOTE_CONFIG_IRQ_PRIORITY);
NRFX_IRQ_ENABLE(nrfx_get_irq_number(NRF_GPIOTE));
nrf_gpiote_event_clear(NRF_GPIOTE_EVENTS_PORT);
nrf_gpiote_int_enable(GPIOTE_INTENSET_PORT_Msk);
m_cb.state = NRFX_DRV_STATE_INITIALIZED;
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
bool nrfx_gpiote_is_init(void)
{
return (m_cb.state != NRFX_DRV_STATE_UNINITIALIZED) ? true : false;
}
void nrfx_gpiote_uninit(void)
{
NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
uint32_t i;
for (i = 0; i < MAX_PIN_NUMBER; i++)
{
if (nrf_gpio_pin_present_check(i))
{
if (pin_in_use_as_non_task_out(i))
{
nrfx_gpiote_out_uninit(i);
}
else if (pin_in_use_by_gpiote(i))
{
/* Disable gpiote_in is having the same effect on out pin as gpiote_out_uninit on
* so it can be called on all pins used by GPIOTE.
*/
nrfx_gpiote_in_uninit(i);
}
}
}
m_cb.state = NRFX_DRV_STATE_UNINITIALIZED;
NRFX_LOG_INFO("Uninitialized.");
}
nrfx_err_t nrfx_gpiote_out_init(nrfx_gpiote_pin_t pin,
nrfx_gpiote_out_config_t const * p_config)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_INITIALIZED);
NRFX_ASSERT(p_config);
nrfx_err_t err_code = NRFX_SUCCESS;
if (pin_in_use(pin))
{
err_code = NRFX_ERROR_INVALID_STATE;
}
else
{
if (p_config->task_pin)
{
int8_t channel = channel_port_alloc(pin, NULL, true);
if (channel != NO_CHANNELS)
{
nrf_gpiote_task_configure((uint32_t)channel,
pin,
p_config->action,
p_config->init_state);
}
else
{
err_code = NRFX_ERROR_NO_MEM;
}
}
else
{
pin_in_use_set(pin);
}
if (err_code == NRFX_SUCCESS)
{
if (p_config->init_state == NRF_GPIOTE_INITIAL_VALUE_HIGH)
{
nrf_gpio_pin_set(pin);
}
else
{
nrf_gpio_pin_clear(pin);
}
nrf_gpio_cfg_output(pin);
pin_configured_set(pin);
}
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
void nrfx_gpiote_out_uninit(nrfx_gpiote_pin_t pin)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(pin_in_use(pin));
if (pin_in_use_by_te(pin))
{
channel_free((uint8_t)channel_port_get(pin));
nrf_gpiote_te_default((uint32_t)channel_port_get(pin));
}
pin_in_use_clear(pin);
if (pin_configured_check(pin))
{
nrf_gpio_cfg_default(pin);
pin_configured_clear(pin);
}
}
void nrfx_gpiote_out_set(nrfx_gpiote_pin_t pin)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(pin_in_use(pin));
NRFX_ASSERT(!pin_in_use_by_te(pin));
nrf_gpio_pin_set(pin);
}
void nrfx_gpiote_out_clear(nrfx_gpiote_pin_t pin)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(pin_in_use(pin));
NRFX_ASSERT(!pin_in_use_by_te(pin));
nrf_gpio_pin_clear(pin);
}
void nrfx_gpiote_out_toggle(nrfx_gpiote_pin_t pin)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(pin_in_use(pin));
NRFX_ASSERT(!pin_in_use_by_te(pin));
nrf_gpio_pin_toggle(pin);
}
void nrfx_gpiote_out_task_enable(nrfx_gpiote_pin_t pin)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(pin_in_use(pin));
NRFX_ASSERT(pin_in_use_by_te(pin));
nrf_gpiote_task_enable((uint32_t)m_cb.pin_assignments[pin]);
}
void nrfx_gpiote_out_task_disable(nrfx_gpiote_pin_t pin)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(pin_in_use(pin));
NRFX_ASSERT(pin_in_use_by_te(pin));
nrf_gpiote_task_disable((uint32_t)m_cb.pin_assignments[pin]);
}
nrf_gpiote_tasks_t nrfx_gpiote_out_task_get(nrfx_gpiote_pin_t pin)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(pin_in_use_by_te(pin));
return TE_OUT_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin));
}
uint32_t nrfx_gpiote_out_task_addr_get(nrfx_gpiote_pin_t pin)
{
nrf_gpiote_tasks_t task = nrfx_gpiote_out_task_get(pin);
return nrf_gpiote_task_addr_get(task);
}
#if defined(GPIOTE_FEATURE_SET_PRESENT)
nrf_gpiote_tasks_t nrfx_gpiote_set_task_get(nrfx_gpiote_pin_t pin)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(pin_in_use_by_te(pin));
return TE_SET_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin));
}
uint32_t nrfx_gpiote_set_task_addr_get(nrfx_gpiote_pin_t pin)
{
nrf_gpiote_tasks_t task = nrfx_gpiote_set_task_get(pin);
return nrf_gpiote_task_addr_get(task);
}
#endif // defined(GPIOTE_FEATURE_SET_PRESENT)
#if defined(GPIOTE_FEATURE_CLR_PRESENT)
nrf_gpiote_tasks_t nrfx_gpiote_clr_task_get(nrfx_gpiote_pin_t pin)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(pin_in_use_by_te(pin));
return TE_CLR_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin));
}
uint32_t nrfx_gpiote_clr_task_addr_get(nrfx_gpiote_pin_t pin)
{
nrf_gpiote_tasks_t task = nrfx_gpiote_clr_task_get(pin);
return nrf_gpiote_task_addr_get(task);
}
#endif // defined(GPIOTE_FEATURE_CLR_PRESENT)
void nrfx_gpiote_out_task_force(nrfx_gpiote_pin_t pin, uint8_t state)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(pin_in_use(pin));
NRFX_ASSERT(pin_in_use_by_te(pin));
nrf_gpiote_outinit_t init_val =
state ? NRF_GPIOTE_INITIAL_VALUE_HIGH : NRF_GPIOTE_INITIAL_VALUE_LOW;
nrf_gpiote_task_force((uint32_t)m_cb.pin_assignments[pin], init_val);
}
void nrfx_gpiote_out_task_trigger(nrfx_gpiote_pin_t pin)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(pin_in_use(pin));
NRFX_ASSERT(pin_in_use_by_te(pin));
nrf_gpiote_tasks_t task = TE_OUT_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin));
nrf_gpiote_task_set(task);
}
#if defined(GPIOTE_FEATURE_SET_PRESENT)
void nrfx_gpiote_set_task_trigger(nrfx_gpiote_pin_t pin)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(pin_in_use(pin));
NRFX_ASSERT(pin_in_use_by_te(pin));
nrf_gpiote_tasks_t task = TE_SET_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin));
nrf_gpiote_task_set(task);
}
#endif // defined(GPIOTE_FEATURE_SET_PRESENT)
#if defined(GPIOTE_FEATURE_CLR_PRESENT)
void nrfx_gpiote_clr_task_trigger(nrfx_gpiote_pin_t pin)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(pin_in_use(pin));
NRFX_ASSERT(pin_in_use_by_te(pin));
nrf_gpiote_tasks_t task = TE_CLR_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin));
nrf_gpiote_task_set(task);
}
#endif // defined(GPIOTE_FEATURE_CLR_PRESENT)
nrfx_err_t nrfx_gpiote_in_init(nrfx_gpiote_pin_t pin,
nrfx_gpiote_in_config_t const * p_config,
nrfx_gpiote_evt_handler_t evt_handler)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
nrfx_err_t err_code = NRFX_SUCCESS;
/* Only one GPIOTE channel can be assigned to one physical pin. */
if (pin_in_use_by_gpiote(pin))
{
err_code = NRFX_ERROR_INVALID_STATE;
}
else
{
int8_t channel = channel_port_alloc(pin, evt_handler, p_config->hi_accuracy);
if (channel != NO_CHANNELS)
{
if (!p_config->skip_gpio_setup)
{
if (p_config->is_watcher)
{
nrf_gpio_cfg_watcher(pin);
}
else
{
nrf_gpio_cfg_input(pin, p_config->pull);
}
pin_configured_set(pin);
}
if (p_config->hi_accuracy)
{
nrf_gpiote_event_configure((uint32_t)channel, pin, p_config->sense);
}
else
{
m_cb.port_handlers_pins[channel - GPIOTE_CH_NUM] |= (p_config->sense) <<
POLARITY_FIELD_POS;
}
}
else
{
err_code = NRFX_ERROR_NO_MEM;
}
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
void nrfx_gpiote_in_event_enable(nrfx_gpiote_pin_t pin, bool int_enable)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(pin_in_use_by_gpiote(pin));
if (pin_in_use_by_port(pin))
{
nrf_gpiote_polarity_t polarity =
port_handler_polarity_get(channel_port_get(pin) - GPIOTE_CH_NUM);
nrf_gpio_pin_sense_t sense;
if (polarity == NRF_GPIOTE_POLARITY_TOGGLE)
{
/* read current pin state and set for next sense to oposit */
sense = (nrf_gpio_pin_read(pin)) ?
NRF_GPIO_PIN_SENSE_LOW : NRF_GPIO_PIN_SENSE_HIGH;
}
else
{
sense = (polarity == NRF_GPIOTE_POLARITY_LOTOHI) ?
NRF_GPIO_PIN_SENSE_HIGH : NRF_GPIO_PIN_SENSE_LOW;
}
nrf_gpio_cfg_sense_set(pin, sense);
}
else if (pin_in_use_by_te(pin))
{
int32_t channel = (int32_t)channel_port_get(pin);
nrf_gpiote_events_t event = TE_IDX_TO_EVENT_ADDR((uint32_t)channel);
nrf_gpiote_event_enable((uint32_t)channel);
nrf_gpiote_event_clear(event);
if (int_enable)
{
nrfx_gpiote_evt_handler_t handler = channel_handler_get((uint32_t)channel_port_get(pin));
// Enable the interrupt only if event handler was provided.
if (handler)
{
nrf_gpiote_int_enable(1 << channel);
}
}
}
}
void nrfx_gpiote_in_event_disable(nrfx_gpiote_pin_t pin)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(pin_in_use_by_gpiote(pin));
if (pin_in_use_by_port(pin))
{
nrf_gpio_cfg_sense_set(pin, NRF_GPIO_PIN_NOSENSE);
}
else if (pin_in_use_by_te(pin))
{
int32_t channel = (int32_t)channel_port_get(pin);
nrf_gpiote_event_disable((uint32_t)channel);
nrf_gpiote_int_disable(1 << channel);
}
}
void nrfx_gpiote_in_uninit(nrfx_gpiote_pin_t pin)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(pin_in_use_by_gpiote(pin));
nrfx_gpiote_in_event_disable(pin);
if (pin_in_use_by_te(pin))
{
nrf_gpiote_te_default((uint32_t)channel_port_get(pin));
}
if (pin_configured_check(pin))
{
nrf_gpio_cfg_default(pin);
pin_configured_clear(pin);
}
if (pin_in_use_by_gpiote(pin))
{
channel_free((uint8_t)channel_port_get(pin));
}
pin_in_use_clear(pin);
}
bool nrfx_gpiote_in_is_set(nrfx_gpiote_pin_t pin)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
return nrf_gpio_pin_read(pin) ? true : false;
}
nrf_gpiote_events_t nrfx_gpiote_in_event_get(nrfx_gpiote_pin_t pin)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(pin_in_use_by_port(pin) || pin_in_use_by_te(pin));
if (pin_in_use_by_te(pin))
{
return TE_IDX_TO_EVENT_ADDR((uint32_t)channel_port_get(pin));
}
return NRF_GPIOTE_EVENTS_PORT;
}
uint32_t nrfx_gpiote_in_event_addr_get(nrfx_gpiote_pin_t pin)
{
nrf_gpiote_events_t event = nrfx_gpiote_in_event_get(pin);
return nrf_gpiote_event_addr_get(event);
}
#if defined(NRF_GPIO_LATCH_PRESENT)
static bool latch_pending_read_and_check(uint32_t * latch)
{
nrf_gpio_latches_read_and_clear(0, GPIO_COUNT, latch);
for (uint32_t port_idx = 0; port_idx < GPIO_COUNT; port_idx++)
{
if (latch[port_idx])
{
/* If any of the latch bits is still set, it means another edge has been captured
* before or during the interrupt processing. Therefore event-processing loop
* should be executed again. */
return true;
}
}
return false;
}
static void port_event_handle(uint32_t * latch)
{
do {
for (uint32_t i = 0; i < NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS; i++)
{
if (m_cb.port_handlers_pins[i] == PIN_NOT_USED)
{
continue;
}
/* Process pin further only if LATCH bit associated with this pin was set. */
nrfx_gpiote_pin_t pin = port_handler_pin_get(i);
if (nrf_bitmask_bit_is_set(pin, latch))
{
nrf_gpiote_polarity_t polarity = port_handler_polarity_get(i);
nrf_gpio_pin_sense_t sense = nrf_gpio_pin_sense_get(pin);
NRFX_LOG_DEBUG("PORT event for pin: %d, polarity: %d.", pin, polarity);
/* Reconfigure sense to the opposite level, so the internal PINx.DETECT signal
* can be deasserted. Therefore PORT event generated again,
* unless some other PINx.DETECT signal is still active. */
nrf_gpio_pin_sense_t next_sense =
(sense == NRF_GPIO_PIN_SENSE_HIGH) ? NRF_GPIO_PIN_SENSE_LOW :
NRF_GPIO_PIN_SENSE_HIGH;
nrf_gpio_cfg_sense_set(pin, next_sense);
/* Try to clear LATCH bit corresponding to currently processed pin.
* This may not succeed if the pin's state changed during the interrupt processing
* and now it matches the new sense configuration. In such case,
* the pin will be processed again in another iteration of the outer loop. */
nrf_gpio_pin_latch_clear(pin);
/* Invoke user handler only if the sensed pin level
* matches its polarity configuration. */
nrfx_gpiote_evt_handler_t handler =
channel_handler_get((uint32_t)channel_port_get(pin));
if (handler &&
((polarity == NRF_GPIOTE_POLARITY_TOGGLE) ||
(sense == NRF_GPIO_PIN_SENSE_HIGH && polarity == NRF_GPIOTE_POLARITY_LOTOHI) ||
(sense == NRF_GPIO_PIN_SENSE_LOW && polarity == NRF_GPIOTE_POLARITY_HITOLO)))
{
handler(pin, polarity);
}
}
}
} while (latch_pending_read_and_check(latch));
}
#else
static bool input_read_and_check(uint32_t * input, uint32_t * pins_to_check)
{
bool process_inputs_again;
uint32_t new_input[GPIO_COUNT];
nrf_gpio_ports_read(0, GPIO_COUNT, new_input);
process_inputs_again = false;
for (uint32_t port_idx = 0; port_idx < GPIO_COUNT; port_idx++)
{
/* Execute XOR to find out which inputs have changed. */
uint32_t input_diff = input[port_idx] ^ new_input[port_idx];
input[port_idx] = new_input[port_idx];
if (input_diff)
{
/* If any differences among inputs were found, mark those pins
* to be processed again. */
pins_to_check[port_idx] = input_diff;
process_inputs_again = true;
}
else
{
pins_to_check[port_idx] = 0;
}
}
return process_inputs_again;
}
static void port_event_handle(uint32_t * input)
{
uint32_t pins_to_check[GPIO_COUNT];
for (uint32_t port_idx = 0; port_idx < GPIO_COUNT; port_idx++)
{
pins_to_check[port_idx] = 0xFFFFFFFF;
}
do {
for (uint32_t i = 0; i < NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS; i++)
{
if (m_cb.port_handlers_pins[i] == PIN_NOT_USED)
{
continue;
}
nrfx_gpiote_pin_t pin = port_handler_pin_get(i);
if (nrf_bitmask_bit_is_set(pin, pins_to_check))
{
nrf_gpiote_polarity_t polarity = port_handler_polarity_get(i);
nrf_gpio_pin_sense_t sense = nrf_gpio_pin_sense_get(pin);
bool pin_state = nrf_bitmask_bit_is_set(pin, input);
/* Process pin further only if its state matches its sense level. */
if ((pin_state && (sense == NRF_GPIO_PIN_SENSE_HIGH)) ||
(!pin_state && (sense == NRF_GPIO_PIN_SENSE_LOW)) )
{
/* Reconfigure sense to the opposite level, so the internal PINx.DETECT signal
* can be deasserted. Therefore PORT event can be generated again,
* unless some other PINx.DETECT signal is still active. */
NRFX_LOG_DEBUG("PORT event for pin: %d, polarity: %d.", pin, polarity);
nrf_gpio_pin_sense_t next_sense =
(sense == NRF_GPIO_PIN_SENSE_HIGH) ? NRF_GPIO_PIN_SENSE_LOW :
NRF_GPIO_PIN_SENSE_HIGH;
nrf_gpio_cfg_sense_set(pin, next_sense);
/* Invoke user handler only if the sensed pin level
* matches its polarity configuration. */
nrfx_gpiote_evt_handler_t handler =
channel_handler_get((uint32_t)channel_port_get(pin));
if (handler &&
((polarity == NRF_GPIOTE_POLARITY_TOGGLE) ||
(sense == NRF_GPIO_PIN_SENSE_HIGH &&
polarity == NRF_GPIOTE_POLARITY_LOTOHI) ||
(sense == NRF_GPIO_PIN_SENSE_LOW &&
polarity == NRF_GPIOTE_POLARITY_HITOLO)))
{
handler(pin, polarity);
}
}
}
}
} while (input_read_and_check(input, pins_to_check));
}
#endif // defined(NRF_GPIO_LATCH_PRESENT)
void nrfx_gpiote_irq_handler(void)
{
uint32_t status = 0;
uint32_t input[GPIO_COUNT] = {0};
/* collect status of all GPIOTE pin events. Processing is done once all are collected and cleared.*/
uint32_t i;
nrf_gpiote_events_t event = NRF_GPIOTE_EVENTS_IN_0;
uint32_t mask = (uint32_t)NRF_GPIOTE_INT_IN0_MASK;
for (i = 0; i < GPIOTE_CH_NUM; i++)
{
if (nrf_gpiote_event_is_set(event) && nrf_gpiote_int_is_enabled(mask))
{
nrf_gpiote_event_clear(event);
status |= mask;
}
mask <<= 1;
/* Incrementing to next event, utilizing the fact that events are grouped together
* in ascending order. */
event = (nrf_gpiote_events_t)((uint32_t)event + sizeof(uint32_t));
}
/* collect PORT status event, if event is set read pins state. Processing is postponed to the
* end of interrupt. */
if (nrf_gpiote_event_is_set(NRF_GPIOTE_EVENTS_PORT))
{
nrf_gpiote_event_clear(NRF_GPIOTE_EVENTS_PORT);
status |= (uint32_t)NRF_GPIOTE_INT_PORT_MASK;
#if defined(NRF_GPIO_LATCH_PRESENT)
nrf_gpio_latches_read_and_clear(0, GPIO_COUNT, input);
#else
nrf_gpio_ports_read(0, GPIO_COUNT, input);
#endif
}
/* Process pin events. */
if (status & NRF_GPIOTE_INT_IN_MASK)
{
mask = (uint32_t)NRF_GPIOTE_INT_IN0_MASK;
for (i = 0; i < GPIOTE_CH_NUM; i++)
{
if (mask & status)
{
nrfx_gpiote_pin_t pin = nrf_gpiote_event_pin_get(i);
NRFX_LOG_DEBUG("Event in number: %d.", i);
nrf_gpiote_polarity_t polarity = nrf_gpiote_event_polarity_get(i);
nrfx_gpiote_evt_handler_t handler = channel_handler_get(i);
NRFX_LOG_DEBUG("Pin: %d, polarity: %d.", pin, polarity);
if (handler)
{
handler(pin, polarity);
}
}
mask <<= 1;
}
}
/* Process PORT event. */
if (status & (uint32_t)NRF_GPIOTE_INT_PORT_MASK)
{
port_event_handle(input);
}
}
/*lint -restore*/
#endif // NRFX_CHECK(NRFX_GPIOTE_ENABLED)
+435
View File
@@ -0,0 +1,435 @@
/**
* Copyright (c) 2019 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_NVMC_ENABLED)
#include <nrfx_nvmc.h>
/**
* Value representing the number of bytes in a word.
*
* It is used in loops iterating over bytes contained in a word
* or in word-alignment checks.
*/
#define NVMC_BYTES_IN_WORD 4
/**
* Value representing non-volatile memory (NVM) page count.
*
* This symbol is needed to determine NVM page count for chips that cannot
* always access FICR for this information.
*/
#if defined(NRF9160_XXAA)
#define NVMC_FLASH_PAGE_COUNT 256
#endif
/**
* Value representing non-volatile memory (NVM) page size in bytes.
*
* This symbol is needed to determine NVM page size for chips that cannot
* always access FICR for this information.
*/
#if defined(NRF9160_XXAA)
#define NVMC_FLASH_PAGE_SIZE 0x1000 ///< 4 kB
#endif
#if defined(NRF_NVMC_PARTIAL_ERASE_PRESENT)
/**
* Value representing the page erase time.
*
* This value is used to determine whether the partial erase is still in progress.
*/
#if defined(NRF52810_XXAA) || defined(NRF52811_XXAA) || defined(NRF52840_XXAA)
#define NVMC_PAGE_ERASE_DURATION_MS 85
#elif defined(NRF52820_XXAA) || defined(NRF52833_XXAA) || defined(NRF9160_XXAA)
#define NVMC_PAGE_ERASE_DURATION_MS 87
#else
#error "Page partial erase present but could not determine its total duration for given SoC"
#endif
/**
* Value representing the invalid page partial erase address.
*
* This value is used for representing a NULL pointer for
* partial erase, as that address 0 can be a valid
* memory address in flash.
*/
#define NVMC_PARTIAL_ERASE_INVALID_ADDR 0xFFFFFFFF
/** Internal counter for page partial erase. */
static uint32_t m_partial_erase_time_elapsed;
/** Partial erase page address. */
static uint32_t m_partial_erase_page_addr = NVMC_PARTIAL_ERASE_INVALID_ADDR;
#endif // defined(NRF_NVMC_PARTIAL_ERASE_PRESENT)
static uint32_t flash_page_size_get(void)
{
uint32_t flash_page_size = 0;
#if defined(NRF51) || defined(NRF52_SERIES)
flash_page_size = nrf_ficr_codepagesize_get(NRF_FICR);
#elif defined(NVMC_FLASH_PAGE_SIZE)
flash_page_size = NVMC_FLASH_PAGE_SIZE;
#else
#error "Cannot determine flash page size for a given SoC."
#endif
return flash_page_size;
}
static uint32_t flash_page_count_get(void)
{
uint32_t page_count = 0;
#if defined(NRF51) || defined(NRF52_SERIES)
page_count = nrf_ficr_codesize_get(NRF_FICR);
#elif defined(NVMC_FLASH_PAGE_COUNT)
page_count = NVMC_FLASH_PAGE_COUNT;
#else
#error "Cannot determine flash page count for a given SoC."
#endif
return page_count;
}
static uint32_t flash_total_size_get(void)
{
return flash_page_size_get() * flash_page_count_get();
}
static bool is_page_aligned_check(uint32_t addr)
{
/* If the modulo operation returns '0', then the address is aligned. */
return !(addr % flash_page_size_get());
}
static uint32_t partial_word_create(uint32_t addr, uint8_t const * bytes, uint32_t bytes_count)
{
uint32_t value32;
uint32_t byte_shift;
byte_shift = addr % NVMC_BYTES_IN_WORD;
NRFX_ASSERT(bytes_count <= (NVMC_BYTES_IN_WORD - byte_shift));
value32 = 0xFFFFFFFF;
for (uint32_t i = 0; i < bytes_count; i++)
{
((uint8_t *)&value32)[byte_shift] = bytes[i];
byte_shift++;
}
return value32;
}
static void nvmc_readonly_mode_set(void)
{
#if defined(NRF_TRUSTZONE_NONSECURE)
nrf_nvmc_nonsecure_mode_set(NRF_NVMC, NRF_NVMC_NS_MODE_READONLY);
#else
nrf_nvmc_mode_set(NRF_NVMC, NRF_NVMC_MODE_READONLY);
#endif
}
static void nvmc_write_mode_set(void)
{
#if defined(NRF_TRUSTZONE_NONSECURE)
nrf_nvmc_nonsecure_mode_set(NRF_NVMC, NRF_NVMC_NS_MODE_WRITE);
#else
nrf_nvmc_mode_set(NRF_NVMC, NRF_NVMC_MODE_WRITE);
#endif
}
static void nvmc_erase_mode_set(void)
{
#if defined(NRF_TRUSTZONE_NONSECURE)
nrf_nvmc_nonsecure_mode_set(NRF_NVMC, NRF_NVMC_NS_MODE_ERASE);
#else
nrf_nvmc_mode_set(NRF_NVMC, NRF_NVMC_MODE_ERASE);
#endif
}
static void nvmc_word_write(uint32_t addr, uint32_t value)
{
#if defined(NRF9160_XXAA)
while (!nrf_nvmc_write_ready_check(NRF_NVMC))
{}
#else
while (!nrf_nvmc_ready_check(NRF_NVMC))
{}
#endif
*(volatile uint32_t *)addr = value;
__DMB();
}
static void nvmc_words_write(uint32_t addr, void const * src, uint32_t num_words)
{
for (uint32_t i = 0; i < num_words; i++)
{
nvmc_word_write(addr + (NVMC_BYTES_IN_WORD * i), ((uint32_t const *)src)[i]);
}
}
nrfx_err_t nrfx_nvmc_page_erase(uint32_t addr)
{
NRFX_ASSERT(addr < flash_total_size_get());
if (!is_page_aligned_check(addr))
{
return NRFX_ERROR_INVALID_ADDR;
}
nvmc_erase_mode_set();
nrf_nvmc_page_erase_start(NRF_NVMC, addr);
while (!nrf_nvmc_ready_check(NRF_NVMC))
{}
nvmc_readonly_mode_set();
return NRFX_SUCCESS;
}
nrfx_err_t nrfx_nvmc_uicr_erase(void)
{
#if defined(NVMC_ERASEUICR_ERASEUICR_Msk)
nvmc_erase_mode_set();
nrf_nvmc_uicr_erase_start(NRF_NVMC);
while (!nrf_nvmc_ready_check(NRF_NVMC))
{}
nvmc_readonly_mode_set();
return NRFX_SUCCESS;
#else
return NRFX_ERROR_NOT_SUPPORTED;
#endif
}
void nrfx_nvmc_all_erase(void)
{
nvmc_erase_mode_set();
nrf_nvmc_erase_all_start(NRF_NVMC);
while (!nrf_nvmc_ready_check(NRF_NVMC))
{}
nvmc_readonly_mode_set();
}
#if defined(NRF_NVMC_PARTIAL_ERASE_PRESENT)
nrfx_err_t nrfx_nvmc_page_partial_erase_init(uint32_t addr, uint32_t duration_ms)
{
NRFX_ASSERT(addr < flash_total_size_get());
if (!is_page_aligned_check(addr))
{
return NRFX_ERROR_INVALID_ADDR;
}
m_partial_erase_time_elapsed = 0;
m_partial_erase_page_addr = addr;
nrf_nvmc_partial_erase_duration_set(NRF_NVMC, duration_ms);
return NRFX_SUCCESS;
}
bool nrfx_nvmc_page_partial_erase_continue(void)
{
NRFX_ASSERT(m_partial_erase_page_addr != NVMC_PARTIAL_ERASE_INVALID_ADDR);
uint32_t duration_ms = nrf_nvmc_partial_erase_duration_get(NRF_NVMC);
#if defined(NVMC_CONFIG_WEN_PEen)
nrf_nvmc_mode_set(NRF_NVMC, NRF_NVMC_MODE_PARTIAL_ERASE);
#else
nrf_nvmc_mode_set(NRF_NVMC, NRF_NVMC_MODE_ERASE);
#endif
nrf_nvmc_page_partial_erase_start(NRF_NVMC, m_partial_erase_page_addr);
while (!nrf_nvmc_ready_check(NRF_NVMC))
{}
nvmc_readonly_mode_set();
m_partial_erase_time_elapsed += duration_ms;
if (m_partial_erase_time_elapsed < NVMC_PAGE_ERASE_DURATION_MS)
{
return false;
}
else
{
m_partial_erase_page_addr = NVMC_PARTIAL_ERASE_INVALID_ADDR;
return true;
}
}
#endif // defined(NRF_NVMC_PARTIAL_ERASE_PRESENT)
bool nrfx_nvmc_byte_writable_check(uint32_t addr, uint8_t val_to_check)
{
NRFX_ASSERT((addr < flash_total_size_get()) ||
((addr - (uint32_t)NRF_UICR) < sizeof(NRF_UICR_Type)));
uint8_t val_on_addr = *(uint8_t const *)addr;
return (val_to_check & val_on_addr) == val_to_check;
}
bool nrfx_nvmc_word_writable_check(uint32_t addr, uint32_t val_to_check)
{
NRFX_ASSERT((addr < flash_total_size_get()) ||
((addr - (uint32_t)NRF_UICR) < sizeof(NRF_UICR_Type)));
NRFX_ASSERT(nrfx_is_word_aligned((void const *)addr));
uint32_t val_on_addr = *(uint32_t const *)addr;
return (val_to_check & val_on_addr) == val_to_check;
}
void nrfx_nvmc_byte_write(uint32_t addr, uint8_t value)
{
uint32_t aligned_addr = addr & ~(0x03UL);
nrfx_nvmc_word_write(aligned_addr, partial_word_create(addr, &value, 1));
}
void nrfx_nvmc_word_write(uint32_t addr, uint32_t value)
{
NRFX_ASSERT((addr < flash_total_size_get()) ||
((addr - (uint32_t)NRF_UICR) < sizeof(NRF_UICR_Type)));
NRFX_ASSERT(nrfx_is_word_aligned((void const *)addr));
nvmc_write_mode_set();
nvmc_word_write(addr, value);
nvmc_readonly_mode_set();
}
void nrfx_nvmc_bytes_write(uint32_t addr, void const * src, uint32_t num_bytes)
{
NRFX_ASSERT((addr < flash_total_size_get()) ||
((addr - (uint32_t)NRF_UICR) < sizeof(NRF_UICR_Type)));
nvmc_write_mode_set();
uint8_t const * bytes_src = (uint8_t const *)src;
uint32_t unaligned_bytes = addr % NVMC_BYTES_IN_WORD;
if (unaligned_bytes != 0)
{
uint32_t leading_bytes = NVMC_BYTES_IN_WORD - unaligned_bytes;
if (leading_bytes > num_bytes)
{
leading_bytes = num_bytes;
}
nvmc_word_write(addr - unaligned_bytes,
partial_word_create(addr, bytes_src, leading_bytes));
num_bytes -= leading_bytes;
addr += leading_bytes;
bytes_src += leading_bytes;
}
#if defined(__CORTEX_M) && (__CORTEX_M == 0U)
if (!nrfx_is_word_aligned((void const *)bytes_src))
{
/* Cortex-M0 allows only word-aligned RAM access.
If source address is not word-aligned, bytes are combined
into words explicitly. */
for (uint32_t i = 0; i < num_bytes / NVMC_BYTES_IN_WORD; i++)
{
uint32_t word = (uint32_t)bytes_src[0]
| ((uint32_t)bytes_src[1]) << 8
| ((uint32_t)bytes_src[2]) << 16
| ((uint32_t)bytes_src[3]) << 24;
nvmc_word_write(addr, word);
bytes_src += NVMC_BYTES_IN_WORD;
addr += NVMC_BYTES_IN_WORD;
}
}
else
#endif
{
uint32_t word_count = num_bytes / NVMC_BYTES_IN_WORD;
nvmc_words_write(addr, (uint32_t const *)bytes_src, word_count);
addr += word_count * NVMC_BYTES_IN_WORD;
bytes_src += word_count * NVMC_BYTES_IN_WORD;
}
uint32_t trailing_bytes = num_bytes % NVMC_BYTES_IN_WORD;
if (trailing_bytes != 0)
{
nvmc_word_write(addr, partial_word_create(addr, bytes_src, trailing_bytes));
}
nvmc_readonly_mode_set();
}
void nrfx_nvmc_words_write(uint32_t addr, void const * src, uint32_t num_words)
{
NRFX_ASSERT((addr < flash_total_size_get()) ||
((addr - (uint32_t)NRF_UICR) < sizeof(NRF_UICR_Type)));
NRFX_ASSERT(nrfx_is_word_aligned((void const *)addr));
NRFX_ASSERT(nrfx_is_word_aligned(src));
nvmc_write_mode_set();
nvmc_words_write(addr, src, num_words);
nvmc_readonly_mode_set();
}
uint32_t nrfx_nvmc_flash_size_get(void)
{
return flash_total_size_get();
}
uint32_t nrfx_nvmc_flash_page_size_get(void)
{
return flash_page_size_get();
}
uint32_t nrfx_nvmc_flash_page_count_get(void)
{
return flash_page_count_get();
}
#endif // NRFX_CHECK(NRFX_NVMC_ENABLED)
+341
View File
@@ -0,0 +1,341 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_POWER_ENABLED)
#include <nrfx_power.h>
#if defined(REGULATORS_PRESENT)
#include <hal/nrf_regulators.h>
#endif
#if NRFX_CHECK(NRFX_CLOCK_ENABLED)
extern bool nrfx_clock_irq_enabled;
extern void nrfx_clock_irq_handler(void);
#endif
/**
* @internal
* @defgroup nrfx_power_internals POWER driver internals
* @ingroup nrfx_power
*
* Internal variables, auxiliary macros and functions of POWER driver.
* @{
*/
/**
* This variable is used to check whether common POWER_CLOCK common interrupt
* should be disabled or not if @ref nrfx_clock tries to disable the interrupt.
*/
bool nrfx_power_irq_enabled;
/**
* @brief The initialization flag
*/
#define m_initialized nrfx_power_irq_enabled
/**
* @brief The handler of power fail comparator warning event
*/
static nrfx_power_pofwarn_event_handler_t m_pofwarn_handler;
#if NRF_POWER_HAS_SLEEPEVT
/**
* @brief The handler of sleep event handler
*/
static nrfx_power_sleep_event_handler_t m_sleepevt_handler;
#endif
#if NRF_POWER_HAS_USBREG
/**
* @brief The handler of USB power events
*/
static nrfx_power_usb_event_handler_t m_usbevt_handler;
#endif
/** @} */
nrfx_power_pofwarn_event_handler_t nrfx_power_pof_handler_get(void)
{
return m_pofwarn_handler;
}
#if NRF_POWER_HAS_USBREG
nrfx_power_usb_event_handler_t nrfx_power_usb_handler_get(void)
{
return m_usbevt_handler;
}
#endif
nrfx_err_t nrfx_power_init(nrfx_power_config_t const * p_config)
{
NRFX_ASSERT(p_config);
if (m_initialized)
{
return NRFX_ERROR_ALREADY_INITIALIZED;
}
#if NRF_POWER_HAS_DCDCEN_VDDH
nrf_power_dcdcen_vddh_set(p_config->dcdcenhv);
#endif
#if NRF_POWER_HAS_DCDCEN
nrf_power_dcdcen_set(p_config->dcdcen);
#else
nrf_regulators_dcdcen_set(NRF_REGULATORS, p_config->dcdcen);
#endif
nrfx_power_clock_irq_init();
m_initialized = true;
return NRFX_SUCCESS;
}
void nrfx_power_uninit(void)
{
NRFX_ASSERT(m_initialized);
#if NRFX_CHECK(NRFX_CLOCK_ENABLED)
if (!nrfx_clock_irq_enabled)
#endif
{
NRFX_IRQ_DISABLE(nrfx_get_irq_number(NRF_POWER));
}
#if NRF_POWER_HAS_POFCON
nrfx_power_pof_uninit();
#endif
#if NRF_POWER_HAS_SLEEPEVT
nrfx_power_sleepevt_uninit();
#endif
#if NRF_POWER_HAS_USBREG
nrfx_power_usbevt_uninit();
#endif
m_initialized = false;
}
#if NRF_POWER_HAS_POFCON
void nrfx_power_pof_init(nrfx_power_pofwarn_config_t const * p_config)
{
NRFX_ASSERT(p_config != NULL);
nrfx_power_pof_uninit();
if (p_config->handler != NULL)
{
m_pofwarn_handler = p_config->handler;
}
}
void nrfx_power_pof_enable(nrfx_power_pofwarn_config_t const * p_config)
{
nrf_power_pofcon_set(true, p_config->thr);
#if NRF_POWER_HAS_VDDH
nrf_power_pofcon_vddh_set(p_config->thrvddh);
#endif
if (m_pofwarn_handler != NULL)
{
nrf_power_int_enable(NRF_POWER_INT_POFWARN_MASK);
}
}
void nrfx_power_pof_disable(void)
{
nrf_power_pofcon_set(false, NRF_POWER_POFTHR_V27);
nrf_power_int_disable(NRF_POWER_INT_POFWARN_MASK);
}
void nrfx_power_pof_uninit(void)
{
m_pofwarn_handler = NULL;
}
#endif // NRF_POWER_HAS_POFCON
#if NRF_POWER_HAS_SLEEPEVT
void nrfx_power_sleepevt_init(nrfx_power_sleepevt_config_t const * p_config)
{
NRFX_ASSERT(p_config != NULL);
nrfx_power_sleepevt_uninit();
if (p_config->handler != NULL)
{
m_sleepevt_handler = p_config->handler;
}
}
void nrfx_power_sleepevt_enable(nrfx_power_sleepevt_config_t const * p_config)
{
uint32_t enmask = 0;
if (p_config->en_enter)
{
enmask |= NRF_POWER_INT_SLEEPENTER_MASK;
nrf_power_event_clear(NRF_POWER_EVENT_SLEEPENTER);
}
if (p_config->en_exit)
{
enmask |= NRF_POWER_INT_SLEEPEXIT_MASK;
nrf_power_event_clear(NRF_POWER_EVENT_SLEEPEXIT);
}
nrf_power_int_enable(enmask);
}
void nrfx_power_sleepevt_disable(void)
{
nrf_power_int_disable(
NRF_POWER_INT_SLEEPENTER_MASK |
NRF_POWER_INT_SLEEPEXIT_MASK);
}
void nrfx_power_sleepevt_uninit(void)
{
m_sleepevt_handler = NULL;
}
#endif /* NRF_POWER_HAS_SLEEPEVT */
#if NRF_POWER_HAS_USBREG
void nrfx_power_usbevt_init(nrfx_power_usbevt_config_t const * p_config)
{
NRFX_ASSERT(p_config != NULL);
nrfx_power_usbevt_uninit();
if (p_config->handler != NULL)
{
m_usbevt_handler = p_config->handler;
}
}
void nrfx_power_usbevt_enable(void)
{
nrf_power_int_enable(
NRF_POWER_INT_USBDETECTED_MASK |
NRF_POWER_INT_USBREMOVED_MASK |
NRF_POWER_INT_USBPWRRDY_MASK);
}
void nrfx_power_usbevt_disable(void)
{
nrf_power_int_disable(
NRF_POWER_INT_USBDETECTED_MASK |
NRF_POWER_INT_USBREMOVED_MASK |
NRF_POWER_INT_USBPWRRDY_MASK);
}
void nrfx_power_usbevt_uninit(void)
{
m_usbevt_handler = NULL;
}
#endif /* NRF_POWER_HAS_USBREG */
void nrfx_power_irq_handler(void)
{
uint32_t enabled = nrf_power_int_enable_get();
#if NRF_POWER_HAS_POFCON
if ((0 != (enabled & NRF_POWER_INT_POFWARN_MASK)) &&
nrf_power_event_get_and_clear(NRF_POWER_EVENT_POFWARN))
{
/* Cannot be null if event is enabled */
NRFX_ASSERT(m_pofwarn_handler != NULL);
m_pofwarn_handler();
}
#endif
#if NRF_POWER_HAS_SLEEPEVT
if ((0 != (enabled & NRF_POWER_INT_SLEEPENTER_MASK)) &&
nrf_power_event_get_and_clear(NRF_POWER_EVENT_SLEEPENTER))
{
/* Cannot be null if event is enabled */
NRFX_ASSERT(m_sleepevt_handler != NULL);
m_sleepevt_handler(NRFX_POWER_SLEEP_EVT_ENTER);
}
if ((0 != (enabled & NRF_POWER_INT_SLEEPEXIT_MASK)) &&
nrf_power_event_get_and_clear(NRF_POWER_EVENT_SLEEPEXIT))
{
/* Cannot be null if event is enabled */
NRFX_ASSERT(m_sleepevt_handler != NULL);
m_sleepevt_handler(NRFX_POWER_SLEEP_EVT_EXIT);
}
#endif
#if NRF_POWER_HAS_USBREG
if ((0 != (enabled & NRF_POWER_INT_USBDETECTED_MASK)) &&
nrf_power_event_get_and_clear(NRF_POWER_EVENT_USBDETECTED))
{
/* Cannot be null if event is enabled */
NRFX_ASSERT(m_usbevt_handler != NULL);
m_usbevt_handler(NRFX_POWER_USB_EVT_DETECTED);
}
if ((0 != (enabled & NRF_POWER_INT_USBREMOVED_MASK)) &&
nrf_power_event_get_and_clear(NRF_POWER_EVENT_USBREMOVED))
{
/* Cannot be null if event is enabled */
NRFX_ASSERT(m_usbevt_handler != NULL);
m_usbevt_handler(NRFX_POWER_USB_EVT_REMOVED);
}
if ((0 != (enabled & NRF_POWER_INT_USBPWRRDY_MASK)) &&
nrf_power_event_get_and_clear(NRF_POWER_EVENT_USBPWRRDY))
{
/* Cannot be null if event is enabled */
NRFX_ASSERT(m_usbevt_handler != NULL);
m_usbevt_handler(NRFX_POWER_USB_EVT_READY);
}
#endif
}
#if NRFX_CHECK(NRFX_CLOCK_ENABLED)
/*
* If both POWER and CLOCK drivers are used, a common IRQ handler function must
* be used that calls the handlers in these two drivers. This is because these
* two peripherals share one interrupt.
* This function is located here, not in a separate nrfx_power_clock.c file,
* so that it does not end up as the only symbol in a separate object when
* a library with nrfx is created. In such case, forcing a linker to use this
* function instead of another one defined as weak will require additional
* actions, and might be even impossible.
*/
void nrfx_power_clock_irq_handler(void)
{
nrfx_power_irq_handler();
nrfx_clock_irq_handler();
}
#endif
#endif // NRFX_CHECK(NRFX_POWER_ENABLED)
+530
View File
@@ -0,0 +1,530 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_PPI_ENABLED)
#include <nrfx_ppi.h>
#define NRFX_LOG_MODULE PPI
#include <nrfx_log.h>
static uint32_t m_channels_allocated; /**< Bitmap representing channels availability. 1 when a channel is allocated, 0 otherwise. */
static uint8_t m_groups_allocated; /**< Bitmap representing groups availability. 1 when a group is allocated, 0 otherwise.*/
/**
* @brief Compute a group mask (needed for driver internals, not used for NRF_PPI registers).
*
* @param[in] group Group number to transform to a mask.
*
* @retval Group mask.
*/
__STATIC_INLINE uint32_t group_to_mask(nrf_ppi_channel_group_t group)
{
return (1uL << (uint32_t) group);
}
/**
* @brief Check whether a channel is a programmable channel and can be used by an application.
*
* @param[in] channel Channel to check.
*
* @retval true The channel is a programmable application channel.
* @retval false The channel is used by a stack (for example SoftDevice) or is preprogrammed.
*/
__STATIC_INLINE bool is_programmable_app_channel(nrf_ppi_channel_t channel)
{
return ((NRFX_PPI_PROG_APP_CHANNELS_MASK & nrfx_ppi_channel_to_mask(channel)) != 0);
}
/**
* @brief Check whether channels can be used by an application.
*
* @param[in] channel_mask Channel mask to check.
*
* @retval true All specified channels can be used by an application.
* @retval false At least one specified channel is used by a stack (for example SoftDevice).
*/
__STATIC_INLINE bool are_app_channels(uint32_t channel_mask)
{
//lint -e(587)
return ((~(NRFX_PPI_ALL_APP_CHANNELS_MASK) & channel_mask) == 0);
}
/**
* @brief Check whether a channel can be used by an application.
*
* @param[in] channel Channel to check.
*
* @retval true The channel can be used by an application.
* @retval false The channel is used by a stack (for example SoftDevice).
*/
__STATIC_INLINE bool is_app_channel(nrf_ppi_channel_t channel)
{
return are_app_channels(nrfx_ppi_channel_to_mask(channel));
}
/**
* @brief Check whether a channel group can be used by an application.
*
* @param[in] group Group to check.
*
* @retval true The group is an application group.
* @retval false The group is not an application group (this group either does not exist or
* it is used by a stack (for example SoftDevice)).
*/
__STATIC_INLINE bool is_app_group(nrf_ppi_channel_group_t group)
{
return ((NRFX_PPI_ALL_APP_GROUPS_MASK & group_to_mask(group)) != 0);
}
/**
* @brief Check whether a channel is allocated.
*
* @param[in] channel_num Channel number to check.
*
* @retval true The channel is allocated.
* @retval false The channel is not allocated.
*/
__STATIC_INLINE bool is_allocated_channel(nrf_ppi_channel_t channel)
{
return ((m_channels_allocated & nrfx_ppi_channel_to_mask(channel)) != 0);
}
/**
* @brief Set channel allocated indication.
*
* @param[in] channel_num Specifies the channel to set the "allocated" indication.
*/
__STATIC_INLINE void channel_allocated_set(nrf_ppi_channel_t channel)
{
m_channels_allocated |= nrfx_ppi_channel_to_mask(channel);
}
/**
* @brief Clear channel allocated indication.
*
* @param[in] channel_num Specifies the channel to clear the "allocated" indication.
*/
__STATIC_INLINE void channel_allocated_clr(nrf_ppi_channel_t channel)
{
m_channels_allocated &= ~nrfx_ppi_channel_to_mask(channel);
}
/**
* @brief Clear all allocated channels.
*/
__STATIC_INLINE void channel_allocated_clr_all(void)
{
m_channels_allocated &= ~NRFX_PPI_ALL_APP_CHANNELS_MASK;
}
/**
* @brief Check whether a group is allocated.
*
* @param[in] group_num Group number to check.
*
* @retval true The group is allocated.
* false The group is not allocated.
*/
__STATIC_INLINE bool is_allocated_group(nrf_ppi_channel_group_t group)
{
return ((m_groups_allocated & group_to_mask(group)) != 0);
}
/**
* @brief Set group allocated indication.
*
* @param[in] group_num Specifies the group to set the "allocated" indication.
*/
__STATIC_INLINE void group_allocated_set(nrf_ppi_channel_group_t group)
{
m_groups_allocated |= group_to_mask(group);
}
/**
* @brief Clear group allocated indication.
*
* @param[in] group_num Specifies the group to clear the "allocated" indication.
*/
__STATIC_INLINE void group_allocated_clr(nrf_ppi_channel_group_t group)
{
m_groups_allocated &= ~group_to_mask(group);
}
/**
* @brief Clear all allocated groups.
*/
__STATIC_INLINE void group_allocated_clr_all()
{
m_groups_allocated &= ~NRFX_PPI_ALL_APP_GROUPS_MASK;
}
void nrfx_ppi_free_all(void)
{
uint32_t mask = NRFX_PPI_ALL_APP_GROUPS_MASK;
nrf_ppi_channel_group_t group;
// Disable all channels and groups
nrf_ppi_channels_disable(NRFX_PPI_ALL_APP_CHANNELS_MASK);
for (group = NRF_PPI_CHANNEL_GROUP0; mask != 0; mask &= ~group_to_mask(group), group++)
{
if (mask & group_to_mask(group))
{
nrf_ppi_channel_group_clear(group);
}
}
channel_allocated_clr_all();
group_allocated_clr_all();
}
nrfx_err_t nrfx_ppi_channel_alloc(nrf_ppi_channel_t * p_channel)
{
nrfx_err_t err_code = NRFX_SUCCESS;
nrf_ppi_channel_t channel;
uint32_t mask = 0;
err_code = NRFX_ERROR_NO_MEM;
mask = NRFX_PPI_PROG_APP_CHANNELS_MASK;
for (channel = NRF_PPI_CHANNEL0;
mask != 0;
mask &= ~nrfx_ppi_channel_to_mask(channel), channel++)
{
NRFX_CRITICAL_SECTION_ENTER();
if ((mask & nrfx_ppi_channel_to_mask(channel)) && (!is_allocated_channel(channel)))
{
channel_allocated_set(channel);
*p_channel = channel;
err_code = NRFX_SUCCESS;
}
NRFX_CRITICAL_SECTION_EXIT();
if (err_code == NRFX_SUCCESS)
{
NRFX_LOG_INFO("Allocated channel: %d.", channel);
break;
}
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_ppi_channel_free(nrf_ppi_channel_t channel)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if (!is_programmable_app_channel(channel))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else
{
// First disable this channel
nrf_ppi_channel_disable(channel);
NRFX_CRITICAL_SECTION_ENTER();
channel_allocated_clr(channel);
NRFX_CRITICAL_SECTION_EXIT();
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_ppi_channel_assign(nrf_ppi_channel_t channel, uint32_t eep, uint32_t tep)
{
if ((uint32_t *)eep == NULL || (uint32_t *)tep == NULL)
{
return NRFX_ERROR_NULL;
}
nrfx_err_t err_code = NRFX_SUCCESS;
if (!is_programmable_app_channel(channel))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else if (!is_allocated_channel(channel))
{
err_code = NRFX_ERROR_INVALID_STATE;
}
else
{
nrf_ppi_channel_endpoint_setup(channel, eep, tep);
NRFX_LOG_INFO("Assigned channel: %d, event end point: %x, task end point: %x.",
channel,
eep,
tep);
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_ppi_channel_fork_assign(nrf_ppi_channel_t channel, uint32_t fork_tep)
{
nrfx_err_t err_code = NRFX_SUCCESS;
#ifdef PPI_FEATURE_FORKS_PRESENT
if (!is_allocated_channel(channel))
{
err_code = NRFX_ERROR_INVALID_STATE;
}
else
{
nrf_ppi_fork_endpoint_setup(channel, fork_tep);
NRFX_LOG_INFO("Fork assigned channel: %d, task end point: %d.", channel, fork_tep);
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
#else
err_code = NRFX_ERROR_NOT_SUPPORTED;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
#endif
}
nrfx_err_t nrfx_ppi_channel_enable(nrf_ppi_channel_t channel)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if (!is_app_channel(channel))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else if (is_programmable_app_channel(channel) && !is_allocated_channel(channel))
{
err_code = NRFX_ERROR_INVALID_STATE;
}
else
{
nrf_ppi_channel_enable(channel);
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_ppi_channel_disable(nrf_ppi_channel_t channel)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if (!is_app_channel(channel))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else if (is_programmable_app_channel(channel) && !is_allocated_channel(channel))
{
err_code = NRFX_ERROR_INVALID_STATE;
}
else
{
nrf_ppi_channel_disable(channel);
err_code = NRFX_SUCCESS;
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_ppi_group_alloc(nrf_ppi_channel_group_t * p_group)
{
nrfx_err_t err_code;
uint32_t mask = 0;
nrf_ppi_channel_group_t group;
err_code = NRFX_ERROR_NO_MEM;
mask = NRFX_PPI_ALL_APP_GROUPS_MASK;
for (group = NRF_PPI_CHANNEL_GROUP0; mask != 0; mask &= ~group_to_mask(group), group++)
{
NRFX_CRITICAL_SECTION_ENTER();
if ((mask & group_to_mask(group)) && (!is_allocated_group(group)))
{
group_allocated_set(group);
*p_group = group;
err_code = NRFX_SUCCESS;
}
NRFX_CRITICAL_SECTION_EXIT();
if (err_code == NRFX_SUCCESS)
{
NRFX_LOG_INFO("Allocated group: %d.", group);
break;
}
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_ppi_group_free(nrf_ppi_channel_group_t group)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if (!is_app_group(group))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
if (!is_allocated_group(group))
{
err_code = NRFX_ERROR_INVALID_STATE;
}
else
{
nrf_ppi_group_disable(group);
NRFX_CRITICAL_SECTION_ENTER();
group_allocated_clr(group);
NRFX_CRITICAL_SECTION_EXIT();
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_ppi_group_enable(nrf_ppi_channel_group_t group)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if (!is_app_group(group))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else if (!is_allocated_group(group))
{
err_code = NRFX_ERROR_INVALID_STATE;
}
else
{
nrf_ppi_group_enable(group);
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_ppi_group_disable(nrf_ppi_channel_group_t group)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if (!is_app_group(group))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else
{
nrf_ppi_group_disable(group);
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_ppi_channels_remove_from_group(uint32_t channel_mask,
nrf_ppi_channel_group_t group)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if (!is_app_group(group))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else if (!is_allocated_group(group))
{
err_code = NRFX_ERROR_INVALID_STATE;
}
else if (!are_app_channels(channel_mask))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else
{
NRFX_CRITICAL_SECTION_ENTER();
nrf_ppi_channels_remove_from_group(channel_mask, group);
NRFX_CRITICAL_SECTION_EXIT();
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_ppi_channels_include_in_group(uint32_t channel_mask,
nrf_ppi_channel_group_t group)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if (!is_app_group(group))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else if (!is_allocated_group(group))
{
err_code = NRFX_ERROR_INVALID_STATE;
}
else if (!are_app_channels(channel_mask))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else
{
NRFX_CRITICAL_SECTION_ENTER();
nrf_ppi_channels_include_in_group(channel_mask, group);
NRFX_CRITICAL_SECTION_EXIT();
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
#endif // NRFX_CHECK(NRFX_PPI_ENABLED)
+523
View File
@@ -0,0 +1,523 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_PWM_ENABLED)
#if !(NRFX_CHECK(NRFX_PWM0_ENABLED) || NRFX_CHECK(NRFX_PWM1_ENABLED) || \
NRFX_CHECK(NRFX_PWM2_ENABLED) || NRFX_CHECK(NRFX_PWM3_ENABLED))
#error "No enabled PWM instances. Check <nrfx_config.h>."
#endif
#include <nrfx_pwm.h>
#include <hal/nrf_gpio.h>
#define NRFX_LOG_MODULE PWM
#include <nrfx_log.h>
#if NRFX_CHECK(NRFX_PWM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
// The workaround uses interrupts to wake up the CPU and ensure it is active
// when PWM is about to start a DMA transfer. For initial transfer, done when
// a playback is started via PPI, a specific EGU instance is used to generate
// an interrupt. During the playback, the PWM interrupt triggered on SEQEND
// event of a preceding sequence is used to protect the transfer done for
// the next sequence to be played.
#include <hal/nrf_egu.h>
#define USE_DMA_ISSUE_WORKAROUND
#endif
#if defined(USE_DMA_ISSUE_WORKAROUND)
#define EGU_IRQn(i) EGU_IRQn_(i)
#define EGU_IRQn_(i) SWI##i##_EGU##i##_IRQn
#define EGU_IRQHandler(i) EGU_IRQHandler_(i)
#define EGU_IRQHandler_(i) nrfx_swi_##i##_irq_handler
#define DMA_ISSUE_EGU_IDX NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE
#define DMA_ISSUE_EGU NRFX_CONCAT_2(NRF_EGU, DMA_ISSUE_EGU_IDX)
#define DMA_ISSUE_EGU_IRQn EGU_IRQn(DMA_ISSUE_EGU_IDX)
#define DMA_ISSUE_EGU_IRQHandler EGU_IRQHandler(DMA_ISSUE_EGU_IDX)
#endif
// Control block - driver instance local data.
typedef struct
{
#if defined(USE_DMA_ISSUE_WORKAROUND)
uint32_t starting_task_address;
#endif
nrfx_pwm_handler_t handler;
nrfx_drv_state_t volatile state;
uint8_t flags;
} pwm_control_block_t;
static pwm_control_block_t m_cb[NRFX_PWM_ENABLED_COUNT];
static void configure_pins(nrfx_pwm_t const * const p_instance,
nrfx_pwm_config_t const * p_config)
{
uint32_t out_pins[NRF_PWM_CHANNEL_COUNT];
uint8_t i;
for (i = 0; i < NRF_PWM_CHANNEL_COUNT; ++i)
{
uint8_t output_pin = p_config->output_pins[i];
if (output_pin != NRFX_PWM_PIN_NOT_USED)
{
bool inverted = output_pin & NRFX_PWM_PIN_INVERTED;
out_pins[i] = output_pin & ~NRFX_PWM_PIN_INVERTED;
if (inverted)
{
nrf_gpio_pin_set(out_pins[i]);
}
else
{
nrf_gpio_pin_clear(out_pins[i]);
}
nrf_gpio_cfg_output(out_pins[i]);
}
else
{
out_pins[i] = NRF_PWM_PIN_NOT_CONNECTED;
}
}
nrf_pwm_pins_set(p_instance->p_registers, out_pins);
}
nrfx_err_t nrfx_pwm_init(nrfx_pwm_t const * const p_instance,
nrfx_pwm_config_t const * p_config,
nrfx_pwm_handler_t handler)
{
NRFX_ASSERT(p_config);
nrfx_err_t err_code;
pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
{
err_code = NRFX_ERROR_INVALID_STATE;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
p_cb->handler = handler;
configure_pins(p_instance, p_config);
nrf_pwm_enable(p_instance->p_registers);
nrf_pwm_configure(p_instance->p_registers,
p_config->base_clock, p_config->count_mode, p_config->top_value);
nrf_pwm_decoder_set(p_instance->p_registers,
p_config->load_mode, p_config->step_mode);
nrf_pwm_shorts_set(p_instance->p_registers, 0);
nrf_pwm_int_set(p_instance->p_registers, 0);
nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_LOOPSDONE);
nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_SEQEND0);
nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_SEQEND1);
nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_STOPPED);
// The workaround for nRF52 Anomaly 109 "protects" DMA transfers by handling
// interrupts generated on SEQEND0 and SEQEND1 events (this ensures that
// the 64 MHz clock is ready when data for the next sequence to be played
// is read). Therefore, the PWM interrupt must be enabled even if the event
// handler is not used.
#if defined(USE_DMA_ISSUE_WORKAROUND)
NRFX_IRQ_PRIORITY_SET(DMA_ISSUE_EGU_IRQn, p_config->irq_priority);
NRFX_IRQ_ENABLE(DMA_ISSUE_EGU_IRQn);
#else
if (p_cb->handler)
#endif
{
NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_registers),
p_config->irq_priority);
NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_registers));
}
p_cb->state = NRFX_DRV_STATE_INITIALIZED;
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
void nrfx_pwm_uninit(nrfx_pwm_t const * const p_instance)
{
pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_registers));
#if defined(USE_DMA_ISSUE_WORKAROUND)
NRFX_IRQ_DISABLE(DMA_ISSUE_EGU_IRQn);
#endif
nrf_pwm_disable(p_instance->p_registers);
p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
}
static uint32_t start_playback(nrfx_pwm_t const * const p_instance,
pwm_control_block_t * p_cb,
uint8_t flags,
nrf_pwm_task_t starting_task)
{
p_cb->state = NRFX_DRV_STATE_POWERED_ON;
p_cb->flags = flags;
if (p_cb->handler)
{
// The notification about finished playback is by default enabled,
// but this can be suppressed.
// The notification that the peripheral has stopped is always enabled.
uint32_t int_mask = NRF_PWM_INT_LOOPSDONE_MASK |
NRF_PWM_INT_STOPPED_MASK;
// The workaround for nRF52 Anomaly 109 "protects" DMA transfers by
// handling interrupts generated on SEQEND0 and SEQEND1 events (see
// 'nrfx_pwm_init'), hence these events must be always enabled
// to generate interrupts.
// However, the user handler is called for them only when requested
// (see 'irq_handler').
#if defined(USE_DMA_ISSUE_WORKAROUND)
int_mask |= NRF_PWM_INT_SEQEND0_MASK | NRF_PWM_INT_SEQEND1_MASK;
#else
if (flags & NRFX_PWM_FLAG_SIGNAL_END_SEQ0)
{
int_mask |= NRF_PWM_INT_SEQEND0_MASK;
}
if (flags & NRFX_PWM_FLAG_SIGNAL_END_SEQ1)
{
int_mask |= NRF_PWM_INT_SEQEND1_MASK;
}
#endif
if (flags & NRFX_PWM_FLAG_NO_EVT_FINISHED)
{
int_mask &= ~NRF_PWM_INT_LOOPSDONE_MASK;
}
nrf_pwm_int_set(p_instance->p_registers, int_mask);
}
#if defined(USE_DMA_ISSUE_WORKAROUND)
else
{
nrf_pwm_int_set(p_instance->p_registers,
NRF_PWM_INT_SEQEND0_MASK | NRF_PWM_INT_SEQEND1_MASK);
}
#endif
nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_STOPPED);
if (flags & NRFX_PWM_FLAG_START_VIA_TASK)
{
uint32_t starting_task_address =
nrf_pwm_task_address_get(p_instance->p_registers, starting_task);
#if defined(USE_DMA_ISSUE_WORKAROUND)
// To "protect" the initial DMA transfer it is required to start
// the PWM by triggering the proper task from EGU interrupt handler,
// it is not safe to do it directly via PPI.
p_cb->starting_task_address = starting_task_address;
nrf_egu_int_enable(DMA_ISSUE_EGU,
nrf_egu_int_get(DMA_ISSUE_EGU, p_instance->drv_inst_idx));
return (uint32_t)nrf_egu_task_trigger_address_get(DMA_ISSUE_EGU,
p_instance->drv_inst_idx);
#else
return starting_task_address;
#endif
}
nrf_pwm_task_trigger(p_instance->p_registers, starting_task);
return 0;
}
uint32_t nrfx_pwm_simple_playback(nrfx_pwm_t const * const p_instance,
nrf_pwm_sequence_t const * p_sequence,
uint16_t playback_count,
uint32_t flags)
{
pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
NRFX_ASSERT(playback_count > 0);
NRFX_ASSERT(nrfx_is_in_ram(p_sequence->values.p_raw));
// To take advantage of the looping mechanism, we need to use both sequences
// (single sequence can be played back only once).
nrf_pwm_sequence_set(p_instance->p_registers, 0, p_sequence);
nrf_pwm_sequence_set(p_instance->p_registers, 1, p_sequence);
bool odd = (playback_count & 1);
nrf_pwm_loop_set(p_instance->p_registers,
(playback_count / 2) + (odd ? 1 : 0));
uint32_t shorts_mask;
if (flags & NRFX_PWM_FLAG_STOP)
{
shorts_mask = NRF_PWM_SHORT_LOOPSDONE_STOP_MASK;
}
else if (flags & NRFX_PWM_FLAG_LOOP)
{
shorts_mask = odd ? NRF_PWM_SHORT_LOOPSDONE_SEQSTART1_MASK
: NRF_PWM_SHORT_LOOPSDONE_SEQSTART0_MASK;
}
else
{
shorts_mask = 0;
}
nrf_pwm_shorts_set(p_instance->p_registers, shorts_mask);
NRFX_LOG_INFO("Function: %s, sequence length: %d.",
__func__,
p_sequence->length);
NRFX_LOG_DEBUG("Sequence data:");
NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)p_sequence->values.p_raw,
p_sequence->length * sizeof(uint16_t));
return start_playback(p_instance, p_cb, flags,
odd ? NRF_PWM_TASK_SEQSTART1 : NRF_PWM_TASK_SEQSTART0);
}
uint32_t nrfx_pwm_complex_playback(nrfx_pwm_t const * const p_instance,
nrf_pwm_sequence_t const * p_sequence_0,
nrf_pwm_sequence_t const * p_sequence_1,
uint16_t playback_count,
uint32_t flags)
{
pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
NRFX_ASSERT(playback_count > 0);
NRFX_ASSERT(nrfx_is_in_ram(p_sequence_0->values.p_raw));
NRFX_ASSERT(nrfx_is_in_ram(p_sequence_1->values.p_raw));
nrf_pwm_sequence_set(p_instance->p_registers, 0, p_sequence_0);
nrf_pwm_sequence_set(p_instance->p_registers, 1, p_sequence_1);
nrf_pwm_loop_set(p_instance->p_registers, playback_count);
uint32_t shorts_mask;
if (flags & NRFX_PWM_FLAG_STOP)
{
shorts_mask = NRF_PWM_SHORT_LOOPSDONE_STOP_MASK;
}
else if (flags & NRFX_PWM_FLAG_LOOP)
{
shorts_mask = NRF_PWM_SHORT_LOOPSDONE_SEQSTART0_MASK;
}
else
{
shorts_mask = 0;
}
nrf_pwm_shorts_set(p_instance->p_registers, shorts_mask);
NRFX_LOG_INFO("Function: %s, sequence 0 length: %d.",
__func__,
p_sequence_0->length);
NRFX_LOG_INFO("Function: %s, sequence 1 length: %d.",
__func__,
p_sequence_1->length);
NRFX_LOG_DEBUG("Sequence 0 data:");
NRFX_LOG_HEXDUMP_DEBUG(p_sequence_0->values.p_raw,
p_sequence_0->length * sizeof(uint16_t));
NRFX_LOG_DEBUG("Sequence 1 data:");
NRFX_LOG_HEXDUMP_DEBUG(p_sequence_1->values.p_raw,
p_sequence_1->length * sizeof(uint16_t));
return start_playback(p_instance, p_cb, flags, NRF_PWM_TASK_SEQSTART0);
}
bool nrfx_pwm_stop(nrfx_pwm_t const * const p_instance,
bool wait_until_stopped)
{
NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state != NRFX_DRV_STATE_UNINITIALIZED);
bool ret_val = false;
// Deactivate shortcuts before triggering the STOP task, otherwise the PWM
// could be immediately started again if the LOOPSDONE event occurred in
// the same peripheral clock cycle as the STOP task was triggered.
nrf_pwm_shorts_set(p_instance->p_registers, 0);
// Trigger the STOP task even if the PWM appears to be already stopped.
// It won't harm, but it could help if for some strange reason the stopped
// status was not reported correctly.
nrf_pwm_task_trigger(p_instance->p_registers, NRF_PWM_TASK_STOP);
if (nrfx_pwm_is_stopped(p_instance))
{
ret_val = true;
}
else
{
do {
if (nrfx_pwm_is_stopped(p_instance))
{
ret_val = true;
break;
}
} while (wait_until_stopped);
}
NRFX_LOG_INFO("%s returned %d.", __func__, ret_val);
return ret_val;
}
bool nrfx_pwm_is_stopped(nrfx_pwm_t const * const p_instance)
{
pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
bool ret_val = false;
// If the event handler is used (interrupts are enabled), the state will
// be changed in interrupt handler when the STOPPED event occurs.
if (p_cb->state != NRFX_DRV_STATE_POWERED_ON)
{
ret_val = true;
}
// If interrupts are disabled, we must check the STOPPED event here.
if (nrf_pwm_event_check(p_instance->p_registers, NRF_PWM_EVENT_STOPPED))
{
p_cb->state = NRFX_DRV_STATE_INITIALIZED;
NRFX_LOG_INFO("Disabled.");
ret_val = true;
}
NRFX_LOG_INFO("%s returned %d.", __func__, ret_val);
return ret_val;
}
static void irq_handler(NRF_PWM_Type * p_pwm, pwm_control_block_t * p_cb)
{
// The user handler is called for SEQEND0 and SEQEND1 events only when the
// user asks for it (by setting proper flags when starting the playback).
if (nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_SEQEND0))
{
nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_SEQEND0);
if ((p_cb->flags & NRFX_PWM_FLAG_SIGNAL_END_SEQ0) && p_cb->handler)
{
p_cb->handler(NRFX_PWM_EVT_END_SEQ0);
}
}
if (nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_SEQEND1))
{
nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_SEQEND1);
if ((p_cb->flags & NRFX_PWM_FLAG_SIGNAL_END_SEQ1) && p_cb->handler)
{
p_cb->handler(NRFX_PWM_EVT_END_SEQ1);
}
}
// For LOOPSDONE the handler is called by default, but the user can disable
// this (via flags).
if (nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_LOOPSDONE))
{
nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_LOOPSDONE);
if (!(p_cb->flags & NRFX_PWM_FLAG_NO_EVT_FINISHED) && p_cb->handler)
{
p_cb->handler(NRFX_PWM_EVT_FINISHED);
}
}
// The STOPPED event is always propagated to the user handler.
if (nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_STOPPED))
{
nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_STOPPED);
p_cb->state = NRFX_DRV_STATE_INITIALIZED;
if (p_cb->handler)
{
p_cb->handler(NRFX_PWM_EVT_STOPPED);
}
}
}
#if defined(USE_DMA_ISSUE_WORKAROUND)
// See 'start_playback' why this is needed.
void DMA_ISSUE_EGU_IRQHandler(void)
{
int i;
for (i = 0; i < NRFX_PWM_ENABLED_COUNT; ++i)
{
volatile uint32_t * p_event_reg =
nrf_egu_event_triggered_address_get(DMA_ISSUE_EGU, i);
if (*p_event_reg)
{
*p_event_reg = 0;
*(volatile uint32_t *)(m_cb[i].starting_task_address) = 1;
}
}
}
#endif
#if NRFX_CHECK(NRFX_PWM0_ENABLED)
void nrfx_pwm_0_irq_handler(void)
{
irq_handler(NRF_PWM0, &m_cb[NRFX_PWM0_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_PWM1_ENABLED)
void nrfx_pwm_1_irq_handler(void)
{
irq_handler(NRF_PWM1, &m_cb[NRFX_PWM1_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_PWM2_ENABLED)
void nrfx_pwm_2_irq_handler(void)
{
irq_handler(NRF_PWM2, &m_cb[NRFX_PWM2_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_PWM3_ENABLED)
void nrfx_pwm_3_irq_handler(void)
{
irq_handler(NRF_PWM3, &m_cb[NRFX_PWM3_INST_IDX]);
}
#endif
#endif // NRFX_CHECK(NRFX_PWM_ENABLED)
+122
View File
@@ -0,0 +1,122 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_RNG_ENABLED)
#include <nrfx_rng.h>
#define NRFX_LOG_MODULE RNG
#include <nrfx_log.h>
/**
* @brief Internal state of RNG driver.
*/
static nrfx_drv_state_t m_rng_state;
/**
* @brief Pointer to handler calling from interrupt routine.
*/
static nrfx_rng_evt_handler_t m_rng_hndl;
nrfx_err_t nrfx_rng_init(nrfx_rng_config_t const * p_config, nrfx_rng_evt_handler_t handler)
{
NRFX_ASSERT(p_config);
NRFX_ASSERT(handler);
if (m_rng_state != NRFX_DRV_STATE_UNINITIALIZED)
{
return NRFX_ERROR_ALREADY_INITIALIZED;
}
m_rng_hndl = handler;
if (p_config->error_correction)
{
nrf_rng_error_correction_enable();
}
nrf_rng_shorts_disable(NRF_RNG_SHORT_VALRDY_STOP_MASK);
NRFX_IRQ_PRIORITY_SET(RNG_IRQn, p_config->interrupt_priority);
NRFX_IRQ_ENABLE(RNG_IRQn);
m_rng_state = NRFX_DRV_STATE_INITIALIZED;
return NRFX_SUCCESS;
}
void nrfx_rng_start(void)
{
NRFX_ASSERT(m_rng_state == NRFX_DRV_STATE_INITIALIZED);
nrf_rng_event_clear(NRF_RNG_EVENT_VALRDY);
nrf_rng_int_enable(NRF_RNG_INT_VALRDY_MASK);
nrf_rng_task_trigger(NRF_RNG_TASK_START);
}
void nrfx_rng_stop(void)
{
NRFX_ASSERT(m_rng_state == NRFX_DRV_STATE_INITIALIZED);
nrf_rng_int_disable(NRF_RNG_INT_VALRDY_MASK);
nrf_rng_task_trigger(NRF_RNG_TASK_STOP);
}
void nrfx_rng_uninit(void)
{
NRFX_ASSERT(m_rng_state == NRFX_DRV_STATE_INITIALIZED);
nrf_rng_int_disable(NRF_RNG_INT_VALRDY_MASK);
nrf_rng_task_trigger(NRF_RNG_TASK_STOP);
NRFX_IRQ_DISABLE(RNG_IRQn);
m_rng_state = NRFX_DRV_STATE_UNINITIALIZED;
NRFX_LOG_INFO("Uninitialized.");
}
void nrfx_rng_irq_handler(void)
{
nrf_rng_event_clear(NRF_RNG_EVENT_VALRDY);
uint8_t rng_value = nrf_rng_random_value_get();
m_rng_hndl(rng_value);
NRFX_LOG_DEBUG("Event: NRF_RNG_EVENT_VALRDY.");
}
#endif // NRFX_CHECK(NRFX_RNG_ENABLED)
+348
View File
@@ -0,0 +1,348 @@
/**
* Copyright (c) 2014 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_RTC_ENABLED)
#if !(NRFX_CHECK(NRFX_RTC0_ENABLED) || NRFX_CHECK(NRFX_RTC1_ENABLED) || \
NRFX_CHECK(NRFX_RTC2_ENABLED))
#error "No enabled RTC instances. Check <nrfx_config.h>."
#endif
#include <nrfx_rtc.h>
#define NRFX_LOG_MODULE RTC
#include <nrfx_log.h>
#define EVT_TO_STR(event) \
(event == NRF_RTC_EVENT_TICK ? "NRF_RTC_EVENT_TICK" : \
(event == NRF_RTC_EVENT_OVERFLOW ? "NRF_RTC_EVENT_OVERFLOW" : \
(event == NRF_RTC_EVENT_COMPARE_0 ? "NRF_RTC_EVENT_COMPARE_0" : \
(event == NRF_RTC_EVENT_COMPARE_1 ? "NRF_RTC_EVENT_COMPARE_1" : \
(event == NRF_RTC_EVENT_COMPARE_2 ? "NRF_RTC_EVENT_COMPARE_2" : \
(event == NRF_RTC_EVENT_COMPARE_3 ? "NRF_RTC_EVENT_COMPARE_3" : \
"UNKNOWN EVENT"))))))
/**@brief RTC driver instance control block structure. */
typedef struct
{
nrfx_drv_state_t state; /**< Instance state. */
bool reliable; /**< Reliable mode flag. */
uint8_t tick_latency; /**< Maximum length of interrupt handler in ticks (max 7.7 ms). */
} nrfx_rtc_cb_t;
// User callbacks local storage.
static nrfx_rtc_handler_t m_handlers[NRFX_RTC_ENABLED_COUNT];
static nrfx_rtc_cb_t m_cb[NRFX_RTC_ENABLED_COUNT];
nrfx_err_t nrfx_rtc_init(nrfx_rtc_t const * const p_instance,
nrfx_rtc_config_t const * p_config,
nrfx_rtc_handler_t handler)
{
NRFX_ASSERT(p_config);
NRFX_ASSERT(handler);
nrfx_err_t err_code;
m_handlers[p_instance->instance_id] = handler;
if (m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED)
{
err_code = NRFX_ERROR_INVALID_STATE;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
NRFX_IRQ_PRIORITY_SET(p_instance->irq, p_config->interrupt_priority);
NRFX_IRQ_ENABLE(p_instance->irq);
nrf_rtc_prescaler_set(p_instance->p_reg, p_config->prescaler);
m_cb[p_instance->instance_id].reliable = p_config->reliable;
m_cb[p_instance->instance_id].tick_latency = p_config->tick_latency;
m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_INITIALIZED;
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
void nrfx_rtc_uninit(nrfx_rtc_t const * const p_instance)
{
uint32_t mask = NRF_RTC_INT_TICK_MASK |
NRF_RTC_INT_OVERFLOW_MASK |
NRF_RTC_INT_COMPARE0_MASK |
NRF_RTC_INT_COMPARE1_MASK |
NRF_RTC_INT_COMPARE2_MASK |
NRF_RTC_INT_COMPARE3_MASK;
NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
NRFX_IRQ_DISABLE(p_instance->irq);
nrf_rtc_task_trigger(p_instance->p_reg, NRF_RTC_TASK_STOP);
nrf_rtc_event_disable(p_instance->p_reg, mask);
nrf_rtc_int_disable(p_instance->p_reg, mask);
m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_UNINITIALIZED;
NRFX_LOG_INFO("Uninitialized.");
}
void nrfx_rtc_enable(nrfx_rtc_t const * const p_instance)
{
NRFX_ASSERT(m_cb[p_instance->instance_id].state == NRFX_DRV_STATE_INITIALIZED);
nrf_rtc_task_trigger(p_instance->p_reg, NRF_RTC_TASK_START);
m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_POWERED_ON;
NRFX_LOG_INFO("Enabled.");
}
void nrfx_rtc_disable(nrfx_rtc_t const * const p_instance)
{
NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
nrf_rtc_task_trigger(p_instance->p_reg, NRF_RTC_TASK_STOP);
m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_INITIALIZED;
NRFX_LOG_INFO("Disabled.");
}
nrfx_err_t nrfx_rtc_cc_disable(nrfx_rtc_t const * const p_instance, uint32_t channel)
{
NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
NRFX_ASSERT(channel<p_instance->cc_channel_count);
nrfx_err_t err_code;
uint32_t int_mask = RTC_CHANNEL_INT_MASK(channel);
nrf_rtc_event_t event = RTC_CHANNEL_EVENT_ADDR(channel);
nrf_rtc_event_disable(p_instance->p_reg,int_mask);
if (nrf_rtc_int_is_enabled(p_instance->p_reg,int_mask))
{
nrf_rtc_int_disable(p_instance->p_reg,int_mask);
if (nrf_rtc_event_pending(p_instance->p_reg,event))
{
nrf_rtc_event_clear(p_instance->p_reg,event);
err_code = NRFX_ERROR_TIMEOUT;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
}
NRFX_LOG_INFO("RTC id: %d, channel disabled: %lu.", p_instance->instance_id, channel);
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_rtc_cc_set(nrfx_rtc_t const * const p_instance,
uint32_t channel,
uint32_t val,
bool enable_irq)
{
NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
NRFX_ASSERT(channel<p_instance->cc_channel_count);
nrfx_err_t err_code;
uint32_t int_mask = RTC_CHANNEL_INT_MASK(channel);
nrf_rtc_event_t event = RTC_CHANNEL_EVENT_ADDR(channel);
nrf_rtc_event_disable(p_instance->p_reg, int_mask);
nrf_rtc_int_disable(p_instance->p_reg, int_mask);
val = RTC_WRAP(val);
if (m_cb[p_instance->instance_id].reliable)
{
nrf_rtc_cc_set(p_instance->p_reg,channel,val);
uint32_t cnt = nrf_rtc_counter_get(p_instance->p_reg);
int32_t diff = cnt - val;
if (cnt < val)
{
diff += RTC_COUNTER_COUNTER_Msk;
}
if (diff < m_cb[p_instance->instance_id].tick_latency)
{
err_code = NRFX_ERROR_TIMEOUT;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
}
else
{
nrf_rtc_cc_set(p_instance->p_reg,channel,val);
}
if (enable_irq)
{
nrf_rtc_event_clear(p_instance->p_reg,event);
nrf_rtc_int_enable(p_instance->p_reg, int_mask);
}
nrf_rtc_event_enable(p_instance->p_reg,int_mask);
NRFX_LOG_INFO("RTC id: %d, channel enabled: %lu, compare value: %lu.",
p_instance->instance_id,
channel,
val);
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
void nrfx_rtc_tick_enable(nrfx_rtc_t const * const p_instance, bool enable_irq)
{
nrf_rtc_event_t event = NRF_RTC_EVENT_TICK;
uint32_t mask = NRF_RTC_INT_TICK_MASK;
nrf_rtc_event_clear(p_instance->p_reg, event);
nrf_rtc_event_enable(p_instance->p_reg, mask);
if (enable_irq)
{
nrf_rtc_int_enable(p_instance->p_reg, mask);
}
NRFX_LOG_INFO("Tick events enabled.");
}
void nrfx_rtc_tick_disable(nrfx_rtc_t const * const p_instance)
{
uint32_t mask = NRF_RTC_INT_TICK_MASK;
nrf_rtc_event_disable(p_instance->p_reg, mask);
nrf_rtc_int_disable(p_instance->p_reg, mask);
NRFX_LOG_INFO("Tick events disabled.");
}
void nrfx_rtc_overflow_enable(nrfx_rtc_t const * const p_instance, bool enable_irq)
{
nrf_rtc_event_t event = NRF_RTC_EVENT_OVERFLOW;
uint32_t mask = NRF_RTC_INT_OVERFLOW_MASK;
nrf_rtc_event_clear(p_instance->p_reg, event);
nrf_rtc_event_enable(p_instance->p_reg, mask);
if (enable_irq)
{
nrf_rtc_int_enable(p_instance->p_reg, mask);
}
}
void nrfx_rtc_overflow_disable(nrfx_rtc_t const * const p_instance)
{
uint32_t mask = NRF_RTC_INT_OVERFLOW_MASK;
nrf_rtc_event_disable(p_instance->p_reg, mask);
nrf_rtc_int_disable(p_instance->p_reg, mask);
}
uint32_t nrfx_rtc_max_ticks_get(nrfx_rtc_t const * const p_instance)
{
uint32_t ticks;
if (m_cb[p_instance->instance_id].reliable)
{
ticks = RTC_COUNTER_COUNTER_Msk - m_cb[p_instance->instance_id].tick_latency;
}
else
{
ticks = RTC_COUNTER_COUNTER_Msk;
}
return ticks;
}
static void irq_handler(NRF_RTC_Type * p_reg,
uint32_t instance_id,
uint32_t channel_count)
{
uint32_t i;
uint32_t int_mask = (uint32_t)NRF_RTC_INT_COMPARE0_MASK;
nrf_rtc_event_t event = NRF_RTC_EVENT_COMPARE_0;
for (i = 0; i < channel_count; i++)
{
if (nrf_rtc_int_is_enabled(p_reg,int_mask) && nrf_rtc_event_pending(p_reg,event))
{
nrf_rtc_event_disable(p_reg,int_mask);
nrf_rtc_int_disable(p_reg,int_mask);
nrf_rtc_event_clear(p_reg,event);
NRFX_LOG_DEBUG("Event: %s, instance id: %lu.", EVT_TO_STR(event), instance_id);
m_handlers[instance_id]((nrfx_rtc_int_type_t)i);
}
int_mask <<= 1;
event = (nrf_rtc_event_t)((uint32_t)event + sizeof(uint32_t));
}
event = NRF_RTC_EVENT_TICK;
if (nrf_rtc_int_is_enabled(p_reg,NRF_RTC_INT_TICK_MASK) &&
nrf_rtc_event_pending(p_reg, event))
{
nrf_rtc_event_clear(p_reg, event);
NRFX_LOG_DEBUG("Event: %s, instance id: %lu.", EVT_TO_STR(event), instance_id);
m_handlers[instance_id](NRFX_RTC_INT_TICK);
}
event = NRF_RTC_EVENT_OVERFLOW;
if (nrf_rtc_int_is_enabled(p_reg,NRF_RTC_INT_OVERFLOW_MASK) &&
nrf_rtc_event_pending(p_reg, event))
{
nrf_rtc_event_clear(p_reg,event);
NRFX_LOG_DEBUG("Event: %s, instance id: %lu.", EVT_TO_STR(event), instance_id);
m_handlers[instance_id](NRFX_RTC_INT_OVERFLOW);
}
}
#if NRFX_CHECK(NRFX_RTC0_ENABLED)
void nrfx_rtc_0_irq_handler(void)
{
irq_handler(NRF_RTC0, NRFX_RTC0_INST_IDX, NRF_RTC_CC_CHANNEL_COUNT(0));
}
#endif
#if NRFX_CHECK(NRFX_RTC1_ENABLED)
void nrfx_rtc_1_irq_handler(void)
{
irq_handler(NRF_RTC1, NRFX_RTC1_INST_IDX, NRF_RTC_CC_CHANNEL_COUNT(1));
}
#endif
#if NRFX_CHECK(NRFX_RTC2_ENABLED)
void nrfx_rtc_2_irq_handler(void)
{
irq_handler(NRF_RTC2, NRFX_RTC2_INST_IDX, NRF_RTC_CC_CHANNEL_COUNT(2));
}
#endif
#endif // NRFX_CHECK(NRFX_RTC_ENABLED)
File diff suppressed because it is too large Load Diff
+436
View File
@@ -0,0 +1,436 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_SPI_ENABLED)
#if !(NRFX_CHECK(NRFX_SPI0_ENABLED) || NRFX_CHECK(NRFX_SPI1_ENABLED) || \
NRFX_CHECK(NRFX_SPI2_ENABLED))
#error "No enabled SPI instances. Check <nrfx_config.h>."
#endif
#include <nrfx_spi.h>
#include "prs/nrfx_prs.h"
#include <hal/nrf_gpio.h>
#define NRFX_LOG_MODULE SPI
#include <nrfx_log.h>
// Control block - driver instance local data.
typedef struct
{
nrfx_spi_evt_handler_t handler;
void * p_context;
nrfx_spi_evt_t evt; // Keep the struct that is ready for event handler. Less memcpy.
nrfx_drv_state_t state;
volatile bool transfer_in_progress;
// [no need for 'volatile' attribute for the following members, as they
// are not concurrently used in IRQ handlers and main line code]
uint8_t ss_pin;
uint8_t miso_pin;
uint8_t orc;
size_t bytes_transferred;
bool abort;
} spi_control_block_t;
static spi_control_block_t m_cb[NRFX_SPI_ENABLED_COUNT];
nrfx_err_t nrfx_spi_init(nrfx_spi_t const * const p_instance,
nrfx_spi_config_t const * p_config,
nrfx_spi_evt_handler_t handler,
void * p_context)
{
NRFX_ASSERT(p_config);
spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
nrfx_err_t err_code;
if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
{
err_code = NRFX_ERROR_INVALID_STATE;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
#if NRFX_CHECK(NRFX_PRS_ENABLED)
static nrfx_irq_handler_t const irq_handlers[NRFX_SPI_ENABLED_COUNT] = {
#if NRFX_CHECK(NRFX_SPI0_ENABLED)
nrfx_spi_0_irq_handler,
#endif
#if NRFX_CHECK(NRFX_SPI1_ENABLED)
nrfx_spi_1_irq_handler,
#endif
#if NRFX_CHECK(NRFX_SPI2_ENABLED)
nrfx_spi_2_irq_handler,
#endif
};
if (nrfx_prs_acquire(p_instance->p_reg,
irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
{
err_code = NRFX_ERROR_BUSY;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
#endif // NRFX_CHECK(NRFX_PRS_ENABLED)
p_cb->handler = handler;
p_cb->p_context = p_context;
uint32_t mosi_pin;
uint32_t miso_pin;
// Configure pins used by the peripheral:
// - SCK - output with initial value corresponding with the SPI mode used:
// 0 - for modes 0 and 1 (CPOL = 0), 1 - for modes 2 and 3 (CPOL = 1);
// according to the reference manual guidelines this pin and its input
// buffer must always be connected for the SPI to work.
if (p_config->mode <= NRF_SPI_MODE_1)
{
nrf_gpio_pin_clear(p_config->sck_pin);
}
else
{
nrf_gpio_pin_set(p_config->sck_pin);
}
nrf_gpio_cfg(p_config->sck_pin,
NRF_GPIO_PIN_DIR_OUTPUT,
NRF_GPIO_PIN_INPUT_CONNECT,
NRF_GPIO_PIN_NOPULL,
NRF_GPIO_PIN_S0S1,
NRF_GPIO_PIN_NOSENSE);
// - MOSI (optional) - output with initial value 0,
if (p_config->mosi_pin != NRFX_SPI_PIN_NOT_USED)
{
mosi_pin = p_config->mosi_pin;
nrf_gpio_pin_clear(mosi_pin);
nrf_gpio_cfg_output(mosi_pin);
}
else
{
mosi_pin = NRF_SPI_PIN_NOT_CONNECTED;
}
// - MISO (optional) - input,
if (p_config->miso_pin != NRFX_SPI_PIN_NOT_USED)
{
miso_pin = p_config->miso_pin;
nrf_gpio_cfg_input(miso_pin, (nrf_gpio_pin_pull_t)NRFX_SPI_MISO_PULL_CFG);
}
else
{
miso_pin = NRF_SPI_PIN_NOT_CONNECTED;
}
m_cb[p_instance->drv_inst_idx].miso_pin = p_config->miso_pin;
// - Slave Select (optional) - output with initial value 1 (inactive).
if (p_config->ss_pin != NRFX_SPI_PIN_NOT_USED)
{
nrf_gpio_pin_set(p_config->ss_pin);
nrf_gpio_cfg_output(p_config->ss_pin);
}
m_cb[p_instance->drv_inst_idx].ss_pin = p_config->ss_pin;
NRF_SPI_Type * p_spi = p_instance->p_reg;
nrf_spi_pins_set(p_spi, p_config->sck_pin, mosi_pin, miso_pin);
nrf_spi_frequency_set(p_spi, p_config->frequency);
nrf_spi_configure(p_spi, p_config->mode, p_config->bit_order);
m_cb[p_instance->drv_inst_idx].orc = p_config->orc;
nrf_spi_enable(p_spi);
if (p_cb->handler)
{
NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg),
p_config->irq_priority);
NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg));
}
p_cb->transfer_in_progress = false;
p_cb->state = NRFX_DRV_STATE_INITIALIZED;
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
void nrfx_spi_uninit(nrfx_spi_t const * const p_instance)
{
spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
if (p_cb->handler)
{
NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg));
}
NRF_SPI_Type * p_spi = p_instance->p_reg;
if (p_cb->handler)
{
nrf_spi_int_disable(p_spi, NRF_SPI_ALL_INTS_MASK);
}
if (p_cb->miso_pin != NRFX_SPI_PIN_NOT_USED)
{
nrf_gpio_cfg_default(p_cb->miso_pin);
}
nrf_spi_disable(p_spi);
#if NRFX_CHECK(NRFX_PRS_ENABLED)
nrfx_prs_release(p_instance->p_reg);
#endif
p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
}
static void finish_transfer(spi_control_block_t * p_cb)
{
// If Slave Select signal is used, this is the time to deactivate it.
if (p_cb->ss_pin != NRFX_SPI_PIN_NOT_USED)
{
nrf_gpio_pin_set(p_cb->ss_pin);
}
// By clearing this flag before calling the handler we allow subsequent
// transfers to be started directly from the handler function.
p_cb->transfer_in_progress = false;
p_cb->evt.type = NRFX_SPI_EVENT_DONE;
p_cb->handler(&p_cb->evt, p_cb->p_context);
}
// This function is called from the IRQ handler or, in blocking mode, directly
// from the 'spi_xfer' function.
// It returns true as long as the transfer should be continued, otherwise (when
// there is nothing more to send/receive) it returns false.
static bool transfer_byte(NRF_SPI_Type * p_spi, spi_control_block_t * p_cb)
{
// Read the data byte received in this transfer (always, because no further
// READY event can be generated until the current byte is read out from the
// RXD register), and store it in the RX buffer (only when needed).
volatile uint8_t rx_data = nrf_spi_rxd_get(p_spi);
if (p_cb->bytes_transferred < p_cb->evt.xfer_desc.rx_length)
{
p_cb->evt.xfer_desc.p_rx_buffer[p_cb->bytes_transferred] = rx_data;
}
++p_cb->bytes_transferred;
// Check if there are more bytes to send or receive and write proper data
// byte (next one from TX buffer or over-run character) to the TXD register
// when needed.
// NOTE - we've already used 'p_cb->bytes_transferred + 1' bytes from our
// buffers, because we take advantage of double buffering of TXD
// register (so in effect one byte is still being transmitted now);
// see how the transfer is started in the 'spi_xfer' function.
size_t bytes_used = p_cb->bytes_transferred + 1;
if (p_cb->abort)
{
if (bytes_used < p_cb->evt.xfer_desc.tx_length)
{
p_cb->evt.xfer_desc.tx_length = bytes_used;
}
if (bytes_used < p_cb->evt.xfer_desc.rx_length)
{
p_cb->evt.xfer_desc.rx_length = bytes_used;
}
}
if (bytes_used < p_cb->evt.xfer_desc.tx_length)
{
nrf_spi_txd_set(p_spi, p_cb->evt.xfer_desc.p_tx_buffer[bytes_used]);
return true;
}
else if (bytes_used < p_cb->evt.xfer_desc.rx_length)
{
nrf_spi_txd_set(p_spi, p_cb->orc);
return true;
}
return (p_cb->bytes_transferred < p_cb->evt.xfer_desc.tx_length ||
p_cb->bytes_transferred < p_cb->evt.xfer_desc.rx_length);
}
static void spi_xfer(NRF_SPI_Type * p_spi,
spi_control_block_t * p_cb,
nrfx_spi_xfer_desc_t const * p_xfer_desc)
{
p_cb->bytes_transferred = 0;
nrf_spi_int_disable(p_spi, NRF_SPI_INT_READY_MASK);
nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY);
// Start the transfer by writing some byte to the TXD register;
// if TX buffer is not empty, take the first byte from this buffer,
// otherwise - use over-run character.
nrf_spi_txd_set(p_spi,
(p_xfer_desc->tx_length > 0 ? p_xfer_desc->p_tx_buffer[0] : p_cb->orc));
// TXD register is double buffered, so next byte to be transmitted can
// be written immediately, if needed, i.e. if TX or RX transfer is to
// be more that 1 byte long. Again - if there is something more in TX
// buffer send it, otherwise use over-run character.
if (p_xfer_desc->tx_length > 1)
{
nrf_spi_txd_set(p_spi, p_xfer_desc->p_tx_buffer[1]);
}
else if (p_xfer_desc->rx_length > 1)
{
nrf_spi_txd_set(p_spi, p_cb->orc);
}
// For blocking mode (user handler not provided) wait here for READY
// events (indicating that the byte from TXD register was transmitted
// and a new incoming byte was moved to the RXD register) and continue
// transaction until all requested bytes are transferred.
// In non-blocking mode - IRQ service routine will do this stuff.
if (p_cb->handler)
{
nrf_spi_int_enable(p_spi, NRF_SPI_INT_READY_MASK);
}
else
{
do {
while (!nrf_spi_event_check(p_spi, NRF_SPI_EVENT_READY)) {}
nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY);
NRFX_LOG_DEBUG("SPI: Event: NRF_SPI_EVENT_READY.");
} while (transfer_byte(p_spi, p_cb));
if (p_cb->ss_pin != NRFX_SPI_PIN_NOT_USED)
{
nrf_gpio_pin_set(p_cb->ss_pin);
}
}
}
nrfx_err_t nrfx_spi_xfer(nrfx_spi_t const * const p_instance,
nrfx_spi_xfer_desc_t const * p_xfer_desc,
uint32_t flags)
{
spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
NRFX_ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0);
NRFX_ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0);
nrfx_err_t err_code = NRFX_SUCCESS;
if (p_cb->transfer_in_progress)
{
err_code = NRFX_ERROR_BUSY;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
else
{
if (p_cb->handler)
{
p_cb->transfer_in_progress = true;
}
}
p_cb->evt.xfer_desc = *p_xfer_desc;
p_cb->abort = false;
if (p_cb->ss_pin != NRFX_SPI_PIN_NOT_USED)
{
nrf_gpio_pin_clear(p_cb->ss_pin);
}
if (flags)
{
p_cb->transfer_in_progress = false;
err_code = NRFX_ERROR_NOT_SUPPORTED;
}
else
{
spi_xfer(p_instance->p_reg, p_cb, p_xfer_desc);
}
NRFX_LOG_INFO("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
void nrfx_spi_abort(nrfx_spi_t const * p_instance)
{
spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
p_cb->abort = true;
}
static void irq_handler(NRF_SPI_Type * p_spi, spi_control_block_t * p_cb)
{
NRFX_ASSERT(p_cb->handler);
nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY);
NRFX_LOG_DEBUG("Event: NRF_SPI_EVENT_READY.");
if (!transfer_byte(p_spi, p_cb))
{
finish_transfer(p_cb);
}
}
#if NRFX_CHECK(NRFX_SPI0_ENABLED)
void nrfx_spi_0_irq_handler(void)
{
irq_handler(NRF_SPI0, &m_cb[NRFX_SPI0_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_SPI1_ENABLED)
void nrfx_spi_1_irq_handler(void)
{
irq_handler(NRF_SPI1, &m_cb[NRFX_SPI1_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_SPI2_ENABLED)
void nrfx_spi_2_irq_handler(void)
{
irq_handler(NRF_SPI2, &m_cb[NRFX_SPI2_INST_IDX]);
}
#endif
#endif // NRFX_CHECK(NRFX_SPI_ENABLED)
+697
View File
@@ -0,0 +1,697 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_SPIM_ENABLED)
#if !(NRFX_CHECK(NRFX_SPIM0_ENABLED) || NRFX_CHECK(NRFX_SPIM1_ENABLED) || \
NRFX_CHECK(NRFX_SPIM2_ENABLED) || NRFX_CHECK(NRFX_SPIM3_ENABLED))
#error "No enabled SPIM instances. Check <nrfx_config.h>."
#endif
#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) && !NRFX_CHECK(NRFX_SPIM3_ENABLED)
#error "Extended options are available only in SPIM3 on the nRF52840 SoC."
#endif
#include <nrfx_spim.h>
#include "prs/nrfx_prs.h"
#include <hal/nrf_gpio.h>
#define NRFX_LOG_MODULE SPIM
#include <nrfx_log.h>
#define SPIMX_LENGTH_VALIDATE(peripheral, drv_inst_idx, rx_len, tx_len) \
(((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \
NRFX_EASYDMA_LENGTH_VALIDATE(peripheral, rx_len, tx_len))
#if NRFX_CHECK(NRFX_SPIM0_ENABLED)
#define SPIM0_LENGTH_VALIDATE(...) SPIMX_LENGTH_VALIDATE(SPIM0, __VA_ARGS__)
#else
#define SPIM0_LENGTH_VALIDATE(...) 0
#endif
#if NRFX_CHECK(NRFX_SPIM1_ENABLED)
#define SPIM1_LENGTH_VALIDATE(...) SPIMX_LENGTH_VALIDATE(SPIM1, __VA_ARGS__)
#else
#define SPIM1_LENGTH_VALIDATE(...) 0
#endif
#if NRFX_CHECK(NRFX_SPIM2_ENABLED)
#define SPIM2_LENGTH_VALIDATE(...) SPIMX_LENGTH_VALIDATE(SPIM2, __VA_ARGS__)
#else
#define SPIM2_LENGTH_VALIDATE(...) 0
#endif
#if NRFX_CHECK(NRFX_SPIM3_ENABLED)
#define SPIM3_LENGTH_VALIDATE(...) SPIMX_LENGTH_VALIDATE(SPIM3, __VA_ARGS__)
#else
#define SPIM3_LENGTH_VALIDATE(...) 0
#endif
#define SPIM_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) \
(SPIM0_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \
SPIM1_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \
SPIM2_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \
SPIM3_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len))
#if defined(NRF52840_XXAA) && (NRFX_CHECK(NRFX_SPIM3_ENABLED))
// Enable workaround for nRF52840 anomaly 195 (SPIM3 continues to draw current after disable).
#define USE_WORKAROUND_FOR_ANOMALY_195
#endif
// Control block - driver instance local data.
typedef struct
{
nrfx_spim_evt_handler_t handler;
void * p_context;
nrfx_spim_evt_t evt; // Keep the struct that is ready for event handler. Less memcpy.
nrfx_drv_state_t state;
volatile bool transfer_in_progress;
#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
bool use_hw_ss;
#endif
// [no need for 'volatile' attribute for the following members, as they
// are not concurrently used in IRQ handlers and main line code]
bool ss_active_high;
uint8_t ss_pin;
uint8_t miso_pin;
uint8_t orc;
#if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
size_t tx_length;
size_t rx_length;
#endif
} spim_control_block_t;
static spim_control_block_t m_cb[NRFX_SPIM_ENABLED_COUNT];
#if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
// Workaround for nRF52840 anomaly 198: SPIM3 transmit data might be corrupted.
static uint32_t m_anomaly_198_preserved_value;
static void anomaly_198_enable(uint8_t const * p_buffer, size_t buf_len)
{
m_anomaly_198_preserved_value = *((volatile uint32_t *)0x40000E00);
if (buf_len == 0)
{
return;
}
uint32_t buffer_end_addr = ((uint32_t)p_buffer) + buf_len;
uint32_t block_addr = ((uint32_t)p_buffer) & ~0x1FFF;
uint32_t block_flag = (1UL << ((block_addr >> 13) & 0xFFFF));
uint32_t occupied_blocks = 0;
if (block_addr >= 0x20010000)
{
occupied_blocks = (1UL << 8);
}
else
{
do {
occupied_blocks |= block_flag;
block_flag <<= 1;
block_addr += 0x2000;
} while ((block_addr < buffer_end_addr) && (block_addr < 0x20012000));
}
*((volatile uint32_t *)0x40000E00) = occupied_blocks;
}
static void anomaly_198_disable(void)
{
*((volatile uint32_t *)0x40000E00) = m_anomaly_198_preserved_value;
}
#endif // NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
nrfx_err_t nrfx_spim_init(nrfx_spim_t const * const p_instance,
nrfx_spim_config_t const * p_config,
nrfx_spim_evt_handler_t handler,
void * p_context)
{
NRFX_ASSERT(p_config);
spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
nrfx_err_t err_code;
if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
{
err_code = NRFX_ERROR_INVALID_STATE;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
// Currently, only SPIM3 in nRF52840 supports the extended features.
// Other instances must be checked.
if ((p_instance->drv_inst_idx != NRFX_SPIM3_INST_IDX) &&
((p_config->dcx_pin != NRFX_SPIM_PIN_NOT_USED) ||
(p_config->frequency == NRF_SPIM_FREQ_16M) ||
(p_config->frequency == NRF_SPIM_FREQ_32M) ||
(p_config->use_hw_ss)))
{
err_code = NRFX_ERROR_NOT_SUPPORTED;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
#endif
NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg;
#if NRFX_CHECK(NRFX_PRS_ENABLED)
static nrfx_irq_handler_t const irq_handlers[NRFX_SPIM_ENABLED_COUNT] = {
#if NRFX_CHECK(NRFX_SPIM0_ENABLED)
nrfx_spim_0_irq_handler,
#endif
#if NRFX_CHECK(NRFX_SPIM1_ENABLED)
nrfx_spim_1_irq_handler,
#endif
#if NRFX_CHECK(NRFX_SPIM2_ENABLED)
nrfx_spim_2_irq_handler,
#endif
#if NRFX_CHECK(NRFX_SPIM3_ENABLED)
nrfx_spim_3_irq_handler,
#endif
};
if (nrfx_prs_acquire(p_instance->p_reg,
irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
{
err_code = NRFX_ERROR_BUSY;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
#endif // NRFX_CHECK(NRFX_PRS_ENABLED)
p_cb->handler = handler;
p_cb->p_context = p_context;
uint32_t mosi_pin;
uint32_t miso_pin;
// Configure pins used by the peripheral:
// - SCK - output with initial value corresponding with the SPI mode used:
// 0 - for modes 0 and 1 (CPOL = 0), 1 - for modes 2 and 3 (CPOL = 1);
// according to the reference manual guidelines this pin and its input
// buffer must always be connected for the SPI to work.
if (p_config->mode <= NRF_SPIM_MODE_1)
{
nrf_gpio_pin_clear(p_config->sck_pin);
}
else
{
nrf_gpio_pin_set(p_config->sck_pin);
}
nrf_gpio_cfg(p_config->sck_pin,
NRF_GPIO_PIN_DIR_OUTPUT,
NRF_GPIO_PIN_INPUT_CONNECT,
NRF_GPIO_PIN_NOPULL,
NRF_GPIO_PIN_S0S1,
NRF_GPIO_PIN_NOSENSE);
// - MOSI (optional) - output with initial value 0,
if (p_config->mosi_pin != NRFX_SPIM_PIN_NOT_USED)
{
mosi_pin = p_config->mosi_pin;
nrf_gpio_pin_clear(mosi_pin);
nrf_gpio_cfg_output(mosi_pin);
}
else
{
mosi_pin = NRF_SPIM_PIN_NOT_CONNECTED;
}
// - MISO (optional) - input,
if (p_config->miso_pin != NRFX_SPIM_PIN_NOT_USED)
{
miso_pin = p_config->miso_pin;
nrf_gpio_cfg_input(miso_pin, (nrf_gpio_pin_pull_t)NRFX_SPIM_MISO_PULL_CFG);
}
else
{
miso_pin = NRF_SPIM_PIN_NOT_CONNECTED;
}
p_cb->miso_pin = p_config->miso_pin;
// - Slave Select (optional) - output with initial value 1 (inactive).
// 'p_cb->ss_pin' variable is used during transfers to check if SS pin should be toggled,
// so this field needs to be initialized even if the pin is not used.
p_cb->ss_pin = p_config->ss_pin;
if (p_config->ss_pin != NRFX_SPIM_PIN_NOT_USED)
{
if (p_config->ss_active_high)
{
nrf_gpio_pin_clear(p_config->ss_pin);
}
else
{
nrf_gpio_pin_set(p_config->ss_pin);
}
nrf_gpio_cfg_output(p_config->ss_pin);
#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
if (p_config->use_hw_ss)
{
p_cb->use_hw_ss = p_config->use_hw_ss;
nrf_spim_csn_configure(p_spim,
p_config->ss_pin,
(p_config->ss_active_high == true ?
NRF_SPIM_CSN_POL_HIGH : NRF_SPIM_CSN_POL_LOW),
p_config->ss_duration);
}
#endif
p_cb->ss_active_high = p_config->ss_active_high;
}
#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
// - DCX (optional) - output.
if (p_config->dcx_pin != NRFX_SPIM_PIN_NOT_USED)
{
nrf_gpio_pin_set(p_config->dcx_pin);
nrf_gpio_cfg_output(p_config->dcx_pin);
nrf_spim_dcx_pin_set(p_spim, p_config->dcx_pin);
}
// Change rx delay
nrf_spim_iftiming_set(p_spim, p_config->rx_delay);
#endif
nrf_spim_pins_set(p_spim, p_config->sck_pin, mosi_pin, miso_pin);
nrf_spim_frequency_set(p_spim, p_config->frequency);
nrf_spim_configure(p_spim, p_config->mode, p_config->bit_order);
nrf_spim_orc_set(p_spim, p_config->orc);
nrf_spim_enable(p_spim);
if (p_cb->handler)
{
NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg),
p_config->irq_priority);
NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg));
}
p_cb->transfer_in_progress = false;
p_cb->state = NRFX_DRV_STATE_INITIALIZED;
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
void nrfx_spim_uninit(nrfx_spim_t const * const p_instance)
{
spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
if (p_cb->handler)
{
NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg));
}
NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg;
if (p_cb->handler)
{
nrf_spim_int_disable(p_spim, NRF_SPIM_ALL_INTS_MASK);
if (p_cb->transfer_in_progress)
{
// Ensure that SPI is not performing any transfer.
nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_STOP);
while (!nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_STOPPED))
{}
p_cb->transfer_in_progress = false;
}
}
if (p_cb->miso_pin != NRFX_SPIM_PIN_NOT_USED)
{
nrf_gpio_cfg_default(p_cb->miso_pin);
}
nrf_spim_disable(p_spim);
#ifdef USE_WORKAROUND_FOR_ANOMALY_195
if (p_spim == NRF_SPIM3)
{
*(volatile uint32_t *)0x4002F004 = 1;
}
#endif
#if NRFX_CHECK(NRFX_PRS_ENABLED)
nrfx_prs_release(p_instance->p_reg);
#endif
p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
}
#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
nrfx_err_t nrfx_spim_xfer_dcx(nrfx_spim_t const * const p_instance,
nrfx_spim_xfer_desc_t const * p_xfer_desc,
uint32_t flags,
uint8_t cmd_length)
{
NRFX_ASSERT(cmd_length <= NRF_SPIM_DCX_CNT_ALL_CMD);
nrf_spim_dcx_cnt_set((NRF_SPIM_Type *)p_instance->p_reg, cmd_length);
return nrfx_spim_xfer(p_instance, p_xfer_desc, 0);
}
#endif
static void finish_transfer(spim_control_block_t * p_cb)
{
// If Slave Select signal is used, this is the time to deactivate it.
if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
{
#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
if (!p_cb->use_hw_ss)
#endif
{
if (p_cb->ss_active_high)
{
nrf_gpio_pin_clear(p_cb->ss_pin);
}
else
{
nrf_gpio_pin_set(p_cb->ss_pin);
}
}
}
// By clearing this flag before calling the handler we allow subsequent
// transfers to be started directly from the handler function.
p_cb->transfer_in_progress = false;
p_cb->evt.type = NRFX_SPIM_EVENT_DONE;
p_cb->handler(&p_cb->evt, p_cb->p_context);
}
__STATIC_INLINE void spim_int_enable(NRF_SPIM_Type * p_spim, bool enable)
{
if (!enable)
{
nrf_spim_int_disable(p_spim, NRF_SPIM_INT_END_MASK);
}
else
{
nrf_spim_int_enable(p_spim, NRF_SPIM_INT_END_MASK);
}
}
__STATIC_INLINE void spim_list_enable_handle(NRF_SPIM_Type * p_spim, uint32_t flags)
{
if (NRFX_SPIM_FLAG_TX_POSTINC & flags)
{
nrf_spim_tx_list_enable(p_spim);
}
else
{
nrf_spim_tx_list_disable(p_spim);
}
if (NRFX_SPIM_FLAG_RX_POSTINC & flags)
{
nrf_spim_rx_list_enable(p_spim);
}
else
{
nrf_spim_rx_list_disable(p_spim);
}
}
static nrfx_err_t spim_xfer(NRF_SPIM_Type * p_spim,
spim_control_block_t * p_cb,
nrfx_spim_xfer_desc_t const * p_xfer_desc,
uint32_t flags)
{
nrfx_err_t err_code;
// EasyDMA requires that transfer buffers are placed in Data RAM region;
// signal error if they are not.
if ((p_xfer_desc->p_tx_buffer != NULL && !nrfx_is_in_ram(p_xfer_desc->p_tx_buffer)) ||
(p_xfer_desc->p_rx_buffer != NULL && !nrfx_is_in_ram(p_xfer_desc->p_rx_buffer)))
{
p_cb->transfer_in_progress = false;
err_code = NRFX_ERROR_INVALID_ADDR;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
#if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
p_cb->tx_length = 0;
p_cb->rx_length = 0;
#endif
nrf_spim_tx_buffer_set(p_spim, p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length);
nrf_spim_rx_buffer_set(p_spim, p_xfer_desc->p_rx_buffer, p_xfer_desc->rx_length);
#if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
if (p_spim == NRF_SPIM3)
{
anomaly_198_enable(p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length);
}
#endif
nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
spim_list_enable_handle(p_spim, flags);
if (!(flags & NRFX_SPIM_FLAG_HOLD_XFER))
{
nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_START);
}
#if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
if (flags & NRFX_SPIM_FLAG_HOLD_XFER)
{
nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
p_cb->tx_length = p_xfer_desc->tx_length;
p_cb->rx_length = p_xfer_desc->rx_length;
nrf_spim_tx_buffer_set(p_spim, p_xfer_desc->p_tx_buffer, 0);
nrf_spim_rx_buffer_set(p_spim, p_xfer_desc->p_rx_buffer, 0);
nrf_spim_int_enable(p_spim, NRF_SPIM_INT_STARTED_MASK);
}
#endif
if (!p_cb->handler)
{
while (!nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END)){}
#if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
if (p_spim == NRF_SPIM3)
{
anomaly_198_disable();
}
#endif
if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
{
#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
if (!p_cb->use_hw_ss)
#endif
{
if (p_cb->ss_active_high)
{
nrf_gpio_pin_clear(p_cb->ss_pin);
}
else
{
nrf_gpio_pin_set(p_cb->ss_pin);
}
}
}
}
else
{
spim_int_enable(p_spim, !(flags & NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER));
}
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_spim_xfer(nrfx_spim_t const * const p_instance,
nrfx_spim_xfer_desc_t const * p_xfer_desc,
uint32_t flags)
{
spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
NRFX_ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0);
NRFX_ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0);
NRFX_ASSERT(SPIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
p_xfer_desc->rx_length,
p_xfer_desc->tx_length));
nrfx_err_t err_code = NRFX_SUCCESS;
if (p_cb->transfer_in_progress)
{
err_code = NRFX_ERROR_BUSY;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
else
{
if (p_cb->handler && !(flags & (NRFX_SPIM_FLAG_REPEATED_XFER |
NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER)))
{
p_cb->transfer_in_progress = true;
}
}
p_cb->evt.xfer_desc = *p_xfer_desc;
if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
{
#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
if (!p_cb->use_hw_ss)
#endif
{
if (p_cb->ss_active_high)
{
nrf_gpio_pin_set(p_cb->ss_pin);
}
else
{
nrf_gpio_pin_clear(p_cb->ss_pin);
}
}
}
return spim_xfer(p_instance->p_reg, p_cb, p_xfer_desc, flags);
}
void nrfx_spim_abort(nrfx_spim_t const * p_instance)
{
spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
nrf_spim_task_trigger(p_instance->p_reg, NRF_SPIM_TASK_STOP);
while (!nrf_spim_event_check(p_instance->p_reg, NRF_SPIM_EVENT_STOPPED))
{}
p_cb->transfer_in_progress = false;
}
uint32_t nrfx_spim_start_task_get(nrfx_spim_t const * p_instance)
{
NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg;
return nrf_spim_task_address_get(p_spim, NRF_SPIM_TASK_START);
}
uint32_t nrfx_spim_end_event_get(nrfx_spim_t const * p_instance)
{
NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg;
return nrf_spim_event_address_get(p_spim, NRF_SPIM_EVENT_END);
}
static void irq_handler(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
{
#if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
if ((nrf_spim_int_enable_check(p_spim, NRF_SPIM_INT_STARTED_MASK)) &&
(nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_STARTED)) )
{
/* Handle first, zero-length, auxiliary transmission. */
nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
NRFX_ASSERT(p_spim->TXD.MAXCNT == 0);
p_spim->TXD.MAXCNT = p_cb->tx_length;
NRFX_ASSERT(p_spim->RXD.MAXCNT == 0);
p_spim->RXD.MAXCNT = p_cb->rx_length;
/* Disable STARTED interrupt, used only in auxiliary transmission. */
nrf_spim_int_disable(p_spim, NRF_SPIM_INT_STARTED_MASK);
/* Start the actual, glitch-free transmission. */
nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_START);
return;
}
#endif
if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END))
{
#if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
if (p_spim == NRF_SPIM3)
{
anomaly_198_disable();
}
#endif
nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
NRFX_ASSERT(p_cb->handler);
NRFX_LOG_DEBUG("Event: NRF_SPIM_EVENT_END.");
finish_transfer(p_cb);
}
}
#if NRFX_CHECK(NRFX_SPIM0_ENABLED)
void nrfx_spim_0_irq_handler(void)
{
irq_handler(NRF_SPIM0, &m_cb[NRFX_SPIM0_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_SPIM1_ENABLED)
void nrfx_spim_1_irq_handler(void)
{
irq_handler(NRF_SPIM1, &m_cb[NRFX_SPIM1_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_SPIM2_ENABLED)
void nrfx_spim_2_irq_handler(void)
{
irq_handler(NRF_SPIM2, &m_cb[NRFX_SPIM2_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_SPIM3_ENABLED)
void nrfx_spim_3_irq_handler(void)
{
irq_handler(NRF_SPIM3, &m_cb[NRFX_SPIM3_INST_IDX]);
}
#endif
#endif // NRFX_CHECK(NRFX_SPIM_ENABLED)
+330
View File
@@ -0,0 +1,330 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_TIMER_ENABLED)
#if !(NRFX_CHECK(NRFX_TIMER0_ENABLED) || NRFX_CHECK(NRFX_TIMER1_ENABLED) || \
NRFX_CHECK(NRFX_TIMER2_ENABLED) || NRFX_CHECK(NRFX_TIMER3_ENABLED) || \
NRFX_CHECK(NRFX_TIMER4_ENABLED))
#error "No enabled TIMER instances. Check <nrfx_config.h>."
#endif
#include <nrfx_timer.h>
#define NRFX_LOG_MODULE TIMER
#include <nrfx_log.h>
/**@brief Timer control block. */
typedef struct
{
nrfx_timer_event_handler_t handler;
void * context;
nrfx_drv_state_t state;
} timer_control_block_t;
static timer_control_block_t m_cb[NRFX_TIMER_ENABLED_COUNT];
nrfx_err_t nrfx_timer_init(nrfx_timer_t const * const p_instance,
nrfx_timer_config_t const * p_config,
nrfx_timer_event_handler_t timer_event_handler)
{
timer_control_block_t * p_cb = &m_cb[p_instance->instance_id];
#ifdef SOFTDEVICE_PRESENT
NRFX_ASSERT(p_instance->p_reg != NRF_TIMER0);
#endif
NRFX_ASSERT(p_config);
NRFX_ASSERT(timer_event_handler);
nrfx_err_t err_code;
if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
{
err_code = NRFX_ERROR_INVALID_STATE;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
/* Warning 685: Relational operator '<=' always evaluates to 'true'"
* Warning in NRF_TIMER_IS_BIT_WIDTH_VALID macro. Macro validate timers resolution.
* Not necessary in nRF52 based systems. Obligatory in nRF51 based systems.
*/
/*lint -save -e685 */
NRFX_ASSERT(NRF_TIMER_IS_BIT_WIDTH_VALID(p_instance->p_reg, p_config->bit_width));
//lint -restore
p_cb->handler = timer_event_handler;
p_cb->context = p_config->p_context;
uint8_t i;
for (i = 0; i < p_instance->cc_channel_count; ++i)
{
nrf_timer_event_clear(p_instance->p_reg,
nrf_timer_compare_event_get(i));
}
NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg),
p_config->interrupt_priority);
NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg));
nrf_timer_mode_set(p_instance->p_reg, p_config->mode);
nrf_timer_bit_width_set(p_instance->p_reg, p_config->bit_width);
nrf_timer_frequency_set(p_instance->p_reg, p_config->frequency);
p_cb->state = NRFX_DRV_STATE_INITIALIZED;
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
void nrfx_timer_uninit(nrfx_timer_t const * const p_instance)
{
NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg));
#define DISABLE_ALL UINT32_MAX
nrf_timer_shorts_disable(p_instance->p_reg, DISABLE_ALL);
nrf_timer_int_disable(p_instance->p_reg, DISABLE_ALL);
#undef DISABLE_ALL
nrfx_timer_disable(p_instance);
m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_UNINITIALIZED;
NRFX_LOG_INFO("Uninitialized instance: %d.", p_instance->instance_id);
}
void nrfx_timer_enable(nrfx_timer_t const * const p_instance)
{
NRFX_ASSERT(m_cb[p_instance->instance_id].state == NRFX_DRV_STATE_INITIALIZED);
nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_START);
m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_POWERED_ON;
NRFX_LOG_INFO("Enabled instance: %d.", p_instance->instance_id);
}
void nrfx_timer_disable(nrfx_timer_t const * const p_instance)
{
NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_SHUTDOWN);
m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_INITIALIZED;
NRFX_LOG_INFO("Disabled instance: %d.", p_instance->instance_id);
}
bool nrfx_timer_is_enabled(nrfx_timer_t const * const p_instance)
{
NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
return (m_cb[p_instance->instance_id].state == NRFX_DRV_STATE_POWERED_ON);
}
void nrfx_timer_resume(nrfx_timer_t const * const p_instance)
{
NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_START);
NRFX_LOG_INFO("Resumed instance: %d.", p_instance->instance_id);
}
void nrfx_timer_pause(nrfx_timer_t const * const p_instance)
{
NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_STOP);
NRFX_LOG_INFO("Paused instance: %d.", p_instance->instance_id);
}
void nrfx_timer_clear(nrfx_timer_t const * const p_instance)
{
NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_CLEAR);
}
void nrfx_timer_increment(nrfx_timer_t const * const p_instance)
{
NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
NRFX_ASSERT(nrf_timer_mode_get(p_instance->p_reg) != NRF_TIMER_MODE_TIMER);
nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_COUNT);
}
uint32_t nrfx_timer_capture(nrfx_timer_t const * const p_instance,
nrf_timer_cc_channel_t cc_channel)
{
NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
NRFX_ASSERT(cc_channel < p_instance->cc_channel_count);
nrf_timer_task_trigger(p_instance->p_reg,
nrf_timer_capture_task_get(cc_channel));
return nrf_timer_cc_read(p_instance->p_reg, cc_channel);
}
void nrfx_timer_compare(nrfx_timer_t const * const p_instance,
nrf_timer_cc_channel_t cc_channel,
uint32_t cc_value,
bool enable_int)
{
nrf_timer_int_mask_t timer_int = nrf_timer_compare_int_get(cc_channel);
if (enable_int)
{
nrf_timer_event_clear(p_instance->p_reg, nrf_timer_compare_event_get(cc_channel));
nrf_timer_int_enable(p_instance->p_reg, timer_int);
}
else
{
nrf_timer_int_disable(p_instance->p_reg, timer_int);
}
nrf_timer_cc_write(p_instance->p_reg, cc_channel, cc_value);
NRFX_LOG_INFO("Timer id: %d, capture value set: %lu, channel: %d.",
p_instance->instance_id,
cc_value,
cc_channel);
}
void nrfx_timer_extended_compare(nrfx_timer_t const * const p_instance,
nrf_timer_cc_channel_t cc_channel,
uint32_t cc_value,
nrf_timer_short_mask_t timer_short_mask,
bool enable_int)
{
nrf_timer_shorts_disable(p_instance->p_reg,
(TIMER_SHORTS_COMPARE0_STOP_Msk << cc_channel) |
(TIMER_SHORTS_COMPARE0_CLEAR_Msk << cc_channel));
nrf_timer_shorts_enable(p_instance->p_reg, timer_short_mask);
nrfx_timer_compare(p_instance,
cc_channel,
cc_value,
enable_int);
NRFX_LOG_INFO("Timer id: %d, capture value set: %lu, channel: %d.",
p_instance->instance_id,
cc_value,
cc_channel);
}
void nrfx_timer_compare_int_enable(nrfx_timer_t const * const p_instance,
uint32_t channel)
{
NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
NRFX_ASSERT(channel < p_instance->cc_channel_count);
nrf_timer_event_clear(p_instance->p_reg,
nrf_timer_compare_event_get(channel));
nrf_timer_int_enable(p_instance->p_reg,
nrf_timer_compare_int_get(channel));
}
void nrfx_timer_compare_int_disable(nrfx_timer_t const * const p_instance,
uint32_t channel)
{
NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
NRFX_ASSERT(channel < p_instance->cc_channel_count);
nrf_timer_int_disable(p_instance->p_reg,
nrf_timer_compare_int_get(channel));
}
static void irq_handler(NRF_TIMER_Type * p_reg,
timer_control_block_t * p_cb,
uint8_t channel_count)
{
uint8_t i;
for (i = 0; i < channel_count; ++i)
{
nrf_timer_event_t event = nrf_timer_compare_event_get(i);
nrf_timer_int_mask_t int_mask = nrf_timer_compare_int_get(i);
if (nrf_timer_event_check(p_reg, event) &&
nrf_timer_int_enable_check(p_reg, int_mask))
{
nrf_timer_event_clear(p_reg, event);
NRFX_LOG_DEBUG("Compare event, channel: %d.", i);
p_cb->handler(event, p_cb->context);
}
}
}
#if NRFX_CHECK(NRFX_TIMER0_ENABLED)
void nrfx_timer_0_irq_handler(void)
{
irq_handler(NRF_TIMER0, &m_cb[NRFX_TIMER0_INST_IDX],
NRF_TIMER_CC_CHANNEL_COUNT(0));
}
#endif
#if NRFX_CHECK(NRFX_TIMER1_ENABLED)
void nrfx_timer_1_irq_handler(void)
{
irq_handler(NRF_TIMER1, &m_cb[NRFX_TIMER1_INST_IDX],
NRF_TIMER_CC_CHANNEL_COUNT(1));
}
#endif
#if NRFX_CHECK(NRFX_TIMER2_ENABLED)
void nrfx_timer_2_irq_handler(void)
{
irq_handler(NRF_TIMER2, &m_cb[NRFX_TIMER2_INST_IDX],
NRF_TIMER_CC_CHANNEL_COUNT(2));
}
#endif
#if NRFX_CHECK(NRFX_TIMER3_ENABLED)
void nrfx_timer_3_irq_handler(void)
{
irq_handler(NRF_TIMER3, &m_cb[NRFX_TIMER3_INST_IDX],
NRF_TIMER_CC_CHANNEL_COUNT(3));
}
#endif
#if NRFX_CHECK(NRFX_TIMER4_ENABLED)
void nrfx_timer_4_irq_handler(void)
{
irq_handler(NRF_TIMER4, &m_cb[NRFX_TIMER4_INST_IDX],
NRF_TIMER_CC_CHANNEL_COUNT(4));
}
#endif
#endif // NRFX_CHECK(NRFX_TIMER_ENABLED)
+783
View File
@@ -0,0 +1,783 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_TWI_ENABLED)
#if !(NRFX_CHECK(NRFX_TWI0_ENABLED) || NRFX_CHECK(NRFX_TWI1_ENABLED))
#error "No enabled TWI instances. Check <nrfx_config.h>."
#endif
#include <nrfx_twi.h>
#include <hal/nrf_gpio.h>
#include "prs/nrfx_prs.h"
#define NRFX_LOG_MODULE TWI
#include <nrfx_log.h>
#define EVT_TO_STR(event) \
(event == NRFX_TWI_EVT_DONE ? "EVT_DONE" : \
(event == NRFX_TWI_EVT_ADDRESS_NACK ? "EVT_ADDRESS_NACK" : \
(event == NRFX_TWI_EVT_DATA_NACK ? "EVT_DATA_NACK" : \
(event == NRFX_TWI_EVT_OVERRUN ? "EVT_OVERRUN" : \
(event == NRFX_TWI_EVT_BUS_ERROR ? "EVT_BUS_ERROR" : \
"UNKNOWN ERROR")))))
#define EVT_TO_STR_TWI(event) \
(event == NRF_TWI_EVENT_STOPPED ? "NRF_TWI_EVENT_STOPPED" : \
(event == NRF_TWI_EVENT_RXDREADY ? "NRF_TWI_EVENT_RXDREADY" : \
(event == NRF_TWI_EVENT_TXDSENT ? "NRF_TWI_EVENT_TXDSENT" : \
(event == NRF_TWI_EVENT_ERROR ? "NRF_TWI_EVENT_ERROR" : \
(event == NRF_TWI_EVENT_BB ? "NRF_TWI_EVENT_BB" : \
(event == NRF_TWI_EVENT_SUSPENDED ? "NRF_TWI_EVENT_SUSPENDED" : \
"UNKNOWN ERROR"))))))
#define TRANSFER_TO_STR(type) \
(type == NRFX_TWI_XFER_TX ? "XFER_TX" : \
(type == NRFX_TWI_XFER_RX ? "XFER_RX" : \
(type == NRFX_TWI_XFER_TXRX ? "XFER_TXRX" : \
(type == NRFX_TWI_XFER_TXTX ? "XFER_TXTX" : \
"UNKNOWN TRANSFER TYPE"))))
#define TWI_PIN_INIT(_pin) nrf_gpio_cfg((_pin), \
NRF_GPIO_PIN_DIR_INPUT, \
NRF_GPIO_PIN_INPUT_CONNECT, \
NRF_GPIO_PIN_PULLUP, \
NRF_GPIO_PIN_S0D1, \
NRF_GPIO_PIN_NOSENSE)
#define TWI_FLAG_NO_STOP(flags) (flags & NRFX_TWI_FLAG_TX_NO_STOP)
#define TWI_FLAG_SUSPEND(flags) (flags & NRFX_TWI_FLAG_SUSPEND)
#define TWI_FLAG_NO_HANDLER_IN_USE(flags) (flags & NRFX_TWI_FLAG_NO_XFER_EVT_HANDLER)
#define HW_TIMEOUT 100000
/* TWI master driver suspend types. */
typedef enum
{
TWI_NO_SUSPEND, //< Last transfer was not suspended.
TWI_SUSPEND_TX, //< Last transfer was TX and was suspended.
TWI_SUSPEND_RX //< Last transfer was RX and was suspended.
} twi_suspend_t;
// Control block - driver instance local data.
typedef struct
{
nrfx_twi_evt_handler_t handler;
void * p_context;
volatile uint32_t int_mask;
nrfx_twi_xfer_desc_t xfer_desc;
uint32_t flags;
uint8_t * p_curr_buf;
size_t curr_length;
bool curr_tx_no_stop;
twi_suspend_t prev_suspend;
nrfx_drv_state_t state;
bool error;
volatile bool busy;
bool repeated;
size_t bytes_transferred;
bool hold_bus_uninit;
} twi_control_block_t;
static twi_control_block_t m_cb[NRFX_TWI_ENABLED_COUNT];
static nrfx_err_t twi_process_error(uint32_t errorsrc)
{
nrfx_err_t ret = NRFX_ERROR_INTERNAL;
if (errorsrc & NRF_TWI_ERROR_OVERRUN)
{
ret = NRFX_ERROR_DRV_TWI_ERR_OVERRUN;
}
if (errorsrc & NRF_TWI_ERROR_ADDRESS_NACK)
{
ret = NRFX_ERROR_DRV_TWI_ERR_ANACK;
}
if (errorsrc & NRF_TWI_ERROR_DATA_NACK)
{
ret = NRFX_ERROR_DRV_TWI_ERR_DNACK;
}
return ret;
}
static bool xfer_completeness_check(NRF_TWI_Type * p_twi, twi_control_block_t const * p_cb)
{
// If the actual number of transferred bytes is not equal to what was requested,
// but there was no error signaled by the peripheral, this means that something
// unexpected, like a premature STOP condition, was received on the bus.
// In such case the peripheral has to be disabled and re-enabled, so that its
// internal state machine is reinitialized.
if (p_cb->bytes_transferred != p_cb->curr_length)
{
nrf_twi_disable(p_twi);
nrf_twi_enable(p_twi);
return false;
}
else
{
return true;
}
}
nrfx_err_t nrfx_twi_init(nrfx_twi_t const * p_instance,
nrfx_twi_config_t const * p_config,
nrfx_twi_evt_handler_t event_handler,
void * p_context)
{
NRFX_ASSERT(p_config);
NRFX_ASSERT(p_config->scl != p_config->sda);
twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
nrfx_err_t err_code;
if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
{
err_code = NRFX_ERROR_INVALID_STATE;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
#if NRFX_CHECK(NRFX_PRS_ENABLED)
static nrfx_irq_handler_t const irq_handlers[NRFX_TWI_ENABLED_COUNT] = {
#if NRFX_CHECK(NRFX_TWI0_ENABLED)
nrfx_twi_0_irq_handler,
#endif
#if NRFX_CHECK(NRFX_TWI1_ENABLED)
nrfx_twi_1_irq_handler,
#endif
};
if (nrfx_prs_acquire(p_instance->p_twi,
irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
{
err_code = NRFX_ERROR_BUSY;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
#endif // NRFX_CHECK(NRFX_PRS_ENABLED)
p_cb->handler = event_handler;
p_cb->p_context = p_context;
p_cb->int_mask = 0;
p_cb->prev_suspend = TWI_NO_SUSPEND;
p_cb->repeated = false;
p_cb->busy = false;
p_cb->hold_bus_uninit = p_config->hold_bus_uninit;
/* To secure correct signal levels on the pins used by the TWI
master when the system is in OFF mode, and when the TWI master is
disabled, these pins must be configured in the GPIO peripheral.
*/
TWI_PIN_INIT(p_config->scl);
TWI_PIN_INIT(p_config->sda);
NRF_TWI_Type * p_twi = p_instance->p_twi;
nrf_twi_pins_set(p_twi, p_config->scl, p_config->sda);
nrf_twi_frequency_set(p_twi,
(nrf_twi_frequency_t)p_config->frequency);
if (p_cb->handler)
{
NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_twi),
p_config->interrupt_priority);
NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_twi));
}
p_cb->state = NRFX_DRV_STATE_INITIALIZED;
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
void nrfx_twi_uninit(nrfx_twi_t const * p_instance)
{
twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
if (p_cb->handler)
{
NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_twi));
}
nrfx_twi_disable(p_instance);
#if NRFX_CHECK(NRFX_PRS_ENABLED)
nrfx_prs_release(p_instance->p_twi);
#endif
if (!p_cb->hold_bus_uninit)
{
nrf_gpio_cfg_default(nrf_twi_scl_pin_get(p_instance->p_twi));
nrf_gpio_cfg_default(nrf_twi_sda_pin_get(p_instance->p_twi));
}
p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
NRFX_LOG_INFO("Instance uninitialized: %d.", p_instance->drv_inst_idx);
}
void nrfx_twi_enable(nrfx_twi_t const * p_instance)
{
twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
NRF_TWI_Type * p_twi = p_instance->p_twi;
nrf_twi_enable(p_twi);
p_cb->state = NRFX_DRV_STATE_POWERED_ON;
NRFX_LOG_INFO("Instance enabled: %d.", p_instance->drv_inst_idx);
}
void nrfx_twi_disable(nrfx_twi_t const * p_instance)
{
twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
NRF_TWI_Type * p_twi = p_instance->p_twi;
nrf_twi_int_disable(p_twi, NRF_TWI_ALL_INTS_MASK);
nrf_twi_shorts_disable(p_twi, NRF_TWI_ALL_SHORTS_MASK);
nrf_twi_disable(p_twi);
p_cb->state = NRFX_DRV_STATE_INITIALIZED;
NRFX_LOG_INFO("Instance disabled: %d.", p_instance->drv_inst_idx);
}
static bool twi_send_byte(NRF_TWI_Type * p_twi,
twi_control_block_t * p_cb)
{
if (p_cb->bytes_transferred < p_cb->curr_length)
{
nrf_twi_txd_set(p_twi, p_cb->p_curr_buf[p_cb->bytes_transferred]);
}
else
{
if (p_cb->curr_tx_no_stop)
{
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_SUSPEND);
return false;
}
else if(TWI_FLAG_SUSPEND(p_cb->flags))
{
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_SUSPEND);
p_cb->prev_suspend = TWI_SUSPEND_TX;
return false;
}
else
{
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STOP);
}
}
return true;
}
static bool twi_receive_byte(NRF_TWI_Type * p_twi,
twi_control_block_t * p_cb)
{
if (p_cb->bytes_transferred < p_cb->curr_length)
{
p_cb->p_curr_buf[p_cb->bytes_transferred] = nrf_twi_rxd_get(p_twi);
++(p_cb->bytes_transferred);
if ((p_cb->bytes_transferred == p_cb->curr_length - 1) && (!TWI_FLAG_SUSPEND(p_cb->flags)))
{
nrf_twi_shorts_set(p_twi, NRF_TWI_SHORT_BB_STOP_MASK);
}
else if (p_cb->bytes_transferred == p_cb->curr_length && (!TWI_FLAG_SUSPEND(p_cb->flags)))
{
return true;
}
else if (p_cb->bytes_transferred == p_cb->curr_length && TWI_FLAG_SUSPEND(p_cb->flags))
{
p_cb->prev_suspend = TWI_SUSPEND_RX;
return false;
}
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_RESUME);
}
return true;
}
static bool twi_transfer(NRF_TWI_Type * p_twi,
twi_control_block_t * p_cb)
{
bool stopped = false;
if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_STOPPED))
{
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_STOPPED);
NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_STOPPED));
// Delay handling of STOPPED event till the end of events processing procedure.
// If penultimate byte is received and function gets interrupted for long enough
// after enabling BB_STOP shortcut, RXDREADY for last byte as well as STOPPED
// may be active at the same time. Therefore RXREADY has to be processed before STOPPED to
// acquire last byte before finishing transmission by returning 'false'.
stopped = true;
}
if (p_cb->error)
{
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT);
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_RXDREADY);
}
else if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_ERROR))
{
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_ERROR));
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STOP);
p_cb->error = true;
}
else
{
if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_TXDSENT))
{
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT);
++(p_cb->bytes_transferred);
NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_TXDSENT));
if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_ERROR))
{
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_ERROR));
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STOP);
p_cb->error = true;
}
else
{
if (!twi_send_byte(p_twi, p_cb))
{
return false;
}
}
}
else if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_RXDREADY))
{
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_RXDREADY);
NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_RXDREADY));
if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_ERROR))
{
NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_ERROR));
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STOP);
p_cb->error = true;
}
else
{
if (!twi_receive_byte(p_twi, p_cb))
{
return false;
}
}
}
}
if (stopped)
{
p_cb->prev_suspend = TWI_NO_SUSPEND;
if (!p_cb->error)
{
p_cb->error = !xfer_completeness_check(p_twi, p_cb);
}
return false;
}
return true;
}
static nrfx_err_t twi_tx_start_transfer(NRF_TWI_Type * p_twi,
twi_control_block_t * p_cb)
{
nrfx_err_t ret_code = NRFX_SUCCESS;
volatile int32_t hw_timeout;
hw_timeout = HW_TIMEOUT;
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_STOPPED);
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT);
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_RXDREADY);
nrf_twi_shorts_set(p_twi, 0);
p_cb->bytes_transferred = 0;
p_cb->error = false;
// In case TWI is suspended resume its operation.
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_RESUME);
if (p_cb->prev_suspend != TWI_SUSPEND_TX)
{
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STARTTX);
}
(void)twi_send_byte(p_twi, p_cb);
if (p_cb->handler)
{
p_cb->int_mask = NRF_TWI_INT_STOPPED_MASK |
NRF_TWI_INT_ERROR_MASK |
NRF_TWI_INT_TXDSENT_MASK |
NRF_TWI_INT_RXDREADY_MASK;
nrf_twi_int_enable(p_twi, p_cb->int_mask);
}
else
{
while ((hw_timeout > 0) &&
twi_transfer(p_twi, p_cb))
{
hw_timeout--;
}
if (p_cb->error)
{
uint32_t errorsrc = nrf_twi_errorsrc_get_and_clear(p_twi);
if (errorsrc)
{
ret_code = twi_process_error(errorsrc);
}
else
{
ret_code = NRFX_ERROR_INTERNAL;
}
}
if (hw_timeout <= 0)
{
nrf_twi_disable(p_twi);
nrf_twi_enable(p_twi);
ret_code = NRFX_ERROR_INTERNAL;
}
}
return ret_code;
}
static nrfx_err_t twi_rx_start_transfer(NRF_TWI_Type * p_twi,
twi_control_block_t * p_cb)
{
nrfx_err_t ret_code = NRFX_SUCCESS;
volatile int32_t hw_timeout;
hw_timeout = HW_TIMEOUT;
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_STOPPED);
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT);
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_RXDREADY);
p_cb->bytes_transferred = 0;
p_cb->error = false;
if ((p_cb->curr_length == 1) && (!TWI_FLAG_SUSPEND(p_cb->flags)))
{
nrf_twi_shorts_set(p_twi, NRF_TWI_SHORT_BB_STOP_MASK);
}
else
{
nrf_twi_shorts_set(p_twi, NRF_TWI_SHORT_BB_SUSPEND_MASK);
}
// In case TWI is suspended resume its operation.
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_RESUME);
if (p_cb->prev_suspend != TWI_SUSPEND_RX)
{
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STARTRX);
}
if (p_cb->handler)
{
p_cb->int_mask = NRF_TWI_INT_STOPPED_MASK |
NRF_TWI_INT_ERROR_MASK |
NRF_TWI_INT_TXDSENT_MASK |
NRF_TWI_INT_RXDREADY_MASK;
nrf_twi_int_enable(p_twi, p_cb->int_mask);
}
else
{
while ((hw_timeout > 0) &&
twi_transfer(p_twi, p_cb))
{
hw_timeout--;
}
if (p_cb->error)
{
uint32_t errorsrc = nrf_twi_errorsrc_get_and_clear(p_twi);
if (errorsrc)
{
ret_code = twi_process_error(errorsrc);
}
else
{
ret_code = NRFX_ERROR_INTERNAL;
}
}
if (hw_timeout <= 0)
{
nrf_twi_disable(p_twi);
nrf_twi_enable(p_twi);
ret_code = NRFX_ERROR_INTERNAL;
}
}
return ret_code;
}
__STATIC_INLINE nrfx_err_t twi_xfer(NRF_TWI_Type * p_twi,
twi_control_block_t * p_cb,
nrfx_twi_xfer_desc_t const * p_xfer_desc,
uint32_t flags)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if ((p_cb->prev_suspend == TWI_SUSPEND_TX) && (p_xfer_desc->type == NRFX_TWI_XFER_RX))
{
/* RX is invalid after TX suspend */
return NRFX_ERROR_INVALID_STATE;
}
else if ((p_cb->prev_suspend == TWI_SUSPEND_RX) && (p_xfer_desc->type != NRFX_TWI_XFER_RX))
{
/* TX, TXRX and TXTX are invalid after RX suspend */
return NRFX_ERROR_INVALID_STATE;
}
/* Block TWI interrupts to ensure that function is not interrupted by TWI interrupt. */
nrf_twi_int_disable(p_twi, NRF_TWI_ALL_INTS_MASK);
if (p_cb->busy)
{
nrf_twi_int_enable(p_twi, p_cb->int_mask);
err_code = NRFX_ERROR_BUSY;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
else
{
p_cb->busy = (TWI_FLAG_NO_HANDLER_IN_USE(flags)) ? false : true;
}
p_cb->flags = flags;
p_cb->xfer_desc = *p_xfer_desc;
p_cb->curr_length = p_xfer_desc->primary_length;
p_cb->p_curr_buf = p_xfer_desc->p_primary_buf;
nrf_twi_address_set(p_twi, p_xfer_desc->address);
if (p_xfer_desc->type != NRFX_TWI_XFER_RX)
{
p_cb->curr_tx_no_stop = ((p_xfer_desc->type == NRFX_TWI_XFER_TX) &&
!(flags & NRFX_TWI_FLAG_TX_NO_STOP)) ? false : true;
err_code = twi_tx_start_transfer(p_twi, p_cb);
}
else
{
err_code = twi_rx_start_transfer(p_twi, p_cb);
}
if (p_cb->handler == NULL)
{
p_cb->busy = false;
}
return err_code;
}
bool nrfx_twi_is_busy(nrfx_twi_t const * p_instance)
{
twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
return p_cb->busy;
}
nrfx_err_t nrfx_twi_xfer(nrfx_twi_t const * p_instance,
nrfx_twi_xfer_desc_t const * p_xfer_desc,
uint32_t flags)
{
nrfx_err_t err_code = NRFX_SUCCESS;
twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
// TXRX and TXTX transfers are supported only in non-blocking mode.
NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWI_XFER_TXRX)));
NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWI_XFER_TXTX)));
NRFX_LOG_INFO("Transfer type: %s.", TRANSFER_TO_STR(p_xfer_desc->type));
NRFX_LOG_INFO("Transfer buffers length: primary: %d, secondary: %d.",
p_xfer_desc->primary_length,
p_xfer_desc->secondary_length);
NRFX_LOG_DEBUG("Primary buffer data:");
NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_primary_buf,
p_xfer_desc->primary_length * sizeof(p_xfer_desc->p_primary_buf[0]));
NRFX_LOG_DEBUG("Secondary buffer data:");
NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_secondary_buf,
p_xfer_desc->secondary_length * sizeof(p_xfer_desc->p_secondary_buf[0]));
err_code = twi_xfer((NRF_TWI_Type *)p_instance->p_twi, p_cb, p_xfer_desc, flags);
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_twi_tx(nrfx_twi_t const * p_instance,
uint8_t address,
uint8_t const * p_data,
size_t length,
bool no_stop)
{
nrfx_twi_xfer_desc_t xfer = NRFX_TWI_XFER_DESC_TX(address, (uint8_t*)p_data, length);
return nrfx_twi_xfer(p_instance, &xfer, no_stop ? NRFX_TWI_FLAG_TX_NO_STOP : 0);
}
nrfx_err_t nrfx_twi_rx(nrfx_twi_t const * p_instance,
uint8_t address,
uint8_t * p_data,
size_t length)
{
nrfx_twi_xfer_desc_t xfer = NRFX_TWI_XFER_DESC_RX(address, p_data, length);
return nrfx_twi_xfer(p_instance, &xfer, 0);
}
size_t nrfx_twi_data_count_get(nrfx_twi_t const * const p_instance)
{
return m_cb[p_instance->drv_inst_idx].bytes_transferred;
}
uint32_t nrfx_twi_stopped_event_get(nrfx_twi_t const * p_instance)
{
return (uint32_t)nrf_twi_event_address_get(p_instance->p_twi, NRF_TWI_EVENT_STOPPED);
}
static void twi_irq_handler(NRF_TWI_Type * p_twi, twi_control_block_t * p_cb)
{
NRFX_ASSERT(p_cb->handler);
if (twi_transfer(p_twi, p_cb))
{
return;
}
if (!p_cb->error &&
((p_cb->xfer_desc.type == NRFX_TWI_XFER_TXRX) ||
(p_cb->xfer_desc.type == NRFX_TWI_XFER_TXTX)) &&
p_cb->p_curr_buf == p_cb->xfer_desc.p_primary_buf)
{
p_cb->p_curr_buf = p_cb->xfer_desc.p_secondary_buf;
p_cb->curr_length = p_cb->xfer_desc.secondary_length;
p_cb->curr_tx_no_stop = (p_cb->flags & NRFX_TWI_FLAG_TX_NO_STOP);
p_cb->prev_suspend = TWI_NO_SUSPEND;
if (p_cb->xfer_desc.type == NRFX_TWI_XFER_TXTX)
{
(void)twi_tx_start_transfer(p_twi, p_cb);
}
else
{
(void)twi_rx_start_transfer(p_twi, p_cb);
}
}
else
{
nrfx_twi_evt_t event;
event.xfer_desc = p_cb->xfer_desc;
if (p_cb->error)
{
uint32_t errorsrc = nrf_twi_errorsrc_get_and_clear(p_twi);
if (errorsrc & NRF_TWI_ERROR_ADDRESS_NACK)
{
event.type = NRFX_TWI_EVT_ADDRESS_NACK;
NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWI_EVT_ADDRESS_NACK));
}
else if (errorsrc & NRF_TWI_ERROR_DATA_NACK)
{
event.type = NRFX_TWI_EVT_DATA_NACK;
NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWI_EVT_DATA_NACK));
}
else if (errorsrc & NRF_TWI_ERROR_OVERRUN)
{
event.type = NRFX_TWI_EVT_OVERRUN;
NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWI_EVT_OVERRUN));
}
else
{
event.type = NRFX_TWI_EVT_BUS_ERROR;
NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWI_EVT_BUS_ERROR));
}
}
else
{
event.type = NRFX_TWI_EVT_DONE;
NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWI_EVT_DONE));
}
p_cb->busy = false;
if (!(TWI_FLAG_NO_HANDLER_IN_USE(p_cb->flags)) || p_cb->error)
{
p_cb->handler(&event, p_cb->p_context);
}
}
}
#if NRFX_CHECK(NRFX_TWI0_ENABLED)
void nrfx_twi_0_irq_handler(void)
{
twi_irq_handler(NRF_TWI0, &m_cb[NRFX_TWI0_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_TWI1_ENABLED)
void nrfx_twi_1_irq_handler(void)
{
twi_irq_handler(NRF_TWI1, &m_cb[NRFX_TWI1_INST_IDX]);
}
#endif
#endif // NRFX_CHECK(NRFX_TWI_ENABLED)
+90
View File
@@ -0,0 +1,90 @@
/**
* Copyright (c) 2019 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#include <nrf_gpio.h>
#define TWI_TWIM_PIN_CONFIGURE(_pin) nrf_gpio_cfg((_pin), \
NRF_GPIO_PIN_DIR_OUTPUT, \
NRF_GPIO_PIN_INPUT_CONNECT, \
NRF_GPIO_PIN_PULLUP, \
NRF_GPIO_PIN_S0D1, \
NRF_GPIO_PIN_NOSENSE)
nrfx_err_t nrfx_twi_twim_bus_recover(uint32_t scl_pin, uint32_t sda_pin)
{
nrf_gpio_pin_set(scl_pin);
nrf_gpio_pin_set(sda_pin);
TWI_TWIM_PIN_CONFIGURE(scl_pin);
TWI_TWIM_PIN_CONFIGURE(sda_pin);
NRFX_DELAY_US(4);
for (uint8_t i = 0; i < 9; i++)
{
if (nrf_gpio_pin_read(sda_pin))
{
break;
}
else
{
// Pulse CLOCK signal
nrf_gpio_pin_clear(scl_pin);
NRFX_DELAY_US(4);
nrf_gpio_pin_set(scl_pin);
NRFX_DELAY_US(4);
}
}
// Generate a STOP condition on the bus
nrf_gpio_pin_clear(sda_pin);
NRFX_DELAY_US(4);
nrf_gpio_pin_set(sda_pin);
NRFX_DELAY_US(4);
if (nrf_gpio_pin_read(sda_pin))
{
return NRFX_SUCCESS;
}
else
{
return NRFX_ERROR_INTERNAL;
}
}
+872
View File
@@ -0,0 +1,872 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_TWIM_ENABLED)
#if !(NRFX_CHECK(NRFX_TWIM0_ENABLED) || \
NRFX_CHECK(NRFX_TWIM1_ENABLED) || \
NRFX_CHECK(NRFX_TWIM2_ENABLED) || \
NRFX_CHECK(NRFX_TWIM3_ENABLED))
#error "No enabled TWIM instances. Check <nrfx_config.h>."
#endif
#include <nrfx_twim.h>
#include <hal/nrf_gpio.h>
#include "prs/nrfx_prs.h"
#define NRFX_LOG_MODULE TWIM
#include <nrfx_log.h>
#define EVT_TO_STR(event) \
(event == NRFX_TWIM_EVT_DONE ? "EVT_DONE" : \
(event == NRFX_TWIM_EVT_ADDRESS_NACK ? "EVT_ADDRESS_NACK" : \
(event == NRFX_TWIM_EVT_DATA_NACK ? "EVT_DATA_NACK" : \
(event == NRFX_TWIM_EVT_OVERRUN ? "EVT_OVERRUN" : \
(event == NRFX_TWIM_EVT_BUS_ERROR ? "EVT_BUS_ERROR" : \
"UNKNOWN ERROR")))))
#define EVT_TO_STR_TWIM(event) \
(event == NRF_TWIM_EVENT_STOPPED ? "NRF_TWIM_EVENT_STOPPED" : \
(event == NRF_TWIM_EVENT_ERROR ? "NRF_TWIM_EVENT_ERROR" : \
(event == NRF_TWIM_EVENT_SUSPENDED ? "NRF_TWIM_EVENT_SUSPENDED" : \
(event == NRF_TWIM_EVENT_RXSTARTED ? "NRF_TWIM_EVENT_RXSTARTED" : \
(event == NRF_TWIM_EVENT_TXSTARTED ? "NRF_TWIM_EVENT_TXSTARTED" : \
(event == NRF_TWIM_EVENT_LASTRX ? "NRF_TWIM_EVENT_LASTRX" : \
(event == NRF_TWIM_EVENT_LASTTX ? "NRF_TWIM_EVENT_LASTTX" : \
"UNKNOWN ERROR")))))))
#define TRANSFER_TO_STR(type) \
(type == NRFX_TWIM_XFER_TX ? "XFER_TX" : \
(type == NRFX_TWIM_XFER_RX ? "XFER_RX" : \
(type == NRFX_TWIM_XFER_TXRX ? "XFER_TXRX" : \
(type == NRFX_TWIM_XFER_TXTX ? "XFER_TXTX" : \
"UNKNOWN TRANSFER TYPE"))))
#define TWIM_PIN_INIT(_pin) nrf_gpio_cfg((_pin), \
NRF_GPIO_PIN_DIR_INPUT, \
NRF_GPIO_PIN_INPUT_CONNECT, \
NRF_GPIO_PIN_PULLUP, \
NRF_GPIO_PIN_S0D1, \
NRF_GPIO_PIN_NOSENSE)
#define TWIMX_LENGTH_VALIDATE(peripheral, drv_inst_idx, len1, len2) \
(((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \
NRFX_EASYDMA_LENGTH_VALIDATE(peripheral, len1, len2))
#if NRFX_CHECK(NRFX_TWIM0_ENABLED)
#define TWIM0_LENGTH_VALIDATE(...) TWIMX_LENGTH_VALIDATE(TWIM0, __VA_ARGS__)
#else
#define TWIM0_LENGTH_VALIDATE(...) 0
#endif
#if NRFX_CHECK(NRFX_TWIM1_ENABLED)
#define TWIM1_LENGTH_VALIDATE(...) TWIMX_LENGTH_VALIDATE(TWIM1, __VA_ARGS__)
#else
#define TWIM1_LENGTH_VALIDATE(...) 0
#endif
#if NRFX_CHECK(NRFX_TWIM2_ENABLED)
#define TWIM2_LENGTH_VALIDATE(...) TWIMX_LENGTH_VALIDATE(TWIM2, __VA_ARGS__)
#else
#define TWIM2_LENGTH_VALIDATE(...) 0
#endif
#if NRFX_CHECK(NRFX_TWIM3_ENABLED)
#define TWIM3_LENGTH_VALIDATE(...) TWIMX_LENGTH_VALIDATE(TWIM3, __VA_ARGS__)
#else
#define TWIM3_LENGTH_VALIDATE(...) 0
#endif
#define TWIM_LENGTH_VALIDATE(drv_inst_idx, len1, len2) \
(TWIM0_LENGTH_VALIDATE(drv_inst_idx, len1, len2) || \
TWIM1_LENGTH_VALIDATE(drv_inst_idx, len1, len2) || \
TWIM2_LENGTH_VALIDATE(drv_inst_idx, len1, len2) || \
TWIM3_LENGTH_VALIDATE(drv_inst_idx, len1, len2))
// Control block - driver instance local data.
typedef struct
{
nrfx_twim_evt_handler_t handler;
void * p_context;
volatile uint32_t int_mask;
nrfx_twim_xfer_desc_t xfer_desc;
uint32_t flags;
uint8_t * p_curr_buf;
size_t curr_length;
bool curr_no_stop;
nrfx_drv_state_t state;
bool error;
volatile bool busy;
bool repeated;
uint8_t bytes_transferred;
bool hold_bus_uninit;
#if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
nrf_twim_frequency_t bus_frequency;
#endif
} twim_control_block_t;
static twim_control_block_t m_cb[NRFX_TWIM_ENABLED_COUNT];
static nrfx_err_t twi_process_error(uint32_t errorsrc)
{
nrfx_err_t ret = NRFX_ERROR_INTERNAL;
if (errorsrc & NRF_TWIM_ERROR_OVERRUN)
{
ret = NRFX_ERROR_DRV_TWI_ERR_OVERRUN;
}
if (errorsrc & NRF_TWIM_ERROR_ADDRESS_NACK)
{
ret = NRFX_ERROR_DRV_TWI_ERR_ANACK;
}
if (errorsrc & NRF_TWIM_ERROR_DATA_NACK)
{
ret = NRFX_ERROR_DRV_TWI_ERR_DNACK;
}
return ret;
}
static bool xfer_completeness_check(NRF_TWIM_Type * p_twim, twim_control_block_t const * p_cb)
{
// If the actual number of transferred bytes is not equal to what was requested,
// but there was no error signaled by the peripheral, this means that something
// unexpected, like a premature STOP condition, was received on the bus.
// In such case the peripheral has to be disabled and re-enabled, so that its
// internal state machine is reinitialized.
bool transfer_complete = true;
switch (p_cb->xfer_desc.type)
{
case NRFX_TWIM_XFER_TXTX:
// int_mask variable is used to determine which length should be checked
// against number of bytes latched in EasyDMA.
// NRF_TWIM_INT_SUSPENDED_MASK is configured only in first TX of TXTX transfer.
if (((p_cb->int_mask & NRF_TWIM_INT_SUSPENDED_MASK) &&
(nrf_twim_txd_amount_get(p_twim) != p_cb->xfer_desc.primary_length)) ||
(!(p_cb->int_mask & NRF_TWIM_INT_SUSPENDED_MASK) &&
(nrf_twim_txd_amount_get(p_twim) != p_cb->xfer_desc.secondary_length)))
{
transfer_complete = false;
}
break;
case NRFX_TWIM_XFER_TXRX:
if ((nrf_twim_txd_amount_get(p_twim) != p_cb->xfer_desc.primary_length) ||
(nrf_twim_rxd_amount_get(p_twim) != p_cb->xfer_desc.secondary_length))
{
transfer_complete = false;
}
break;
case NRFX_TWIM_XFER_TX:
if (nrf_twim_txd_amount_get(p_twim) != p_cb->xfer_desc.primary_length)
{
transfer_complete = false;
}
break;
case NRFX_TWIM_XFER_RX:
if (nrf_twim_rxd_amount_get(p_twim) != p_cb->xfer_desc.primary_length)
{
transfer_complete = false;
}
break;
default:
break;
}
if (!transfer_complete)
{
nrf_twim_disable(p_twim);
nrf_twim_enable(p_twim);
}
return transfer_complete;
}
nrfx_err_t nrfx_twim_init(nrfx_twim_t const * p_instance,
nrfx_twim_config_t const * p_config,
nrfx_twim_evt_handler_t event_handler,
void * p_context)
{
NRFX_ASSERT(p_config);
NRFX_ASSERT(p_config->scl != p_config->sda);
twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
nrfx_err_t err_code;
if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
{
err_code = NRFX_ERROR_INVALID_STATE;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
#if NRFX_CHECK(NRFX_PRS_ENABLED)
static nrfx_irq_handler_t const irq_handlers[NRFX_TWIM_ENABLED_COUNT] = {
#if NRFX_CHECK(NRFX_TWIM0_ENABLED)
nrfx_twim_0_irq_handler,
#endif
#if NRFX_CHECK(NRFX_TWIM1_ENABLED)
nrfx_twim_1_irq_handler,
#endif
#if NRFX_CHECK(NRFX_TWIM2_ENABLED)
nrfx_twim_2_irq_handler,
#endif
#if NRFX_CHECK(NRFX_TWIM3_ENABLED)
nrfx_twim_3_irq_handler,
#endif
};
if (nrfx_prs_acquire(p_instance->p_twim,
irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
{
err_code = NRFX_ERROR_BUSY;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
#endif // NRFX_CHECK(NRFX_PRS_ENABLED)
p_cb->handler = event_handler;
p_cb->p_context = p_context;
p_cb->int_mask = 0;
p_cb->repeated = false;
p_cb->busy = false;
p_cb->hold_bus_uninit = p_config->hold_bus_uninit;
#if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
p_cb->bus_frequency = (nrf_twim_frequency_t)p_config->frequency;
#endif
/* To secure correct signal levels on the pins used by the TWI
master when the system is in OFF mode, and when the TWI master is
disabled, these pins must be configured in the GPIO peripheral.
*/
TWIM_PIN_INIT(p_config->scl);
TWIM_PIN_INIT(p_config->sda);
NRF_TWIM_Type * p_twim = p_instance->p_twim;
nrf_twim_pins_set(p_twim, p_config->scl, p_config->sda);
nrf_twim_frequency_set(p_twim,
(nrf_twim_frequency_t)p_config->frequency);
if (p_cb->handler)
{
NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_twim),
p_config->interrupt_priority);
NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_twim));
}
p_cb->state = NRFX_DRV_STATE_INITIALIZED;
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
void nrfx_twim_uninit(nrfx_twim_t const * p_instance)
{
twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
if (p_cb->handler)
{
NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_twim));
}
nrfx_twim_disable(p_instance);
#if NRFX_CHECK(NRFX_PRS_ENABLED)
nrfx_prs_release(p_instance->p_twim);
#endif
if (!p_cb->hold_bus_uninit)
{
nrf_gpio_cfg_default(p_instance->p_twim->PSEL.SCL);
nrf_gpio_cfg_default(p_instance->p_twim->PSEL.SDA);
}
p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
NRFX_LOG_INFO("Instance uninitialized: %d.", p_instance->drv_inst_idx);
}
void nrfx_twim_enable(nrfx_twim_t const * p_instance)
{
twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
nrf_twim_enable(p_instance->p_twim);
p_cb->state = NRFX_DRV_STATE_POWERED_ON;
NRFX_LOG_INFO("Instance enabled: %d.", p_instance->drv_inst_idx);
}
void nrfx_twim_disable(nrfx_twim_t const * p_instance)
{
twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
NRF_TWIM_Type * p_twim = p_instance->p_twim;
p_cb->int_mask = 0;
nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
nrf_twim_shorts_disable(p_twim, NRF_TWIM_ALL_SHORTS_MASK);
nrf_twim_disable(p_twim);
p_cb->state = NRFX_DRV_STATE_INITIALIZED;
NRFX_LOG_INFO("Instance disabled: %d.", p_instance->drv_inst_idx);
}
bool nrfx_twim_is_busy(nrfx_twim_t const * p_instance)
{
twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
return p_cb->busy;
}
__STATIC_INLINE void twim_list_enable_handle(NRF_TWIM_Type * p_twim, uint32_t flags)
{
if (NRFX_TWIM_FLAG_TX_POSTINC & flags)
{
nrf_twim_tx_list_enable(p_twim);
}
else
{
nrf_twim_tx_list_disable(p_twim);
}
if (NRFX_TWIM_FLAG_RX_POSTINC & flags)
{
nrf_twim_rx_list_enable(p_twim);
}
else
{
nrf_twim_rx_list_disable(p_twim);
}
}
__STATIC_INLINE nrfx_err_t twim_xfer(twim_control_block_t * p_cb,
NRF_TWIM_Type * p_twim,
nrfx_twim_xfer_desc_t const * p_xfer_desc,
uint32_t flags)
{
nrfx_err_t err_code = NRFX_SUCCESS;
nrf_twim_task_t start_task = NRF_TWIM_TASK_STARTTX;
p_cb->error = false;
if (!nrfx_is_in_ram(p_xfer_desc->p_primary_buf))
{
err_code = NRFX_ERROR_INVALID_ADDR;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
/* Block TWI interrupts to ensure that function is not interrupted by TWI interrupt. */
nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
if (p_cb->busy)
{
nrf_twim_int_enable(p_twim, p_cb->int_mask);
err_code = NRFX_ERROR_BUSY;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
else
{
p_cb->busy = ((NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER & flags) ||
(NRFX_TWIM_FLAG_REPEATED_XFER & flags)) ? false: true;
}
p_cb->xfer_desc = *p_xfer_desc;
p_cb->repeated = (flags & NRFX_TWIM_FLAG_REPEATED_XFER) ? true : false;
p_cb->flags = flags;
nrf_twim_address_set(p_twim, p_xfer_desc->address);
nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_STOPPED);
nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTTX);
nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
twim_list_enable_handle(p_twim, flags);
switch (p_xfer_desc->type)
{
case NRFX_TWIM_XFER_TXTX:
NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_REPEATED_XFER));
NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_HOLD_XFER));
NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER));
if (!nrfx_is_in_ram(p_xfer_desc->p_secondary_buf))
{
err_code = NRFX_ERROR_INVALID_ADDR;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK);
nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
while (!nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_TXSTARTED))
{}
NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_TXSTARTED));
nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_secondary_buf, p_xfer_desc->secondary_length);
p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK;
break;
case NRFX_TWIM_XFER_TXRX:
nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
if (!nrfx_is_in_ram(p_xfer_desc->p_secondary_buf))
{
err_code = NRFX_ERROR_INVALID_ADDR;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrf_twim_rx_buffer_set(p_twim, p_xfer_desc->p_secondary_buf, p_xfer_desc->secondary_length);
nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STARTRX_MASK |
NRF_TWIM_SHORT_LASTRX_STOP_MASK);
p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK;
nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
break;
case NRFX_TWIM_XFER_TX:
nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
if (NRFX_TWIM_FLAG_TX_NO_STOP & flags)
{
nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK);
p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK;
}
else
{
nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STOP_MASK);
p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK;
}
nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
break;
case NRFX_TWIM_XFER_RX:
nrf_twim_rx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTRX_STOP_MASK);
p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK;
start_task = NRF_TWIM_TASK_STARTRX;
nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
break;
default:
err_code = NRFX_ERROR_INVALID_PARAM;
break;
}
if (!(flags & NRFX_TWIM_FLAG_HOLD_XFER) && (p_xfer_desc->type != NRFX_TWIM_XFER_TXTX))
{
nrf_twim_task_trigger(p_twim, start_task);
}
if (p_cb->handler)
{
if (flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER)
{
p_cb->int_mask = 0;
}
if (!(flags & NRFX_TWIM_FLAG_NO_SPURIOUS_STOP_CHECK))
{
p_cb->int_mask |= NRF_TWIM_INT_STOPPED_MASK;
}
// Interrupts for ERROR are implicitly enabled, regardless of driver configuration.
p_cb->int_mask |= NRF_TWIM_INT_ERROR_MASK;
nrf_twim_int_enable(p_twim, p_cb->int_mask);
#if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
if ((flags & NRFX_TWIM_FLAG_HOLD_XFER) && (p_xfer_desc->type != NRFX_TWIM_XFER_RX))
{
twim_list_enable_handle(p_twim, 0);
p_twim->FREQUENCY = 0;
nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
nrf_twim_int_enable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK);
}
else
{
nrf_twim_frequency_set(p_twim, p_cb->bus_frequency);
}
#endif
}
else
{
bool transmission_finished = false;
do {
if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_SUSPENDED))
{
NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_SUSPENDED));
transmission_finished = true;
}
if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_STOPPED))
{
nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_STOPPED);
NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_STOPPED));
transmission_finished = true;
}
if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_ERROR))
{
nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_ERROR));
bool lasttx_triggered = nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_LASTTX);
uint32_t shorts_mask = nrf_twim_shorts_get(p_twim);
if (!(lasttx_triggered && (shorts_mask & NRF_TWIM_SHORT_LASTTX_STOP_MASK)))
{
// Unless LASTTX event arrived and LASTTX_STOP shortcut is active,
// triggering of STOP task in case of error has to be done manually.
nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
// Mark transmission as not finished yet,
// as STOPPED event is expected to arrive.
// If LASTTX_SUSPENDED shortcut is active,
// NACK has been received on last byte sent
// and SUSPENDED event happened to be checked before ERROR,
// transmission will be marked as finished.
// In such case this flag has to be overwritten.
transmission_finished = false;
}
if (lasttx_triggered && (shorts_mask & NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK))
{
// When STOP task was triggered just before SUSPEND task has taken effect,
// SUSPENDED event may not arrive.
// However if SUSPENDED arrives it always arrives after ERROR.
// Therefore SUSPENDED has to be cleared
// so it does not cause premature termination of busy loop
// waiting for STOPPED event to arrive.
nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
// Mark transmission as not finished yet,
// for same reasons as above.
transmission_finished = false;
}
}
} while (!transmission_finished);
uint32_t errorsrc = nrf_twim_errorsrc_get_and_clear(p_twim);
p_cb->busy = false;
if (errorsrc)
{
err_code = twi_process_error(errorsrc);
}
else
{
if (!(flags & NRFX_TWIM_FLAG_NO_SPURIOUS_STOP_CHECK) &&
!xfer_completeness_check(p_twim, p_cb))
{
err_code = NRFX_ERROR_INTERNAL;
}
}
}
return err_code;
}
nrfx_err_t nrfx_twim_xfer(nrfx_twim_t const * p_instance,
nrfx_twim_xfer_desc_t const * p_xfer_desc,
uint32_t flags)
{
NRFX_ASSERT(TWIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
p_xfer_desc->primary_length,
p_xfer_desc->secondary_length));
nrfx_err_t err_code = NRFX_SUCCESS;
twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
// TXRX and TXTX transfers are supported only in non-blocking mode.
NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWIM_XFER_TXRX)));
NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWIM_XFER_TXTX)));
NRFX_LOG_INFO("Transfer type: %s.", TRANSFER_TO_STR(p_xfer_desc->type));
NRFX_LOG_INFO("Transfer buffers length: primary: %d, secondary: %d.",
p_xfer_desc->primary_length,
p_xfer_desc->secondary_length);
NRFX_LOG_DEBUG("Primary buffer data:");
NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_primary_buf,
p_xfer_desc->primary_length * sizeof(p_xfer_desc->p_primary_buf[0]));
NRFX_LOG_DEBUG("Secondary buffer data:");
NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_secondary_buf,
p_xfer_desc->secondary_length * sizeof(p_xfer_desc->p_secondary_buf[0]));
err_code = twim_xfer(p_cb, (NRF_TWIM_Type *)p_instance->p_twim, p_xfer_desc, flags);
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_twim_tx(nrfx_twim_t const * p_instance,
uint8_t address,
uint8_t const * p_data,
size_t length,
bool no_stop)
{
nrfx_twim_xfer_desc_t xfer = NRFX_TWIM_XFER_DESC_TX(address, (uint8_t*)p_data, length);
return nrfx_twim_xfer(p_instance, &xfer, no_stop ? NRFX_TWIM_FLAG_TX_NO_STOP : 0);
}
nrfx_err_t nrfx_twim_rx(nrfx_twim_t const * p_instance,
uint8_t address,
uint8_t * p_data,
size_t length)
{
nrfx_twim_xfer_desc_t xfer = NRFX_TWIM_XFER_DESC_RX(address, p_data, length);
return nrfx_twim_xfer(p_instance, &xfer, 0);
}
uint32_t nrfx_twim_start_task_get(nrfx_twim_t const * p_instance,
nrfx_twim_xfer_type_t xfer_type)
{
return (uint32_t)nrf_twim_task_address_get(p_instance->p_twim,
(xfer_type != NRFX_TWIM_XFER_RX) ? NRF_TWIM_TASK_STARTTX : NRF_TWIM_TASK_STARTRX);
}
uint32_t nrfx_twim_stopped_event_get(nrfx_twim_t const * p_instance)
{
return (uint32_t)nrf_twim_event_address_get(p_instance->p_twim, NRF_TWIM_EVENT_STOPPED);
}
static void twim_irq_handler(NRF_TWIM_Type * p_twim, twim_control_block_t * p_cb)
{
#if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
/* Handle only workaround case. Can be used without TWIM handler in IRQs. */
if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_TXSTARTED))
{
nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
nrf_twim_int_disable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK);
if (p_twim->FREQUENCY == 0)
{
// Set enable to zero to reset TWIM internal state.
nrf_twim_disable(p_twim);
nrf_twim_enable(p_twim);
// Set proper frequency.
nrf_twim_frequency_set(p_twim, p_cb->bus_frequency);
twim_list_enable_handle(p_twim, p_cb->flags);
// Start proper transmission.
nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
return;
}
}
#endif
NRFX_ASSERT(p_cb->handler);
if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_ERROR))
{
nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_ERROR));
if (!nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_STOPPED))
{
nrf_twim_int_disable(p_twim, p_cb->int_mask);
p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK;
nrf_twim_int_enable(p_twim, p_cb->int_mask);
if (!(nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_LASTTX) &&
(nrf_twim_shorts_get(p_twim) & NRF_TWIM_SHORT_LASTTX_STOP_MASK)))
{
nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
}
p_cb->error = true;
return;
}
}
nrfx_twim_evt_t event;
if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_STOPPED))
{
NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_STOPPED));
nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_STOPPED);
if (!(p_cb->flags & NRFX_TWIM_FLAG_NO_SPURIOUS_STOP_CHECK) && !p_cb->error)
{
p_cb->error = !xfer_completeness_check(p_twim, p_cb);
}
// Further processing of STOPPED event is valid only if NO_XFER_EVT_HANDLER
// setting is not used.
if (!(p_cb->flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER))
{
event.xfer_desc = p_cb->xfer_desc;
nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTTX);
nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTRX);
if (!p_cb->repeated || p_cb->error)
{
nrf_twim_shorts_set(p_twim, 0);
p_cb->int_mask = 0;
nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
// At this point interrupt handler should not be invoked again for current transfer.
// If STOPPED arrived during ERROR processing,
// its pending interrupt should be ignored.
// Otherwise spurious NRFX_TWIM_EVT_DONE or NRFX_TWIM_EVT_BUS_ERROR
// would be passed to user's handler.
NRFX_IRQ_PENDING_CLEAR(nrfx_get_irq_number(p_twim));
}
}
#if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
else if (p_cb->xfer_desc.type != NRFX_TWIM_XFER_RX)
{
/* Add Anomaly 109 workaround for each potential repeated transfer starting from TX. */
twim_list_enable_handle(p_twim, 0);
p_twim->FREQUENCY = 0;
nrf_twim_int_enable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK);
}
#endif
}
else
{
nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_SUSPENDED));
if (p_cb->xfer_desc.type == NRFX_TWIM_XFER_TX)
{
event.xfer_desc = p_cb->xfer_desc;
if (!p_cb->repeated)
{
nrf_twim_shorts_set(p_twim, 0);
p_cb->int_mask = 0;
nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
// At this point interrupt handler should not be invoked again for current transfer.
// If STOPPED arrived during SUSPENDED processing,
// its pending interrupt should be ignored.
// Otherwise spurious NRFX_TWIM_EVT_DONE or NRFX_TWIM_EVT_BUS_ERROR
// would be passed to user's handler.
NRFX_IRQ_PENDING_CLEAR(nrfx_get_irq_number(p_twim));
}
}
else
{
nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STOP_MASK);
p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
nrf_twim_int_enable(p_twim, p_cb->int_mask);
nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
return;
}
}
uint32_t errorsrc = nrf_twim_errorsrc_get_and_clear(p_twim);
if (errorsrc & NRF_TWIM_ERROR_ADDRESS_NACK)
{
event.type = NRFX_TWIM_EVT_ADDRESS_NACK;
NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_ADDRESS_NACK));
}
else if (errorsrc & NRF_TWIM_ERROR_DATA_NACK)
{
event.type = NRFX_TWIM_EVT_DATA_NACK;
NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_DATA_NACK));
}
else if (errorsrc & NRF_TWIM_ERROR_OVERRUN)
{
event.type = NRFX_TWIM_EVT_OVERRUN;
NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_OVERRUN));
}
else if (p_cb->error)
{
event.type = NRFX_TWIM_EVT_BUS_ERROR;
NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_BUS_ERROR));
}
else
{
event.type = NRFX_TWIM_EVT_DONE;
NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_DONE));
}
if (!p_cb->repeated)
{
p_cb->busy = false;
}
if (!(p_cb->flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER) || p_cb->error)
{
p_cb->handler(&event, p_cb->p_context);
}
}
#if NRFX_CHECK(NRFX_TWIM0_ENABLED)
void nrfx_twim_0_irq_handler(void)
{
twim_irq_handler(NRF_TWIM0, &m_cb[NRFX_TWIM0_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_TWIM1_ENABLED)
void nrfx_twim_1_irq_handler(void)
{
twim_irq_handler(NRF_TWIM1, &m_cb[NRFX_TWIM1_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_TWIM2_ENABLED)
void nrfx_twim_2_irq_handler(void)
{
twim_irq_handler(NRF_TWIM2, &m_cb[NRFX_TWIM2_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_TWIM3_ENABLED)
void nrfx_twim_3_irq_handler(void)
{
twim_irq_handler(NRF_TWIM3, &m_cb[NRFX_TWIM3_INST_IDX]);
}
#endif
#endif // NRFX_CHECK(NRFX_TWIM_ENABLED)
+654
View File
@@ -0,0 +1,654 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_UART_ENABLED)
#if !NRFX_CHECK(NRFX_UART0_ENABLED)
#error "No enabled UART instances. Check <nrfx_config.h>."
#endif
#include <nrfx_uart.h>
#include "prs/nrfx_prs.h"
#include <hal/nrf_gpio.h>
#define NRFX_LOG_MODULE UART
#include <nrfx_log.h>
#define EVT_TO_STR(event) \
(event == NRF_UART_EVENT_ERROR ? "NRF_UART_EVENT_ERROR" : \
"UNKNOWN EVENT")
#define TX_COUNTER_ABORT_REQ_VALUE UINT32_MAX
typedef struct
{
void * p_context;
nrfx_uart_event_handler_t handler;
uint8_t const * p_tx_buffer;
uint8_t * p_rx_buffer;
uint8_t * p_rx_secondary_buffer;
volatile size_t tx_buffer_length;
size_t rx_buffer_length;
size_t rx_secondary_buffer_length;
volatile size_t tx_counter;
volatile size_t rx_counter;
volatile bool tx_abort;
bool rx_enabled;
nrfx_drv_state_t state;
} uart_control_block_t;
static uart_control_block_t m_cb[NRFX_UART_ENABLED_COUNT];
static void apply_config(nrfx_uart_t const * p_instance,
nrfx_uart_config_t const * p_config)
{
if (p_config->pseltxd != NRF_UART_PSEL_DISCONNECTED)
{
nrf_gpio_pin_set(p_config->pseltxd);
nrf_gpio_cfg_output(p_config->pseltxd);
}
if (p_config->pselrxd != NRF_UART_PSEL_DISCONNECTED)
{
nrf_gpio_cfg_input(p_config->pselrxd, NRF_GPIO_PIN_NOPULL);
}
nrf_uart_baudrate_set(p_instance->p_reg, p_config->baudrate);
nrf_uart_configure(p_instance->p_reg, p_config->parity, p_config->hwfc);
nrf_uart_txrx_pins_set(p_instance->p_reg, p_config->pseltxd, p_config->pselrxd);
if (p_config->hwfc == NRF_UART_HWFC_ENABLED)
{
if (p_config->pselcts != NRF_UART_PSEL_DISCONNECTED)
{
nrf_gpio_cfg_input(p_config->pselcts, NRF_GPIO_PIN_NOPULL);
}
if (p_config->pselrts != NRF_UART_PSEL_DISCONNECTED)
{
nrf_gpio_pin_set(p_config->pselrts);
nrf_gpio_cfg_output(p_config->pselrts);
}
nrf_uart_hwfc_pins_set(p_instance->p_reg, p_config->pselrts, p_config->pselcts);
}
}
static void interrupts_enable(nrfx_uart_t const * p_instance,
uint8_t interrupt_priority)
{
nrf_uart_event_clear(p_instance->p_reg, NRF_UART_EVENT_TXDRDY);
nrf_uart_event_clear(p_instance->p_reg, NRF_UART_EVENT_RXTO);
nrf_uart_int_enable(p_instance->p_reg, NRF_UART_INT_MASK_TXDRDY |
NRF_UART_INT_MASK_RXTO);
NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number((void *)p_instance->p_reg),
interrupt_priority);
NRFX_IRQ_ENABLE(nrfx_get_irq_number((void *)p_instance->p_reg));
}
static void interrupts_disable(nrfx_uart_t const * p_instance)
{
nrf_uart_int_disable(p_instance->p_reg, NRF_UART_INT_MASK_RXDRDY |
NRF_UART_INT_MASK_TXDRDY |
NRF_UART_INT_MASK_ERROR |
NRF_UART_INT_MASK_RXTO);
NRFX_IRQ_DISABLE(nrfx_get_irq_number((void *)p_instance->p_reg));
}
static void pins_to_default(nrfx_uart_t const * p_instance)
{
/* Reset pins to default states */
uint32_t txd;
uint32_t rxd;
uint32_t rts;
uint32_t cts;
txd = nrf_uart_tx_pin_get(p_instance->p_reg);
rxd = nrf_uart_rx_pin_get(p_instance->p_reg);
rts = nrf_uart_rts_pin_get(p_instance->p_reg);
cts = nrf_uart_cts_pin_get(p_instance->p_reg);
nrf_uart_txrx_pins_disconnect(p_instance->p_reg);
nrf_uart_hwfc_pins_disconnect(p_instance->p_reg);
if (txd != NRF_UART_PSEL_DISCONNECTED)
{
nrf_gpio_cfg_default(txd);
}
if (rxd != NRF_UART_PSEL_DISCONNECTED)
{
nrf_gpio_cfg_default(rxd);
}
if (cts != NRF_UART_PSEL_DISCONNECTED)
{
nrf_gpio_cfg_default(cts);
}
if (rts != NRF_UART_PSEL_DISCONNECTED)
{
nrf_gpio_cfg_default(rts);
}
}
nrfx_err_t nrfx_uart_init(nrfx_uart_t const * p_instance,
nrfx_uart_config_t const * p_config,
nrfx_uart_event_handler_t event_handler)
{
NRFX_ASSERT(p_config);
uart_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
nrfx_err_t err_code = NRFX_SUCCESS;
if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
{
err_code = NRFX_ERROR_INVALID_STATE;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
#if NRFX_CHECK(NRFX_PRS_ENABLED)
static nrfx_irq_handler_t const irq_handlers[NRFX_UART_ENABLED_COUNT] = {
#if NRFX_CHECK(NRFX_UART0_ENABLED)
nrfx_uart_0_irq_handler,
#endif
};
if (nrfx_prs_acquire(p_instance->p_reg,
irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
{
err_code = NRFX_ERROR_BUSY;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
#endif // NRFX_CHECK(NRFX_PRS_ENABLED)
apply_config(p_instance, p_config);
p_cb->handler = event_handler;
p_cb->p_context = p_config->p_context;
if (p_cb->handler)
{
interrupts_enable(p_instance, p_config->interrupt_priority);
}
nrf_uart_enable(p_instance->p_reg);
p_cb->rx_buffer_length = 0;
p_cb->rx_secondary_buffer_length = 0;
p_cb->rx_enabled = false;
p_cb->tx_buffer_length = 0;
p_cb->state = NRFX_DRV_STATE_INITIALIZED;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
void nrfx_uart_uninit(nrfx_uart_t const * p_instance)
{
uart_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
nrf_uart_disable(p_instance->p_reg);
if (p_cb->handler)
{
interrupts_disable(p_instance);
}
pins_to_default(p_instance);
#if NRFX_CHECK(NRFX_PRS_ENABLED)
nrfx_prs_release(p_instance->p_reg);
#endif
p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
p_cb->handler = NULL;
NRFX_LOG_INFO("Instance uninitialized: %d.", p_instance->drv_inst_idx);
}
static void tx_byte(NRF_UART_Type * p_uart, uart_control_block_t * p_cb)
{
nrf_uart_event_clear(p_uart, NRF_UART_EVENT_TXDRDY);
uint8_t txd = p_cb->p_tx_buffer[p_cb->tx_counter];
p_cb->tx_counter++;
nrf_uart_txd_set(p_uart, txd);
}
static bool tx_blocking(NRF_UART_Type * p_uart, uart_control_block_t * p_cb)
{
// Use a local variable to avoid undefined order of accessing two volatile variables
// in one statement.
size_t const tx_buffer_length = p_cb->tx_buffer_length;
while (p_cb->tx_counter < tx_buffer_length)
{
// Wait until the transmitter is ready to accept a new byte.
// Exit immediately if the transfer has been aborted.
while (!nrf_uart_event_check(p_uart, NRF_UART_EVENT_TXDRDY))
{
if (p_cb->tx_abort)
{
return false;
}
}
tx_byte(p_uart, p_cb);
}
return true;
}
nrfx_err_t nrfx_uart_tx(nrfx_uart_t const * p_instance,
uint8_t const * p_data,
size_t length)
{
uart_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
NRFX_ASSERT(p_data);
NRFX_ASSERT(length > 0);
nrfx_err_t err_code;
if (nrfx_uart_tx_in_progress(p_instance))
{
err_code = NRFX_ERROR_BUSY;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
p_cb->tx_buffer_length = length;
p_cb->p_tx_buffer = p_data;
p_cb->tx_counter = 0;
p_cb->tx_abort = false;
NRFX_LOG_INFO("Transfer tx_len: %d.", p_cb->tx_buffer_length);
NRFX_LOG_DEBUG("Tx data:");
NRFX_LOG_HEXDUMP_DEBUG(p_cb->p_tx_buffer,
p_cb->tx_buffer_length * sizeof(p_cb->p_tx_buffer[0]));
err_code = NRFX_SUCCESS;
nrf_uart_event_clear(p_instance->p_reg, NRF_UART_EVENT_TXDRDY);
nrf_uart_task_trigger(p_instance->p_reg, NRF_UART_TASK_STARTTX);
tx_byte(p_instance->p_reg, p_cb);
if (p_cb->handler == NULL)
{
if (!tx_blocking(p_instance->p_reg, p_cb))
{
// The transfer has been aborted.
err_code = NRFX_ERROR_FORBIDDEN;
}
else
{
// Wait until the last byte is completely transmitted.
while (!nrf_uart_event_check(p_instance->p_reg, NRF_UART_EVENT_TXDRDY))
{}
nrf_uart_task_trigger(p_instance->p_reg, NRF_UART_TASK_STOPTX);
}
p_cb->tx_buffer_length = 0;
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
bool nrfx_uart_tx_in_progress(nrfx_uart_t const * p_instance)
{
return (m_cb[p_instance->drv_inst_idx].tx_buffer_length != 0);
}
static void rx_enable(nrfx_uart_t const * p_instance)
{
nrf_uart_event_clear(p_instance->p_reg, NRF_UART_EVENT_ERROR);
nrf_uart_event_clear(p_instance->p_reg, NRF_UART_EVENT_RXDRDY);
nrf_uart_task_trigger(p_instance->p_reg, NRF_UART_TASK_STARTRX);
}
static void rx_byte(NRF_UART_Type * p_uart, uart_control_block_t * p_cb)
{
if (!p_cb->rx_buffer_length)
{
nrf_uart_event_clear(p_uart, NRF_UART_EVENT_RXDRDY);
// Byte received when buffer is not set - data lost.
(void) nrf_uart_rxd_get(p_uart);
return;
}
nrf_uart_event_clear(p_uart, NRF_UART_EVENT_RXDRDY);
p_cb->p_rx_buffer[p_cb->rx_counter] = nrf_uart_rxd_get(p_uart);
p_cb->rx_counter++;
}
nrfx_err_t nrfx_uart_rx(nrfx_uart_t const * p_instance,
uint8_t * p_data,
size_t length)
{
uart_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state == NRFX_DRV_STATE_INITIALIZED);
NRFX_ASSERT(p_data);
NRFX_ASSERT(length > 0);
nrfx_err_t err_code;
bool second_buffer = false;
if (p_cb->handler)
{
nrf_uart_int_disable(p_instance->p_reg, NRF_UART_INT_MASK_RXDRDY |
NRF_UART_INT_MASK_ERROR);
}
if (p_cb->rx_buffer_length != 0)
{
if (p_cb->rx_secondary_buffer_length != 0)
{
if (p_cb->handler)
{
nrf_uart_int_enable(p_instance->p_reg, NRF_UART_INT_MASK_RXDRDY |
NRF_UART_INT_MASK_ERROR);
}
err_code = NRFX_ERROR_BUSY;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
second_buffer = true;
}
if (!second_buffer)
{
p_cb->rx_buffer_length = length;
p_cb->p_rx_buffer = p_data;
p_cb->rx_counter = 0;
p_cb->rx_secondary_buffer_length = 0;
}
else
{
p_cb->p_rx_secondary_buffer = p_data;
p_cb->rx_secondary_buffer_length = length;
}
NRFX_LOG_INFO("Transfer rx_len: %d.", length);
if ((!p_cb->rx_enabled) && (!second_buffer))
{
rx_enable(p_instance);
}
if (p_cb->handler == NULL)
{
nrf_uart_event_clear(p_instance->p_reg, NRF_UART_EVENT_RXTO);
bool rxrdy;
bool rxto;
bool error;
do
{
do
{
error = nrf_uart_event_check(p_instance->p_reg, NRF_UART_EVENT_ERROR);
rxrdy = nrf_uart_event_check(p_instance->p_reg, NRF_UART_EVENT_RXDRDY);
rxto = nrf_uart_event_check(p_instance->p_reg, NRF_UART_EVENT_RXTO);
} while ((!rxrdy) && (!rxto) && (!error));
if (error || rxto)
{
break;
}
rx_byte(p_instance->p_reg, p_cb);
} while (p_cb->rx_buffer_length > p_cb->rx_counter);
p_cb->rx_buffer_length = 0;
if (error)
{
err_code = NRFX_ERROR_INTERNAL;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
if (rxto)
{
err_code = NRFX_ERROR_FORBIDDEN;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
if (p_cb->rx_enabled)
{
nrf_uart_task_trigger(p_instance->p_reg, NRF_UART_TASK_STARTRX);
}
else
{
// Skip stopping RX if driver is forced to be enabled.
nrf_uart_task_trigger(p_instance->p_reg, NRF_UART_TASK_STOPRX);
}
}
else
{
nrf_uart_int_enable(p_instance->p_reg, NRF_UART_INT_MASK_RXDRDY |
NRF_UART_INT_MASK_ERROR);
}
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
bool nrfx_uart_rx_ready(nrfx_uart_t const * p_instance)
{
return nrf_uart_event_check(p_instance->p_reg, NRF_UART_EVENT_RXDRDY);
}
void nrfx_uart_rx_enable(nrfx_uart_t const * p_instance)
{
if (!m_cb[p_instance->drv_inst_idx].rx_enabled)
{
rx_enable(p_instance);
m_cb[p_instance->drv_inst_idx].rx_enabled = true;
}
}
void nrfx_uart_rx_disable(nrfx_uart_t const * p_instance)
{
nrf_uart_task_trigger(p_instance->p_reg, NRF_UART_TASK_STOPRX);
m_cb[p_instance->drv_inst_idx].rx_enabled = false;
}
uint32_t nrfx_uart_errorsrc_get(nrfx_uart_t const * p_instance)
{
nrf_uart_event_clear(p_instance->p_reg, NRF_UART_EVENT_ERROR);
return nrf_uart_errorsrc_get_and_clear(p_instance->p_reg);
}
static void rx_done_event(uart_control_block_t * p_cb,
size_t bytes,
uint8_t * p_data)
{
nrfx_uart_event_t event;
event.type = NRFX_UART_EVT_RX_DONE;
event.data.rxtx.bytes = bytes;
event.data.rxtx.p_data = p_data;
p_cb->handler(&event, p_cb->p_context);
}
static void tx_done_event(uart_control_block_t * p_cb,
size_t bytes)
{
nrfx_uart_event_t event;
event.type = NRFX_UART_EVT_TX_DONE;
event.data.rxtx.bytes = bytes;
event.data.rxtx.p_data = (uint8_t *)p_cb->p_tx_buffer;
p_cb->tx_buffer_length = 0;
p_cb->handler(&event, p_cb->p_context);
}
void nrfx_uart_tx_abort(nrfx_uart_t const * p_instance)
{
uart_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
p_cb->tx_abort = true;
nrf_uart_task_trigger(p_instance->p_reg, NRF_UART_TASK_STOPTX);
if (p_cb->handler)
{
tx_done_event(p_cb, p_cb->tx_counter);
}
NRFX_LOG_INFO("TX transaction aborted.");
}
void nrfx_uart_rx_abort(nrfx_uart_t const * p_instance)
{
nrf_uart_int_disable(p_instance->p_reg, NRF_UART_INT_MASK_RXDRDY |
NRF_UART_INT_MASK_ERROR);
nrf_uart_task_trigger(p_instance->p_reg, NRF_UART_TASK_STOPRX);
NRFX_LOG_INFO("RX transaction aborted.");
}
static void uart_irq_handler(NRF_UART_Type * p_uart,
uart_control_block_t * p_cb)
{
if (nrf_uart_int_enable_check(p_uart, NRF_UART_INT_MASK_ERROR) &&
nrf_uart_event_check(p_uart, NRF_UART_EVENT_ERROR))
{
nrfx_uart_event_t event;
nrf_uart_event_clear(p_uart, NRF_UART_EVENT_ERROR);
NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_UART_EVENT_ERROR));
nrf_uart_int_disable(p_uart, NRF_UART_INT_MASK_RXDRDY |
NRF_UART_INT_MASK_ERROR);
if (!p_cb->rx_enabled)
{
nrf_uart_task_trigger(p_uart, NRF_UART_TASK_STOPRX);
}
event.type = NRFX_UART_EVT_ERROR;
event.data.error.error_mask = nrf_uart_errorsrc_get_and_clear(p_uart);
event.data.error.rxtx.bytes = p_cb->rx_buffer_length;
event.data.error.rxtx.p_data = p_cb->p_rx_buffer;
// Abort transfer.
p_cb->rx_buffer_length = 0;
p_cb->rx_secondary_buffer_length = 0;
p_cb->handler(&event,p_cb->p_context);
}
else if (nrf_uart_int_enable_check(p_uart, NRF_UART_INT_MASK_RXDRDY) &&
nrf_uart_event_check(p_uart, NRF_UART_EVENT_RXDRDY))
{
rx_byte(p_uart, p_cb);
if (p_cb->rx_buffer_length == p_cb->rx_counter)
{
if (p_cb->rx_secondary_buffer_length)
{
uint8_t * p_data = p_cb->p_rx_buffer;
size_t rx_counter = p_cb->rx_counter;
// Switch to secondary buffer.
p_cb->rx_buffer_length = p_cb->rx_secondary_buffer_length;
p_cb->p_rx_buffer = p_cb->p_rx_secondary_buffer;
p_cb->rx_secondary_buffer_length = 0;
p_cb->rx_counter = 0;
rx_done_event(p_cb, rx_counter, p_data);
}
else
{
if (!p_cb->rx_enabled)
{
nrf_uart_task_trigger(p_uart, NRF_UART_TASK_STOPRX);
}
nrf_uart_int_disable(p_uart, NRF_UART_INT_MASK_RXDRDY |
NRF_UART_INT_MASK_ERROR);
p_cb->rx_buffer_length = 0;
rx_done_event(p_cb, p_cb->rx_counter, p_cb->p_rx_buffer);
}
}
}
if (nrf_uart_event_check(p_uart, NRF_UART_EVENT_TXDRDY))
{
// Use a local variable to avoid undefined order of accessing two volatile variables
// in one statement.
size_t const tx_buffer_length = p_cb->tx_buffer_length;
if (p_cb->tx_counter < tx_buffer_length && !p_cb->tx_abort)
{
tx_byte(p_uart, p_cb);
}
else
{
nrf_uart_event_clear(p_uart, NRF_UART_EVENT_TXDRDY);
if (p_cb->tx_buffer_length)
{
tx_done_event(p_cb, p_cb->tx_buffer_length);
}
}
}
if (nrf_uart_event_check(p_uart, NRF_UART_EVENT_RXTO))
{
nrf_uart_event_clear(p_uart, NRF_UART_EVENT_RXTO);
// RXTO event may be triggered as a result of abort call. In th
if (p_cb->rx_enabled)
{
nrf_uart_task_trigger(p_uart, NRF_UART_TASK_STARTRX);
}
if (p_cb->rx_buffer_length)
{
p_cb->rx_buffer_length = 0;
rx_done_event(p_cb, p_cb->rx_counter, p_cb->p_rx_buffer);
}
}
}
#if NRFX_CHECK(NRFX_UART0_ENABLED)
void nrfx_uart_0_irq_handler(void)
{
uart_irq_handler(NRF_UART0, &m_cb[NRFX_UART0_INST_IDX]);
}
#endif
#endif // NRFX_CHECK(NRFX_UART_ENABLED)
+702
View File
@@ -0,0 +1,702 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_UARTE_ENABLED)
#if !(NRFX_CHECK(NRFX_UARTE0_ENABLED) || \
NRFX_CHECK(NRFX_UARTE1_ENABLED) || \
NRFX_CHECK(NRFX_UARTE2_ENABLED) || \
NRFX_CHECK(NRFX_UARTE3_ENABLED))
#error "No enabled UARTE instances. Check <nrfx_config.h>."
#endif
#include <nrfx_uarte.h>
#include "prs/nrfx_prs.h"
#include <hal/nrf_gpio.h>
#define NRFX_LOG_MODULE UARTE
#include <nrfx_log.h>
#define EVT_TO_STR(event) \
(event == NRF_UARTE_EVENT_ERROR ? "NRF_UARTE_EVENT_ERROR" : \
"UNKNOWN EVENT")
#define UARTEX_LENGTH_VALIDATE(peripheral, drv_inst_idx, len1, len2) \
(((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \
NRFX_EASYDMA_LENGTH_VALIDATE(peripheral, len1, len2))
#if NRFX_CHECK(NRFX_UARTE0_ENABLED)
#define UARTE0_LENGTH_VALIDATE(...) UARTEX_LENGTH_VALIDATE(UARTE0, __VA_ARGS__)
#else
#define UARTE0_LENGTH_VALIDATE(...) 0
#endif
#if NRFX_CHECK(NRFX_UARTE1_ENABLED)
#define UARTE1_LENGTH_VALIDATE(...) UARTEX_LENGTH_VALIDATE(UARTE1, __VA_ARGS__)
#else
#define UARTE1_LENGTH_VALIDATE(...) 0
#endif
#if NRFX_CHECK(NRFX_UARTE2_ENABLED)
#define UARTE2_LENGTH_VALIDATE(...) UARTEX_LENGTH_VALIDATE(UARTE2, __VA_ARGS__)
#else
#define UARTE2_LENGTH_VALIDATE(...) 0
#endif
#if NRFX_CHECK(NRFX_UARTE3_ENABLED)
#define UARTE3_LENGTH_VALIDATE(...) UARTEX_LENGTH_VALIDATE(UARTE3, __VA_ARGS__)
#else
#define UARTE3_LENGTH_VALIDATE(...) 0
#endif
#define UARTE_LENGTH_VALIDATE(drv_inst_idx, length) \
(UARTE0_LENGTH_VALIDATE(drv_inst_idx, length, 0) || \
UARTE1_LENGTH_VALIDATE(drv_inst_idx, length, 0) || \
UARTE2_LENGTH_VALIDATE(drv_inst_idx, length, 0) || \
UARTE3_LENGTH_VALIDATE(drv_inst_idx, length, 0))
typedef struct
{
void * p_context;
nrfx_uarte_event_handler_t handler;
uint8_t const * p_tx_buffer;
uint8_t * p_rx_buffer;
uint8_t * p_rx_secondary_buffer;
volatile size_t tx_buffer_length;
size_t rx_buffer_length;
size_t rx_secondary_buffer_length;
nrfx_drv_state_t state;
} uarte_control_block_t;
static uarte_control_block_t m_cb[NRFX_UARTE_ENABLED_COUNT];
static void apply_config(nrfx_uarte_t const * p_instance,
nrfx_uarte_config_t const * p_config)
{
if (p_config->pseltxd != NRF_UARTE_PSEL_DISCONNECTED)
{
nrf_gpio_pin_set(p_config->pseltxd);
nrf_gpio_cfg_output(p_config->pseltxd);
}
if (p_config->pselrxd != NRF_UARTE_PSEL_DISCONNECTED)
{
nrf_gpio_cfg_input(p_config->pselrxd, NRF_GPIO_PIN_NOPULL);
}
nrf_uarte_baudrate_set(p_instance->p_reg, p_config->baudrate);
nrf_uarte_configure(p_instance->p_reg, p_config->parity, p_config->hwfc);
nrf_uarte_txrx_pins_set(p_instance->p_reg, p_config->pseltxd, p_config->pselrxd);
if (p_config->hwfc == NRF_UARTE_HWFC_ENABLED)
{
if (p_config->pselcts != NRF_UARTE_PSEL_DISCONNECTED)
{
nrf_gpio_cfg_input(p_config->pselcts, NRF_GPIO_PIN_NOPULL);
}
if (p_config->pselrts != NRF_UARTE_PSEL_DISCONNECTED)
{
nrf_gpio_pin_set(p_config->pselrts);
nrf_gpio_cfg_output(p_config->pselrts);
}
nrf_uarte_hwfc_pins_set(p_instance->p_reg, p_config->pselrts, p_config->pselcts);
}
}
static void interrupts_enable(nrfx_uarte_t const * p_instance,
uint8_t interrupt_priority)
{
nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ENDRX);
nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ENDTX);
nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ERROR);
nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_RXTO);
nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_TXSTOPPED);
nrf_uarte_int_enable(p_instance->p_reg, NRF_UARTE_INT_ENDRX_MASK |
NRF_UARTE_INT_ENDTX_MASK |
NRF_UARTE_INT_ERROR_MASK |
NRF_UARTE_INT_RXTO_MASK |
NRF_UARTE_INT_TXSTOPPED_MASK);
NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number((void *)p_instance->p_reg),
interrupt_priority);
NRFX_IRQ_ENABLE(nrfx_get_irq_number((void *)p_instance->p_reg));
}
static void interrupts_disable(nrfx_uarte_t const * p_instance)
{
nrf_uarte_int_disable(p_instance->p_reg, NRF_UARTE_INT_ENDRX_MASK |
NRF_UARTE_INT_ENDTX_MASK |
NRF_UARTE_INT_ERROR_MASK |
NRF_UARTE_INT_RXTO_MASK |
NRF_UARTE_INT_TXSTOPPED_MASK);
NRFX_IRQ_DISABLE(nrfx_get_irq_number((void *)p_instance->p_reg));
}
static void pins_to_default(nrfx_uarte_t const * p_instance)
{
/* Reset pins to default states */
uint32_t txd;
uint32_t rxd;
uint32_t rts;
uint32_t cts;
txd = nrf_uarte_tx_pin_get(p_instance->p_reg);
rxd = nrf_uarte_rx_pin_get(p_instance->p_reg);
rts = nrf_uarte_rts_pin_get(p_instance->p_reg);
cts = nrf_uarte_cts_pin_get(p_instance->p_reg);
nrf_uarte_txrx_pins_disconnect(p_instance->p_reg);
nrf_uarte_hwfc_pins_disconnect(p_instance->p_reg);
if (txd != NRF_UARTE_PSEL_DISCONNECTED)
{
nrf_gpio_cfg_default(txd);
}
if (rxd != NRF_UARTE_PSEL_DISCONNECTED)
{
nrf_gpio_cfg_default(rxd);
}
if (cts != NRF_UARTE_PSEL_DISCONNECTED)
{
nrf_gpio_cfg_default(cts);
}
if (rts != NRF_UARTE_PSEL_DISCONNECTED)
{
nrf_gpio_cfg_default(rts);
}
}
nrfx_err_t nrfx_uarte_init(nrfx_uarte_t const * p_instance,
nrfx_uarte_config_t const * p_config,
nrfx_uarte_event_handler_t event_handler)
{
NRFX_ASSERT(p_config);
uarte_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
nrfx_err_t err_code = NRFX_SUCCESS;
if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
{
err_code = NRFX_ERROR_INVALID_STATE;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
#if NRFX_CHECK(NRFX_PRS_ENABLED)
static nrfx_irq_handler_t const irq_handlers[NRFX_UARTE_ENABLED_COUNT] = {
#if NRFX_CHECK(NRFX_UARTE0_ENABLED)
nrfx_uarte_0_irq_handler,
#endif
#if NRFX_CHECK(NRFX_UARTE1_ENABLED)
nrfx_uarte_1_irq_handler,
#endif
#if NRFX_CHECK(NRFX_UARTE2_ENABLED)
nrfx_uarte_2_irq_handler,
#endif
#if NRFX_CHECK(NRFX_UARTE3_ENABLED)
nrfx_uarte_3_irq_handler,
#endif
};
if (nrfx_prs_acquire(p_instance->p_reg,
irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
{
err_code = NRFX_ERROR_BUSY;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
#endif // NRFX_CHECK(NRFX_PRS_ENABLED)
apply_config(p_instance, p_config);
#if defined(NRF5340_XXAA_APPLICATION) || defined(NRF5340_XXAA_NETWORK) || defined(NRF9160_XXAA)
// Apply workaround for anomalies:
// - nRF9160 - anomaly 23
// - nRF5340 - anomaly 44
volatile uint32_t const * rxenable_reg =
(volatile uint32_t *)(((uint32_t)p_instance->p_reg) + 0x564);
volatile uint32_t const * txenable_reg =
(volatile uint32_t *)(((uint32_t)p_instance->p_reg) + 0x568);
if (*txenable_reg == 1)
{
nrf_uarte_task_trigger(p_instance->p_reg, NRF_UARTE_TASK_STOPTX);
}
if (*rxenable_reg == 1)
{
nrf_uarte_enable(p_instance->p_reg);
nrf_uarte_task_trigger(p_instance->p_reg, NRF_UARTE_TASK_STOPRX);
while (*rxenable_reg)
{}
(void)nrf_uarte_errorsrc_get_and_clear(p_instance->p_reg);
nrf_uarte_disable(p_instance->p_reg);
}
#endif // defined(NRF5340_XXAA_APPLICATION) || defined(NRF5340_XXAA_NETWORK) || defined(NRF9160_XXAA)
p_cb->handler = event_handler;
p_cb->p_context = p_config->p_context;
if (p_cb->handler)
{
interrupts_enable(p_instance, p_config->interrupt_priority);
}
nrf_uarte_enable(p_instance->p_reg);
p_cb->rx_buffer_length = 0;
p_cb->rx_secondary_buffer_length = 0;
p_cb->tx_buffer_length = 0;
p_cb->state = NRFX_DRV_STATE_INITIALIZED;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
void nrfx_uarte_uninit(nrfx_uarte_t const * p_instance)
{
uarte_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRF_UARTE_Type * p_reg = p_instance->p_reg;
if (p_cb->handler)
{
interrupts_disable(p_instance);
}
// Make sure all transfers are finished before UARTE is disabled
// to achieve the lowest power consumption.
nrf_uarte_shorts_disable(p_reg, NRF_UARTE_SHORT_ENDRX_STARTRX);
// Check if there is any ongoing reception.
if (p_cb->rx_buffer_length)
{
nrf_uarte_event_clear(p_reg, NRF_UARTE_EVENT_RXTO);
nrf_uarte_task_trigger(p_reg, NRF_UARTE_TASK_STOPRX);
}
nrf_uarte_event_clear(p_reg, NRF_UARTE_EVENT_TXSTOPPED);
nrf_uarte_task_trigger(p_reg, NRF_UARTE_TASK_STOPTX);
// Wait for TXSTOPPED event and for RXTO event, provided that there was ongoing reception.
while (!nrf_uarte_event_check(p_reg, NRF_UARTE_EVENT_TXSTOPPED) ||
(p_cb->rx_buffer_length && !nrf_uarte_event_check(p_reg, NRF_UARTE_EVENT_RXTO)))
{}
nrf_uarte_disable(p_reg);
pins_to_default(p_instance);
#if NRFX_CHECK(NRFX_PRS_ENABLED)
nrfx_prs_release(p_reg);
#endif
p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
p_cb->handler = NULL;
NRFX_LOG_INFO("Instance uninitialized: %d.", p_instance->drv_inst_idx);
}
nrfx_err_t nrfx_uarte_tx(nrfx_uarte_t const * p_instance,
uint8_t const * p_data,
size_t length)
{
uarte_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
NRFX_ASSERT(p_data);
NRFX_ASSERT(length > 0);
NRFX_ASSERT(UARTE_LENGTH_VALIDATE(p_instance->drv_inst_idx, length));
nrfx_err_t err_code;
// EasyDMA requires that transfer buffers are placed in DataRAM,
// signal error if the are not.
if (!nrfx_is_in_ram(p_data))
{
err_code = NRFX_ERROR_INVALID_ADDR;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
if (nrfx_uarte_tx_in_progress(p_instance))
{
err_code = NRFX_ERROR_BUSY;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
p_cb->tx_buffer_length = length;
p_cb->p_tx_buffer = p_data;
NRFX_LOG_INFO("Transfer tx_len: %d.", p_cb->tx_buffer_length);
NRFX_LOG_DEBUG("Tx data:");
NRFX_LOG_HEXDUMP_DEBUG(p_cb->p_tx_buffer,
p_cb->tx_buffer_length * sizeof(p_cb->p_tx_buffer[0]));
err_code = NRFX_SUCCESS;
nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ENDTX);
nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_TXSTOPPED);
nrf_uarte_tx_buffer_set(p_instance->p_reg, p_cb->p_tx_buffer, p_cb->tx_buffer_length);
nrf_uarte_task_trigger(p_instance->p_reg, NRF_UARTE_TASK_STARTTX);
if (p_cb->handler == NULL)
{
bool endtx;
bool txstopped;
do
{
endtx = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_ENDTX);
txstopped = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_TXSTOPPED);
}
while ((!endtx) && (!txstopped));
if (txstopped)
{
err_code = NRFX_ERROR_FORBIDDEN;
}
else
{
// Transmitter has to be stopped by triggering the STOPTX task to achieve
// the lowest possible level of the UARTE power consumption.
nrf_uarte_task_trigger(p_instance->p_reg, NRF_UARTE_TASK_STOPTX);
while (!nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_TXSTOPPED))
{}
}
p_cb->tx_buffer_length = 0;
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
bool nrfx_uarte_tx_in_progress(nrfx_uarte_t const * p_instance)
{
return (m_cb[p_instance->drv_inst_idx].tx_buffer_length != 0);
}
nrfx_err_t nrfx_uarte_rx(nrfx_uarte_t const * p_instance,
uint8_t * p_data,
size_t length)
{
uarte_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state == NRFX_DRV_STATE_INITIALIZED);
NRFX_ASSERT(p_data);
NRFX_ASSERT(length > 0);
NRFX_ASSERT(UARTE_LENGTH_VALIDATE(p_instance->drv_inst_idx, length));
nrfx_err_t err_code;
// EasyDMA requires that transfer buffers are placed in DataRAM,
// signal error if the are not.
if (!nrfx_is_in_ram(p_data))
{
err_code = NRFX_ERROR_INVALID_ADDR;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
bool second_buffer = false;
if (p_cb->handler)
{
nrf_uarte_int_disable(p_instance->p_reg, NRF_UARTE_INT_ERROR_MASK |
NRF_UARTE_INT_ENDRX_MASK);
}
if (p_cb->rx_buffer_length != 0)
{
if (p_cb->rx_secondary_buffer_length != 0)
{
if (p_cb->handler)
{
nrf_uarte_int_enable(p_instance->p_reg, NRF_UARTE_INT_ERROR_MASK |
NRF_UARTE_INT_ENDRX_MASK);
}
err_code = NRFX_ERROR_BUSY;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
second_buffer = true;
}
if (!second_buffer)
{
p_cb->rx_buffer_length = length;
p_cb->p_rx_buffer = p_data;
p_cb->rx_secondary_buffer_length = 0;
}
else
{
p_cb->p_rx_secondary_buffer = p_data;
p_cb->rx_secondary_buffer_length = length;
}
NRFX_LOG_INFO("Transfer rx_len: %d.", length);
err_code = NRFX_SUCCESS;
nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ENDRX);
nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_RXTO);
nrf_uarte_rx_buffer_set(p_instance->p_reg, p_data, length);
if (!second_buffer)
{
nrf_uarte_task_trigger(p_instance->p_reg, NRF_UARTE_TASK_STARTRX);
}
else
{
nrf_uarte_shorts_enable(p_instance->p_reg, NRF_UARTE_SHORT_ENDRX_STARTRX);
}
if (m_cb[p_instance->drv_inst_idx].handler == NULL)
{
bool endrx;
bool rxto;
bool error;
do {
endrx = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_ENDRX);
rxto = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_RXTO);
error = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_ERROR);
} while ((!endrx) && (!rxto) && (!error));
m_cb[p_instance->drv_inst_idx].rx_buffer_length = 0;
if (error)
{
err_code = NRFX_ERROR_INTERNAL;
}
if (rxto)
{
err_code = NRFX_ERROR_FORBIDDEN;
}
}
else
{
nrf_uarte_int_enable(p_instance->p_reg, NRF_UARTE_INT_ERROR_MASK |
NRF_UARTE_INT_ENDRX_MASK);
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
bool nrfx_uarte_rx_ready(nrfx_uarte_t const * p_instance)
{
return nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_ENDRX);
}
uint32_t nrfx_uarte_errorsrc_get(nrfx_uarte_t const * p_instance)
{
nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ERROR);
return nrf_uarte_errorsrc_get_and_clear(p_instance->p_reg);
}
static void rx_done_event(uarte_control_block_t * p_cb,
size_t bytes,
uint8_t * p_data)
{
nrfx_uarte_event_t event;
event.type = NRFX_UARTE_EVT_RX_DONE;
event.data.rxtx.bytes = bytes;
event.data.rxtx.p_data = p_data;
p_cb->handler(&event, p_cb->p_context);
}
static void tx_done_event(uarte_control_block_t * p_cb,
size_t bytes)
{
nrfx_uarte_event_t event;
event.type = NRFX_UARTE_EVT_TX_DONE;
event.data.rxtx.bytes = bytes;
event.data.rxtx.p_data = (uint8_t *)p_cb->p_tx_buffer;
p_cb->tx_buffer_length = 0;
p_cb->handler(&event, p_cb->p_context);
}
void nrfx_uarte_tx_abort(nrfx_uarte_t const * p_instance)
{
uarte_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_TXSTOPPED);
nrf_uarte_task_trigger(p_instance->p_reg, NRF_UARTE_TASK_STOPTX);
if (p_cb->handler == NULL)
{
while (!nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_TXSTOPPED))
{}
}
NRFX_LOG_INFO("TX transaction aborted.");
}
void nrfx_uarte_rx_abort(nrfx_uarte_t const * p_instance)
{
uarte_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
// Short between ENDRX event and STARTRX task must be disabled before
// aborting transmission.
if (p_cb->rx_secondary_buffer_length != 0)
{
nrf_uarte_shorts_disable(p_instance->p_reg, NRF_UARTE_SHORT_ENDRX_STARTRX);
}
nrf_uarte_task_trigger(p_instance->p_reg, NRF_UARTE_TASK_STOPRX);
NRFX_LOG_INFO("RX transaction aborted.");
}
static void uarte_irq_handler(NRF_UARTE_Type * p_uarte,
uarte_control_block_t * p_cb)
{
if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_ERROR))
{
nrfx_uarte_event_t event;
nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_ERROR);
event.type = NRFX_UARTE_EVT_ERROR;
event.data.error.error_mask = nrf_uarte_errorsrc_get_and_clear(p_uarte);
event.data.error.rxtx.bytes = nrf_uarte_rx_amount_get(p_uarte);
event.data.error.rxtx.p_data = p_cb->p_rx_buffer;
// Abort transfer.
p_cb->rx_buffer_length = 0;
p_cb->rx_secondary_buffer_length = 0;
p_cb->handler(&event, p_cb->p_context);
}
else if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_ENDRX))
{
nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_ENDRX);
size_t amount = nrf_uarte_rx_amount_get(p_uarte);
// If the transfer was stopped before completion, amount of transfered bytes
// will not be equal to the buffer length. Interrupted transfer is ignored.
if (amount == p_cb->rx_buffer_length)
{
if (p_cb->rx_secondary_buffer_length != 0)
{
uint8_t * p_data = p_cb->p_rx_buffer;
nrf_uarte_shorts_disable(p_uarte, NRF_UARTE_SHORT_ENDRX_STARTRX);
p_cb->rx_buffer_length = p_cb->rx_secondary_buffer_length;
p_cb->p_rx_buffer = p_cb->p_rx_secondary_buffer;
p_cb->rx_secondary_buffer_length = 0;
rx_done_event(p_cb, amount, p_data);
}
else
{
p_cb->rx_buffer_length = 0;
rx_done_event(p_cb, amount, p_cb->p_rx_buffer);
}
}
}
if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_RXTO))
{
nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_RXTO);
if (p_cb->rx_buffer_length != 0)
{
p_cb->rx_buffer_length = 0;
// In case of using double-buffered reception both variables storing buffer length
// have to be cleared to prevent incorrect behaviour of the driver.
p_cb->rx_secondary_buffer_length = 0;
rx_done_event(p_cb, nrf_uarte_rx_amount_get(p_uarte), p_cb->p_rx_buffer);
}
}
if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_ENDTX))
{
nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_ENDTX);
// Transmitter has to be stopped by triggering STOPTX task to achieve
// the lowest possible level of the UARTE power consumption.
nrf_uarte_task_trigger(p_uarte, NRF_UARTE_TASK_STOPTX);
if (p_cb->tx_buffer_length != 0)
{
tx_done_event(p_cb, nrf_uarte_tx_amount_get(p_uarte));
}
}
if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_TXSTOPPED))
{
nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_TXSTOPPED);
if (p_cb->tx_buffer_length != 0)
{
tx_done_event(p_cb, nrf_uarte_tx_amount_get(p_uarte));
}
}
}
#if NRFX_CHECK(NRFX_UARTE0_ENABLED)
void nrfx_uarte_0_irq_handler(void)
{
uarte_irq_handler(NRF_UARTE0, &m_cb[NRFX_UARTE0_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_UARTE1_ENABLED)
void nrfx_uarte_1_irq_handler(void)
{
uarte_irq_handler(NRF_UARTE1, &m_cb[NRFX_UARTE1_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_UARTE2_ENABLED)
void nrfx_uarte_2_irq_handler(void)
{
uarte_irq_handler(NRF_UARTE2, &m_cb[NRFX_UARTE2_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_UARTE3_ENABLED)
void nrfx_uarte_3_irq_handler(void)
{
uarte_irq_handler(NRF_UARTE3, &m_cb[NRFX_UARTE3_INST_IDX]);
}
#endif
#endif // NRFX_CHECK(NRFX_UARTE_ENABLED)
+166
View File
@@ -0,0 +1,166 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_WDT_ENABLED)
#include <nrfx_wdt.h>
#define NRFX_LOG_MODULE WDT
#include <nrfx_log.h>
/**@brief WDT state. */
static nrfx_drv_state_t m_state;
/**@brief WDT alloc table. */
static uint8_t m_alloc_index;
#if !NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ)
/**@brief WDT event handler. */
static nrfx_wdt_event_handler_t m_wdt_event_handler;
/**@brief WDT interrupt handler. */
void nrfx_wdt_irq_handler(void)
{
if (nrf_wdt_event_check(NRF_WDT_EVENT_TIMEOUT))
{
m_wdt_event_handler();
nrf_wdt_event_clear(NRF_WDT_EVENT_TIMEOUT);
}
}
#endif
nrfx_err_t nrfx_wdt_init(nrfx_wdt_config_t const * p_config,
nrfx_wdt_event_handler_t wdt_event_handler)
{
NRFX_ASSERT(p_config);
nrfx_err_t err_code;
#if !NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ)
NRFX_ASSERT(wdt_event_handler != NULL);
m_wdt_event_handler = wdt_event_handler;
#else
NRFX_ASSERT(wdt_event_handler == NULL);
(void)wdt_event_handler;
#endif
if (m_state == NRFX_DRV_STATE_UNINITIALIZED)
{
m_state = NRFX_DRV_STATE_INITIALIZED;
}
else
{
err_code = NRFX_ERROR_INVALID_STATE;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrf_wdt_behaviour_set(p_config->behaviour);
uint64_t ticks = (p_config->reload_value * 32768ULL) / 1000;
NRFX_ASSERT(ticks <= UINT32_MAX);
nrf_wdt_reload_value_set((uint32_t) ticks);
#if !NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ)
NRFX_IRQ_PRIORITY_SET(WDT_IRQn, p_config->interrupt_priority);
NRFX_IRQ_ENABLE(WDT_IRQn);
#endif
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
void nrfx_wdt_enable(void)
{
NRFX_ASSERT(m_alloc_index != 0);
NRFX_ASSERT(m_state == NRFX_DRV_STATE_INITIALIZED);
#if !NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ)
nrf_wdt_int_enable(NRF_WDT_INT_TIMEOUT_MASK);
#endif
nrf_wdt_task_trigger(NRF_WDT_TASK_START);
m_state = NRFX_DRV_STATE_POWERED_ON;
NRFX_LOG_INFO("Enabled.");
}
void nrfx_wdt_feed(void)
{
NRFX_ASSERT(m_state == NRFX_DRV_STATE_POWERED_ON);
for (uint8_t i = 0; i < m_alloc_index; i++)
{
nrf_wdt_reload_request_set((nrf_wdt_rr_register_t)(NRF_WDT_RR0 + i));
}
}
nrfx_err_t nrfx_wdt_channel_alloc(nrfx_wdt_channel_id * p_channel_id)
{
nrfx_err_t result;
NRFX_ASSERT(p_channel_id);
NRFX_ASSERT(m_state == NRFX_DRV_STATE_INITIALIZED);
NRFX_CRITICAL_SECTION_ENTER();
if (m_alloc_index < NRF_WDT_CHANNEL_NUMBER)
{
*p_channel_id = (nrfx_wdt_channel_id)(NRF_WDT_RR0 + m_alloc_index);
m_alloc_index++;
nrf_wdt_reload_request_enable(*p_channel_id);
result = NRFX_SUCCESS;
}
else
{
result = NRFX_ERROR_NO_MEM;
}
NRFX_CRITICAL_SECTION_EXIT();
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(result));
return result;
}
void nrfx_wdt_channel_feed(nrfx_wdt_channel_id channel_id)
{
NRFX_ASSERT(m_state == NRFX_DRV_STATE_POWERED_ON);
nrf_wdt_reload_request_set(channel_id);
}
#endif // NRFX_CHECK(NRFX_WDT_ENABLED)
+166
View File
@@ -0,0 +1,166 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_PRS_ENABLED)
#include "nrfx_prs.h"
#define NRFX_LOG_MODULE PRS
#include <nrfx_log.h>
#define LOG_FUNCTION_EXIT(level, ret_code) \
NRFX_LOG_##level("Function: %s, error code: %s.", \
__func__, \
NRFX_LOG_ERROR_STRING_GET(ret_code))
typedef struct {
nrfx_irq_handler_t handler;
bool acquired;
} prs_box_t;
#define PRS_BOX_DEFINE(n) \
static prs_box_t m_prs_box_##n = { .handler = NULL, .acquired = false }; \
void nrfx_prs_box_##n##_irq_handler(void) \
{ \
NRFX_ASSERT(m_prs_box_##n.handler); \
m_prs_box_##n.handler(); \
}
#if defined(NRFX_PRS_BOX_0_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_0_ENABLED)
PRS_BOX_DEFINE(0)
#endif
#if defined(NRFX_PRS_BOX_1_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_1_ENABLED)
PRS_BOX_DEFINE(1)
#endif
#if defined(NRFX_PRS_BOX_2_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_2_ENABLED)
PRS_BOX_DEFINE(2)
#endif
#if defined(NRFX_PRS_BOX_3_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_3_ENABLED)
PRS_BOX_DEFINE(3)
#endif
#if defined(NRFX_PRS_BOX_4_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_4_ENABLED)
PRS_BOX_DEFINE(4)
#endif
static prs_box_t * prs_box_get(void const * p_base_addr)
{
#if !defined(IS_PRS_BOX)
#define IS_PRS_BOX(n, p_base_addr) ((p_base_addr) == NRFX_PRS_BOX_##n##_ADDR)
#endif
#if defined(NRFX_PRS_BOX_0_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_0_ENABLED)
if (IS_PRS_BOX(0, p_base_addr)) { return &m_prs_box_0; }
else
#endif
#if defined(NRFX_PRS_BOX_1_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_1_ENABLED)
if (IS_PRS_BOX(1, p_base_addr)) { return &m_prs_box_1; }
else
#endif
#if defined(NRFX_PRS_BOX_2_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_2_ENABLED)
if (IS_PRS_BOX(2, p_base_addr)) { return &m_prs_box_2; }
else
#endif
#if defined(NRFX_PRS_BOX_3_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_3_ENABLED)
if (IS_PRS_BOX(3, p_base_addr)) { return &m_prs_box_3; }
else
#endif
#if defined(NRFX_PRS_BOX_4_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_4_ENABLED)
if (IS_PRS_BOX(4, p_base_addr)) { return &m_prs_box_4; }
else
#endif
{
return NULL;
}
}
nrfx_err_t nrfx_prs_acquire(void const * p_base_addr,
nrfx_irq_handler_t irq_handler)
{
NRFX_ASSERT(p_base_addr);
nrfx_err_t ret_code;
prs_box_t * p_box = prs_box_get(p_base_addr);
if (p_box != NULL)
{
bool busy = false;
NRFX_CRITICAL_SECTION_ENTER();
if (p_box->acquired)
{
busy = true;
}
else
{
p_box->handler = irq_handler;
p_box->acquired = true;
}
NRFX_CRITICAL_SECTION_EXIT();
if (busy)
{
ret_code = NRFX_ERROR_BUSY;
LOG_FUNCTION_EXIT(WARNING, ret_code);
return ret_code;
}
}
ret_code = NRFX_SUCCESS;
LOG_FUNCTION_EXIT(INFO, ret_code);
return ret_code;
}
void nrfx_prs_release(void const * p_base_addr)
{
NRFX_ASSERT(p_base_addr);
prs_box_t * p_box = prs_box_get(p_base_addr);
if (p_box != NULL)
{
p_box->handler = NULL;
p_box->acquired = false;
}
}
#endif // NRFX_CHECK(NRFX_PRS_ENABLED)
+155
View File
@@ -0,0 +1,155 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_PRS_H__
#define NRFX_PRS_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_prs Peripheral Resource Sharing (PRS)
* @{
* @ingroup nrfx
*
* @brief Peripheral Resource Sharing interface (PRS).
*/
#if defined(NRF51)
// SPI0, TWI0
#define NRFX_PRS_BOX_0_ADDR NRF_SPI0
// SPI1, SPIS1, TWI1
#define NRFX_PRS_BOX_1_ADDR NRF_SPI1
#elif defined(NRF52810_XXAA)
// TWIM0, TWIS0, TWI0
#define NRFX_PRS_BOX_0_ADDR NRF_TWIM0
// SPIM0, SPIS0, SPI0
#define NRFX_PRS_BOX_1_ADDR NRF_SPIM0
// UARTE0, UART0
#define NRFX_PRS_BOX_2_ADDR NRF_UARTE0
#elif defined(NRF52811_XXAA)
// TWIM0, TWIS0, TWI0, SPIM1, SPIS1, SPI1
#define NRFX_PRS_BOX_0_ADDR NRF_TWIM0
// SPIM0, SPIS0, SPI0
#define NRFX_PRS_BOX_1_ADDR NRF_SPIM0
// UART0, UARTE0
#define NRFX_PRS_BOX_2_ADDR NRF_UART0
#elif defined(NRF52820_XXAA)
// SPIM0, SPIS0, TWIM0, TWIS0, SPI0, TWI0
#define NRFX_PRS_BOX_0_ADDR NRF_SPIM0
// SPIM1, SPIS1, TWIM1, TWIS1, SPI1, TWI1
#define NRFX_PRS_BOX_1_ADDR NRF_SPIM1
// UARTE0, UART0
#define NRFX_PRS_BOX_2_ADDR NRF_UARTE0
#elif defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || \
defined(NRF52833_XXAA) || defined(NRF52840_XXAA)
// SPIM0, SPIS0, TWIM0, TWIS0, SPI0, TWI0
#define NRFX_PRS_BOX_0_ADDR NRF_SPIM0
// SPIM1, SPIS1, TWIM1, TWIS1, SPI1, TWI1
#define NRFX_PRS_BOX_1_ADDR NRF_SPIM1
// SPIM2, SPIS2, SPI2
#define NRFX_PRS_BOX_2_ADDR NRF_SPIM2
// COMP, LPCOMP
#define NRFX_PRS_BOX_3_ADDR NRF_COMP
// UARTE0, UART0
#define NRFX_PRS_BOX_4_ADDR NRF_UARTE0
#elif defined(NRF9160_XXAA)
// UARTE0, SPIM0, SPIS0, TWIM0, TWIS0
#define NRFX_PRS_BOX_0_ADDR NRF_UARTE0
// UARTE1, SPIM1, SPIS1, TWIM1, TWIS1
#define NRFX_PRS_BOX_1_ADDR NRF_UARTE1
// UARTE2, SPIM2, SPIS2, TWIM2, TWIS2
#define NRFX_PRS_BOX_2_ADDR NRF_UARTE2
// UARTE3, SPIM3, SPIS3, TWIM3, TWIS3
#define NRFX_PRS_BOX_3_ADDR NRF_UARTE3
#else
#error "Unknown device."
#endif
/**
* @brief Function for acquiring shared peripheral resources associated with
* the specified peripheral.
*
* Certain resources and registers are shared among peripherals that have
* the same ID (for example: SPI0, SPIM0, SPIS0, TWI0, TWIM0, and TWIS0 in
* nRF52832). Only one of them can be utilized at a given time. This function
* reserves proper resources to be used by the specified peripheral.
* If NRFX_PRS_ENABLED is set to a non-zero value, IRQ handlers for peripherals
* that are sharing resources with others are implemented by the @ref nrfx_prs
* module instead of individual drivers. The drivers must then specify their
* interrupt handling routines and register them by using this function.
*
* @param[in] p_base_addr Requested peripheral base pointer.
* @param[in] irq_handler Interrupt handler to register.
*
* @retval NRFX_SUCCESS If resources were acquired successfully or the
* specified peripheral is not handled by the PRS
* subsystem and there is no need to acquire resources
* for it.
* @retval NRFX_ERROR_BUSY If resources were already acquired.
*/
nrfx_err_t nrfx_prs_acquire(void const * p_base_addr,
nrfx_irq_handler_t irq_handler);
/**
* @brief Function for releasing shared resources reserved previously by
* @ref nrfx_prs_acquire() for the specified peripheral.
*
* @param[in] p_base_addr Released peripheral base pointer.
*/
void nrfx_prs_release(void const * p_base_addr);
/** @} */
void nrfx_prs_box_0_irq_handler(void);
void nrfx_prs_box_1_irq_handler(void);
void nrfx_prs_box_2_irq_handler(void);
void nrfx_prs_box_3_irq_handler(void);
void nrfx_prs_box_4_irq_handler(void);
#ifdef __cplusplus
}
#endif
#endif // NRFX_PRS_H__
+385
View File
@@ -0,0 +1,385 @@
/**
* Copyright (c) 2019 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_AAR_H__
#define NRF_AAR_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_aar_hal AAR HAL
* @{
* @ingroup nrf_aar
* @brief Hardware access layer for managing the Accelerated Address Resolver (AAR) peripheral.
*/
/** @brief AAR events. */
typedef enum
{
NRF_AAR_EVENT_END = offsetof(NRF_AAR_Type, EVENTS_END), ///< Address resolution procedure complete.
NRF_AAR_EVENT_RESOLVED = offsetof(NRF_AAR_Type, EVENTS_RESOLVED), ///< Address resolved.
NRF_AAR_EVENT_NOTRESOLVED = offsetof(NRF_AAR_Type, EVENTS_NOTRESOLVED), ///< Address not resolved.
} nrf_aar_event_t;
/** @brief AAR interrupts. */
typedef enum
{
NRF_AAR_INT_END_MASK = AAR_INTENSET_END_Msk, ///< Interrupt on END event.
NRF_AAR_INT_RESOLVED_MASK = AAR_INTENSET_RESOLVED_Msk, ///< Interrupt on RESOLVED event.
NRF_AAR_INT_NOTRESOLVED_MASK = AAR_INTENSET_NOTRESOLVED_Msk, ///< Interrupt on NOTRESOLVED event.
} nrf_aar_int_mask_t;
/** @brief AAR tasks. */
typedef enum
{
NRF_AAR_TASK_START = offsetof(NRF_AAR_Type, TASKS_START), ///< Start address resolution procedure.
NRF_AAR_TASK_STOP = offsetof(NRF_AAR_Type, TASKS_STOP), ///< Stop address resolution procedure.
} nrf_aar_task_t;
/**
* @brief Function for retrieving the state of the AAR event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be checked.
*
* @retval true Event is set.
* @retval false Event is not set.
*/
__STATIC_INLINE bool nrf_aar_event_check(NRF_AAR_Type const * p_reg,
nrf_aar_event_t event);
/**
* @brief Function for clearing the specified AAR event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be cleared.
*/
__STATIC_INLINE void nrf_aar_event_clear(NRF_AAR_Type * p_reg,
nrf_aar_event_t event);
/**
* @brief Function for getting the address of the specified AAR event register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to get the address of.
*
* @return Address of the specified event register.
*/
__STATIC_INLINE uint32_t nrf_aar_event_address_get(NRF_AAR_Type const * p_reg,
nrf_aar_event_t event);
/**
* @brief Function for enabling the specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of interrupts to be enabled.
*/
__STATIC_INLINE void nrf_aar_int_enable(NRF_AAR_Type * p_reg, uint32_t mask);
/**
* @brief Function for retrieving the state of the specified interrupt.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of the interrupt to be checked.
*
* @retval true Interrupt is enabled.
* @retval false Interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_aar_int_enable_check(NRF_AAR_Type const * p_reg,
nrf_aar_int_mask_t mask);
/**
* @brief Function for disabling the specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of interrupts to be disabled.
*/
__STATIC_INLINE void nrf_aar_int_disable(NRF_AAR_Type * p_reg, uint32_t mask);
/**
* @brief Function for starting an AAR task.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param task Task to be activated.
*/
__STATIC_INLINE void nrf_aar_task_trigger(NRF_AAR_Type * p_reg, nrf_aar_task_t task);
/**
* @brief Function for getting the address of a specific AAR task register.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param task Requested AAR task.
*
* @return Address of the specified task register.
*/
__STATIC_INLINE uint32_t nrf_aar_task_address_get(NRF_AAR_Type const * p_reg,
nrf_aar_task_t task);
/**
* @brief Function for enabling AAR.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_aar_enable(NRF_AAR_Type * p_reg);
/**
* @brief Function for disabling AAR.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_aar_disable(NRF_AAR_Type * p_reg);
/**
* @brief Function for setting the pointer to the Identity Resolving Keys (IRK) data structure.
*
* The size of the provided data structure must correspond to the number of keys available.
* Each key occupies 16 bytes.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param irk_ptr Pointer to the IRK data structure. Must point to the Data RAM region.
*
* @sa nrf_aar_irk_number_set
*/
__STATIC_INLINE void nrf_aar_irk_pointer_set(NRF_AAR_Type * p_reg, uint8_t const * irk_ptr);
/**
* @brief Function for getting the pointer to the Identity Resolving Keys
* data structure.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return Pointer to the IRK data structure.
*/
__STATIC_INLINE uint8_t const * nrf_aar_irk_pointer_get(NRF_AAR_Type const * p_reg);
/**
* @brief Function for setting the number of keys available in the Identity Resolving Keys
* data structure.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param irk_num Number of keys available in the IRK data structure. Maximum is 16.
* Must correspond to the size of the provided IRK data structure.
*
* @sa nrf_aar_irk_pointer_set
*/
__STATIC_INLINE void nrf_aar_irk_number_set(NRF_AAR_Type * p_reg, uint8_t irk_num);
/**
* @brief Function for getting the number of keys available in the Identity Resolving Keys
* data structure.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return Number of keys in the IRK data structure.
*/
__STATIC_INLINE uint8_t nrf_aar_irk_number_get(NRF_AAR_Type const * p_reg);
/**
* @brief Function for setting the pointer to the resolvable address.
*
* The resolvable address must consist of 6 bytes.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param addr_ptr Pointer to the address to resolve using the available IRK keys.
* Must point to the Data RAM region.
*/
__STATIC_INLINE void nrf_aar_addr_pointer_set(NRF_AAR_Type * p_reg, uint8_t const * addr_ptr);
/**
* @brief Function for getting the pointer to the resolvable address.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return Pointer to the address to resolve.
*/
__STATIC_INLINE uint8_t const * nrf_aar_addr_pointer_get(NRF_AAR_Type const * p_reg);
/**
* @brief Function for setting the pointer to the scratch data area.
*
* The scratch data area is used for temporary storage during the address resolution procedure.
* A space of minimum 3 bytes must be reserved for the scratch data area.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param scratch_ptr Pointer to the scratch data area. Must point to the Data RAM region.
*/
__STATIC_INLINE void nrf_aar_scratch_pointer_set(NRF_AAR_Type * p_reg, uint8_t * scratch_ptr);
/**
* @brief Function for getting the pointer to the scratch data area.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return Pointer to the scratch data area.
*/
__STATIC_INLINE uint8_t * nrf_aar_scratch_pointer_get(NRF_AAR_Type const * p_reg);
/**
* @brief Function for getting the index of the Identity Resolving Key that was used
* the last time an address was resolved.
*
* This function can be used to get the IRK index that matched the resolvable address,
* provided that @ref NRF_AAR_EVENT_RESOLVED occured. Otherwise, it will return
* the index of the last IRK stored in the IRK data structure.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return The index of the IRK that was used the last time an address was resolved.
*/
__STATIC_INLINE uint8_t nrf_aar_resolution_status_get(NRF_AAR_Type const * p_reg);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE bool nrf_aar_event_check(NRF_AAR_Type const * p_reg,
nrf_aar_event_t aar_event)
{
return (bool)*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)aar_event);
}
__STATIC_INLINE void nrf_aar_event_clear(NRF_AAR_Type * p_reg,
nrf_aar_event_t aar_event)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)aar_event)) = 0;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)aar_event));
(void)dummy;
#endif
}
__STATIC_INLINE uint32_t nrf_aar_event_address_get(NRF_AAR_Type const * p_reg,
nrf_aar_event_t aar_event)
{
return (uint32_t)((uint8_t *)p_reg + (uint32_t)aar_event);
}
__STATIC_INLINE void nrf_aar_int_enable(NRF_AAR_Type * p_reg, uint32_t mask)
{
p_reg->INTENSET = mask;
}
__STATIC_INLINE bool nrf_aar_int_enable_check(NRF_AAR_Type const * p_reg,
nrf_aar_int_mask_t mask)
{
return (bool)(p_reg->INTENSET & mask);
}
__STATIC_INLINE void nrf_aar_int_disable(NRF_AAR_Type * p_reg, uint32_t mask)
{
p_reg->INTENCLR = mask;
}
__STATIC_INLINE void nrf_aar_task_trigger(NRF_AAR_Type * p_reg, nrf_aar_task_t task)
{
*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)task) = 1;
}
__STATIC_INLINE uint32_t nrf_aar_task_address_get(NRF_AAR_Type const * p_reg,
nrf_aar_task_t task)
{
return (uint32_t)((uint8_t *)p_reg + (uint32_t)task);
}
__STATIC_INLINE void nrf_aar_enable(NRF_AAR_Type * p_reg)
{
p_reg->ENABLE = AAR_ENABLE_ENABLE_Enabled << AAR_ENABLE_ENABLE_Pos;
}
__STATIC_INLINE void nrf_aar_disable(NRF_AAR_Type * p_reg)
{
p_reg->ENABLE = AAR_ENABLE_ENABLE_Disabled << AAR_ENABLE_ENABLE_Pos;
}
__STATIC_INLINE void nrf_aar_irk_pointer_set(NRF_AAR_Type * p_reg, uint8_t const * irk_ptr)
{
p_reg->IRKPTR = (uint32_t)irk_ptr;
}
__STATIC_INLINE uint8_t const * nrf_aar_irk_pointer_get(NRF_AAR_Type const * p_reg)
{
return (uint8_t const *)(p_reg->IRKPTR);
}
__STATIC_INLINE void nrf_aar_irk_number_set(NRF_AAR_Type * p_reg, uint8_t irk_num)
{
p_reg->NIRK = irk_num;
}
__STATIC_INLINE uint8_t nrf_aar_irk_number_get(NRF_AAR_Type const * p_reg)
{
return (uint8_t)(p_reg->NIRK);
}
__STATIC_INLINE void nrf_aar_addr_pointer_set(NRF_AAR_Type * p_reg, uint8_t const * addr_ptr)
{
p_reg->ADDRPTR = (uint32_t)addr_ptr;
}
__STATIC_INLINE uint8_t const * nrf_aar_addr_pointer_get(NRF_AAR_Type const * p_reg)
{
return (uint8_t const *)(p_reg->ADDRPTR);
}
__STATIC_INLINE void nrf_aar_scratch_pointer_set(NRF_AAR_Type * p_reg, uint8_t * scratch_ptr)
{
p_reg->SCRATCHPTR = (uint32_t)scratch_ptr;
}
__STATIC_INLINE uint8_t * nrf_aar_scratch_pointer_get(NRF_AAR_Type const * p_reg)
{
return (uint8_t *)(p_reg->SCRATCHPTR);
}
__STATIC_INLINE uint8_t nrf_aar_resolution_status_get(NRF_AAR_Type const * p_reg)
{
return (uint8_t)(p_reg->STATUS);
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_AAR_H__
+155
View File
@@ -0,0 +1,155 @@
/**
* Copyright (c) 2018 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_ACL_H__
#define NRF_ACL_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
#define NRF_ACL_REGION_SIZE_MAX (512 * 1024UL)
/**
* @defgroup nrf_acl_hal ACL HAL
* @{
* @ingroup nrf_acl
* @brief Hardware access layer for managing the Access Control List (ACL) peripheral.
*/
/** @brief ACL permissions. */
typedef enum
{
NRF_ACL_PERM_READ_NO_WRITE = ACL_ACL_PERM_WRITE_Msk, /**< Read allowed, write disallowed. */
NRF_ACL_PERM_NO_READ_WRITE = ACL_ACL_PERM_READ_Msk, /**< Read disallowed, write allowed. */
NRF_ACL_PERM_NO_READ_NO_WRITE = ACL_ACL_PERM_READ_Msk | ACL_ACL_PERM_WRITE_Msk /**< Read disallowed, write disallowed. */
} nrf_acl_perm_t;
/**
* @brief Function for setting region parameters for given ACL region.
*
* Address must be word and page aligned. Size must be page aligned.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] region_id ACL region index.
* @param[in] address Start address.
* @param[in] size Size of region to protect in bytes.
* @param[in] perm Permissions to set for region to protect.
*/
__STATIC_INLINE void nrf_acl_region_set(NRF_ACL_Type * p_reg,
uint32_t region_id,
uint32_t address,
size_t size,
nrf_acl_perm_t perm);
/**
* @brief Function for getting the configured region address of a specific ACL region.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] region_id ACL region index.
*
* @return Configured region address of given ACL region.
*/
__STATIC_INLINE uint32_t nrf_acl_region_address_get(NRF_ACL_Type * p_reg, uint32_t region_id);
/**
* @brief Function for getting the configured region size of a specific ACL region.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] region_id ACL region index.
*
* @return Configured region size of given ACL region.
*/
__STATIC_INLINE size_t nrf_acl_region_size_get(NRF_ACL_Type * p_reg, uint32_t region_id);
/**
* @brief Function for getting the configured region permissions of a specific ACL region.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] region_id ACL region index.
*
* @return Configured region permissions of given ACL region.
*/
__STATIC_INLINE nrf_acl_perm_t nrf_acl_region_perm_get(NRF_ACL_Type * p_reg, uint32_t region_id);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_acl_region_set(NRF_ACL_Type * p_reg,
uint32_t region_id,
uint32_t address,
size_t size,
nrf_acl_perm_t perm)
{
NRFX_ASSERT(region_id < ACL_REGIONS_COUNT);
NRFX_ASSERT(address % NRF_FICR->CODEPAGESIZE == 0);
NRFX_ASSERT(size <= NRF_ACL_REGION_SIZE_MAX);
NRFX_ASSERT(size != 0);
p_reg->ACL[region_id].ADDR = address;
p_reg->ACL[region_id].SIZE = size;
p_reg->ACL[region_id].PERM = perm;
}
__STATIC_INLINE uint32_t nrf_acl_region_address_get(NRF_ACL_Type * p_reg, uint32_t region_id)
{
return (uint32_t)p_reg->ACL[region_id].ADDR;
}
__STATIC_INLINE size_t nrf_acl_region_size_get(NRF_ACL_Type * p_reg, uint32_t region_id)
{
return (size_t)p_reg->ACL[region_id].SIZE;
}
__STATIC_INLINE nrf_acl_perm_t nrf_acl_region_perm_get(NRF_ACL_Type * p_reg, uint32_t region_id)
{
return (nrf_acl_perm_t)p_reg->ACL[region_id].PERM;
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_ACL_H__
+134
View File
@@ -0,0 +1,134 @@
/**
* Copyright (c) 2019 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_BPROT_H__
#define NRF_BPROT_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_bprot_hal BPROT HAL
* @{
* @ingroup nrf_bprot
* @brief Hardware access layer for managing the Block Protection (BPROT) mechanism.
*/
/**
* @brief Function for enabling protection for specified non-volatile memory blocks.
*
* Blocks are arranged into groups of 32 blocks each. Each block size is 4 kB.
* Any attempt to write or erase a protected block will result in hard fault.
* The memory block protection can be disabled only by resetting the device.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] group_idx Non-volatile memory group containing memory blocks to protect.
* @param[in] block_mask Non-volatile memory blocks to protect. Each bit in bitmask represents
* one memory block in the specified group.
*/
__STATIC_INLINE void nrf_bprot_nvm_blocks_protection_enable(NRF_BPROT_Type * p_reg,
uint8_t group_idx,
uint32_t block_mask);
/**
* @brief Function for setting the non-volatile memory (NVM) protection during debug.
*
* NVM protection is disabled by default while debugging.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] enable True if NVM protection during debug is to be enabled.
* False if otherwise.
*/
__STATIC_INLINE void nrf_bprot_nvm_protection_in_debug_set(NRF_BPROT_Type * p_reg,
bool enable);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_bprot_nvm_blocks_protection_enable(NRF_BPROT_Type * p_reg,
uint8_t group_idx,
uint32_t block_mask)
{
switch (group_idx)
{
case 0:
p_reg->CONFIG0 = block_mask;
break;
case 1:
p_reg->CONFIG1 = block_mask;
break;
#if defined(BPROT_CONFIG2_REGION64_Pos)
case 2:
p_reg->CONFIG2 = block_mask;
break;
#endif
#if defined(BPROT_CONFIG3_REGION96_Pos)
case 3:
p_reg->CONFIG3 = block_mask;
break;
#endif
default:
NRFX_ASSERT(false);
break;
}
}
__STATIC_INLINE void nrf_bprot_nvm_protection_in_debug_set(NRF_BPROT_Type * p_reg,
bool enable)
{
p_reg->DISABLEINDEBUG =
(enable ? 0 : BPROT_DISABLEINDEBUG_DISABLEINDEBUG_Msk);
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_BPROT_H__
+488
View File
@@ -0,0 +1,488 @@
/**
* Copyright (c) 2018 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_CCM_H__
#define NRF_CCM_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_ccm_hal AES CCM HAL
* @{
* @ingroup nrf_ccm
* @brief Hardware access layer for managing the AES CCM peripheral.
*/
/** @brief CCM tasks. */
typedef enum
{
NRF_CCM_TASK_KSGEN = offsetof(NRF_CCM_Type, TASKS_KSGEN), ///< Start generation of key-stream.
NRF_CCM_TASK_CRYPT = offsetof(NRF_CCM_Type, TASKS_CRYPT), ///< Start encryption/decryption.
NRF_CCM_TASK_STOP = offsetof(NRF_CCM_Type, TASKS_STOP), ///< Stop encryption/decryption.
#if defined(CCM_RATEOVERRIDE_RATEOVERRIDE_Pos) || defined(__NRFX_DOXYGEN__)
NRF_CCM_TASK_RATEOVERRIDE = offsetof(NRF_CCM_Type, TASKS_RATEOVERRIDE), ///< Override DATARATE setting in MODE register.
#endif
} nrf_ccm_task_t;
/** @brief CCM events. */
typedef enum
{
NRF_CCM_EVENT_ENDKSGEN = offsetof(NRF_CCM_Type, EVENTS_ENDKSGEN), ///< Keystream generation complete.
NRF_CCM_EVENT_ENDCRYPT = offsetof(NRF_CCM_Type, EVENTS_ENDCRYPT), ///< Encrypt/decrypt complete.
NRF_CCM_EVENT_ERROR = offsetof(NRF_CCM_Type, EVENTS_ERROR), ///< CCM error event.
} nrf_ccm_event_t;
/** @brief CCM interrupts. */
typedef enum
{
NRF_CCM_INT_ENDKSGEN_MASK = CCM_INTENSET_ENDKSGEN_Msk, ///< Interrupt on ENDKSGEN event.
NRF_CCM_INT_ENDCRYPT_MASK = CCM_INTENSET_ENDCRYPT_Msk, ///< Interrupt on ENDCRYPT event.
NRF_CCM_INT_ERROR_MASK = CCM_INTENSET_ERROR_Msk, ///< Interrupt on ERROR event.
} nrf_ccm_int_mask_t;
/** @brief CCM modes of operation. */
typedef enum
{
NRF_CCM_MODE_ENCRYPTION = CCM_MODE_MODE_Encryption, ///< Encryption mode.
NRF_CCM_MODE_DECRYPTION = CCM_MODE_MODE_Decryption, ///< Decryption mode.
} nrf_ccm_mode_t;
#if defined(CCM_MODE_DATARATE_Pos) || defined(__NRFX_DOXYGEN__)
/** @brief CCM data rates. */
typedef enum
{
NRF_CCM_DATARATE_1M = CCM_MODE_DATARATE_1Mbit, ///< 1 Mbps.
NRF_CCM_DATARATE_2M = CCM_MODE_DATARATE_2Mbit, ///< 2 Mbps.
#if defined(CCM_MODE_DATARATE_125Kbps) || defined(__NRFX_DOXYGEN__)
NRF_CCM_DATARATE_125K = CCM_MODE_DATARATE_125Kbps, ///< 125 Kbps.
#endif
#if defined(CCM_MODE_DATARATE_500Kbps) || defined(__NRFX_DOXYGEN__)
NRF_CCM_DATARATE_500K = CCM_MODE_DATARATE_500Kbps, ///< 500 Kbps.
#endif
} nrf_ccm_datarate_t;
#endif // defined(CCM_MODE_DATARATE_Pos) || defined(__NRFX_DOXYGEN__)
#if defined(CCM_MODE_LENGTH_Pos) || defined(__NRFX_DOXYGEN__)
/** @brief CCM packet length options. */
typedef enum
{
NRF_CCM_LENGTH_DEFAULT = CCM_MODE_LENGTH_Default, ///< Default length.
NRF_CCM_LENGTH_EXTENDED = CCM_MODE_LENGTH_Extended, ///< Extended length.
} nrf_ccm_length_t;
#endif // defined(CCM_MODE_LENGTH_Pos) || defined(__NRFX_DOXYGEN__)
/** @brief CCM configuration. */
typedef struct {
nrf_ccm_mode_t mode; ///< Operation mode.
#if defined(CCM_MODE_DATARATE_Pos) || defined(__NRFX_DOXYGEN__)
nrf_ccm_datarate_t datarate; ///< Data rate.
#endif
#if defined(CCM_MODE_LENGTH_Pos) || defined(__NRFX_DOXYGEN__)
nrf_ccm_length_t length; ///< Lenght of the CCM packet.
#endif
} nrf_ccm_config_t;
/**
* @brief Function for activating a specific CCM task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task to be activated.
*/
__STATIC_INLINE void nrf_ccm_task_trigger(NRF_CCM_Type * p_reg,
nrf_ccm_task_t task);
/**
* @brief Function for getting the address of a specific CCM task register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Requested task.
*
* @return Address of the specified task register.
*/
__STATIC_INLINE uint32_t nrf_ccm_task_address_get(NRF_CCM_Type const * p_reg,
nrf_ccm_task_t task);
/**
* @brief Function for clearing a specific CCM event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to clear.
*/
__STATIC_INLINE void nrf_ccm_event_clear(NRF_CCM_Type * p_reg,
nrf_ccm_event_t event);
/**
* @brief Function for retrieving the state of a specific CCM event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be checked.
*
* @retval true The event has been generated.
* @retval false The event has not been generated.
*/
__STATIC_INLINE bool nrf_ccm_event_check(NRF_CCM_Type const * p_reg,
nrf_ccm_event_t event);
/**
* @brief Function for getting the address of a specific CCM event register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Requested event.
*
* @return Address of the specified event register.
*/
__STATIC_INLINE uint32_t nrf_ccm_event_address_get(NRF_CCM_Type const * p_reg,
nrf_ccm_event_t event);
/**
* @brief Function for enabling specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Interrupts to be enabled.
*/
__STATIC_INLINE void nrf_ccm_int_enable(NRF_CCM_Type * p_reg, uint32_t mask);
/**
* @brief Function for disabling specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Interrupts to be disabled.
*/
__STATIC_INLINE void nrf_ccm_int_disable(NRF_CCM_Type * p_reg, uint32_t mask);
/**
* @brief Function for retrieving the state of a given interrupt.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] ccm_int Interrupt to be checked.
*
* @retval true The interrupt is enabled.
* @retval false The interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_ccm_int_enable_check(NRF_CCM_Type const * p_reg,
nrf_ccm_int_mask_t ccm_int);
/**
* @brief Function for enabling the CCM peripheral.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_ccm_enable(NRF_CCM_Type * p_reg);
/**
* @brief Function for disabling the CCM peripheral.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_ccm_disable(NRF_CCM_Type * p_reg);
/**
* @brief Function for setting the CCM peripheral configuration.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] p_config Pointer to the structure with configuration to be set.
*/
__STATIC_INLINE void nrf_ccm_configure(NRF_CCM_Type * p_reg,
nrf_ccm_config_t const * p_config);
#if defined(CCM_MAXPACKETSIZE_MAXPACKETSIZE_Pos) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting the length of key-stream generated
* when the packet length is configured as extended.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] size Maximum length of the key-stream.
*/
__STATIC_INLINE void nrf_ccm_maxpacketsize_set(NRF_CCM_Type * p_reg,
uint8_t size);
#endif // defined(CCM_MAXPACKETSIZE_MAXPACKETSIZE_Pos) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for getting the MIC check result.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @retval true The MIC check passed.
* @retval false The MIC check failed.
*/
__STATIC_INLINE bool nrf_ccm_micstatus_get(NRF_CCM_Type const * p_reg);
/**
* @brief Function for setting the pointer to the data structure
* holding the AES key and the CCM NONCE vector.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] p_data Pointer to the data structure.
*/
__STATIC_INLINE void nrf_ccm_cnfptr_set(NRF_CCM_Type * p_reg,
uint32_t const * p_data);
/**
* @brief Function for getting the pointer to the data structure
* holding the AES key and the CCM NONCE vector.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Pointer to the data structure.
*/
__STATIC_INLINE uint32_t * nrf_ccm_cnfptr_get(NRF_CCM_Type const * p_reg);
/**
* @brief Function for setting the input data pointer.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] p_data Input data pointer.
*/
__STATIC_INLINE void nrf_ccm_inptr_set(NRF_CCM_Type * p_reg,
uint32_t const * p_data);
/**
* @brief Function for getting the input data pointer.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Input data pointer.
*/
__STATIC_INLINE uint32_t * nrf_ccm_inptr_get(NRF_CCM_Type const * p_reg);
/**
* @brief Function for setting the output data pointer.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] p_data Output data pointer.
*/
__STATIC_INLINE void nrf_ccm_outptr_set(NRF_CCM_Type * p_reg,
uint32_t const * p_data);
/**
* @brief Function for getting the output data pointer.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Output data pointer.
*/
__STATIC_INLINE uint32_t * nrf_ccm_outptr_get(NRF_CCM_Type const * p_reg);
/**
* @brief Function for setting the pointer to the scratch area used for
* temporary storage.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] p_area Pointer to the scratch area.
*/
__STATIC_INLINE void nrf_ccm_scratchptr_set(NRF_CCM_Type * p_reg,
uint32_t const * p_area);
/**
* @brief Function for getting the pointer to the scratch area.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Pointer to the scratch area.
*/
__STATIC_INLINE uint32_t * nrf_ccm_stratchptr_get(NRF_CCM_Type const * p_reg);
#if defined(CCM_RATEOVERRIDE_RATEOVERRIDE_Pos) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting the data rate override value.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] datarate Override value to be applied when the RATEOVERRIDE task
* is triggered.
*/
__STATIC_INLINE void nrf_ccm_datarate_override_set(NRF_CCM_Type * p_reg,
nrf_ccm_datarate_t datarate);
#endif // defined(CCM_RATEOVERRIDE_RATEOVERRIDE_Pos) || defined(__NRFX_DOXYGEN__)
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_ccm_task_trigger(NRF_CCM_Type * p_reg,
nrf_ccm_task_t task)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)task)) = 0x1UL;
}
__STATIC_INLINE uint32_t nrf_ccm_task_address_get(NRF_CCM_Type const * p_reg,
nrf_ccm_task_t task)
{
return ((uint32_t)p_reg + (uint32_t)task);
}
__STATIC_INLINE void nrf_ccm_event_clear(NRF_CCM_Type * p_reg,
nrf_ccm_event_t event)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0x0UL;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event));
(void)dummy;
#endif
}
__STATIC_INLINE bool nrf_ccm_event_check(NRF_CCM_Type const * p_reg,
nrf_ccm_event_t event)
{
return (bool)*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE uint32_t nrf_ccm_event_address_get(NRF_CCM_Type const * p_reg,
nrf_ccm_event_t event)
{
return ((uint32_t)p_reg + (uint32_t)event);
}
__STATIC_INLINE void nrf_ccm_int_enable(NRF_CCM_Type * p_reg, uint32_t mask)
{
p_reg->INTENSET = mask;
}
__STATIC_INLINE void nrf_ccm_int_disable(NRF_CCM_Type * p_reg, uint32_t mask)
{
p_reg->INTENCLR = mask;
}
__STATIC_INLINE bool nrf_ccm_int_enable_check(NRF_CCM_Type const * p_reg,
nrf_ccm_int_mask_t ccm_int)
{
return (bool)(p_reg->INTENSET & ccm_int);
}
__STATIC_INLINE void nrf_ccm_enable(NRF_CCM_Type * p_reg)
{
p_reg->ENABLE = (CCM_ENABLE_ENABLE_Enabled << CCM_ENABLE_ENABLE_Pos);
}
__STATIC_INLINE void nrf_ccm_disable(NRF_CCM_Type * p_reg)
{
p_reg->ENABLE = (CCM_ENABLE_ENABLE_Disabled << CCM_ENABLE_ENABLE_Pos);
}
__STATIC_INLINE void nrf_ccm_configure(NRF_CCM_Type * p_reg,
nrf_ccm_config_t const * p_config)
{
p_reg->MODE = (((uint32_t)p_config->mode << CCM_MODE_MODE_Pos) |
#if defined(CCM_MODE_DATARATE_Pos)
((uint32_t)p_config->datarate << CCM_MODE_DATARATE_Pos) |
#endif
#if defined(CCM_MODE_LENGTH_Pos)
((uint32_t)p_config->length << CCM_MODE_LENGTH_Pos) |
#endif
0);
}
#if defined(CCM_MAXPACKETSIZE_MAXPACKETSIZE_Pos)
__STATIC_INLINE void nrf_ccm_maxpacketsize_set(NRF_CCM_Type * p_reg,
uint8_t size)
{
NRFX_ASSERT((size >= 0x1B) && (size <= 0xFB));
p_reg->MAXPACKETSIZE = size;
}
#endif // defined(CCM_MAXPACKETSIZE_MAXPACKETSIZE_Pos)
__STATIC_INLINE bool nrf_ccm_micstatus_get(NRF_CCM_Type const * p_reg)
{
return (bool)(p_reg->MICSTATUS);
}
__STATIC_INLINE void nrf_ccm_cnfptr_set(NRF_CCM_Type * p_reg,
uint32_t const * p_data)
{
p_reg->CNFPTR = (uint32_t)p_data;
}
__STATIC_INLINE uint32_t * nrf_ccm_cnfptr_get(NRF_CCM_Type const * p_reg)
{
return (uint32_t *)(p_reg->CNFPTR);
}
__STATIC_INLINE void nrf_ccm_inptr_set(NRF_CCM_Type * p_reg,
uint32_t const * p_data)
{
p_reg->INPTR = (uint32_t)p_data;
}
__STATIC_INLINE uint32_t * nrf_ccm_inptr_get(NRF_CCM_Type const * p_reg)
{
return (uint32_t *)(p_reg->INPTR);
}
__STATIC_INLINE void nrf_ccm_outptr_set(NRF_CCM_Type * p_reg,
uint32_t const * p_data)
{
p_reg->OUTPTR = (uint32_t)p_data;
}
__STATIC_INLINE uint32_t * nrf_ccm_outptr_get(NRF_CCM_Type const * p_reg)
{
return (uint32_t *)(p_reg->OUTPTR);
}
__STATIC_INLINE void nrf_ccm_scratchptr_set(NRF_CCM_Type * p_reg,
uint32_t const * p_area)
{
p_reg->SCRATCHPTR = (uint32_t)p_area;
}
__STATIC_INLINE uint32_t * nrf_ccm_stratchptr_get(NRF_CCM_Type const * p_reg)
{
return (uint32_t *)(p_reg->SCRATCHPTR);
}
#if defined(CCM_RATEOVERRIDE_RATEOVERRIDE_Pos)
__STATIC_INLINE void nrf_ccm_datarate_override_set(NRF_CCM_Type * p_reg,
nrf_ccm_datarate_t datarate)
{
p_reg->RATEOVERRIDE = ((uint32_t)datarate << CCM_RATEOVERRIDE_RATEOVERRIDE_Pos);
}
#endif
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_CCM_H__
+530
View File
@@ -0,0 +1,530 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_CLOCK_H__
#define NRF_CLOCK_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_clock_hal Clock HAL
* @{
* @ingroup nrf_clock
* @brief Hardware access layer for managing the CLOCK peripheral.
*
* This code can be used to managing low-frequency clock (LFCLK) and the high-frequency clock
* (HFCLK) settings.
*/
#if defined(CLOCK_LFCLKSRC_BYPASS_Msk) && defined(CLOCK_LFCLKSRC_EXTERNAL_Msk)
// Enable support for external LFCLK sources. Read more in the Product Specification.
#define NRF_CLOCK_USE_EXTERNAL_LFCLK_SOURCES
#endif
#if defined(CLOCK_CTIV_CTIV_Msk) || defined(__NRFX_DOXYGEN__)
/**
* @brief Presence of the Low Frequency Clock calibration.
*
* In some MCUs there is possibility to use LFCLK calibration.
*/
#define NRF_CLOCK_HAS_CALIBRATION 1
#else
#define NRF_CLOCK_HAS_CALIBRATION 0
#endif // defined(CLOCK_CTIV_CTIV_Msk) || defined(__NRFX_DOXYGEN__)
/**
* @brief Low-frequency clock sources.
* @details Used by LFCLKSRC, LFCLKSTAT, and LFCLKSRCCOPY registers.
*/
typedef enum
{
#if defined(CLOCK_LFCLKSRC_SRC_RC) || defined(__NRFX_DOXYGEN__)
NRF_CLOCK_LFCLK_RC = CLOCK_LFCLKSRC_SRC_RC, /**< Internal 32 kHz RC oscillator. */
#else
NRF_CLOCK_LFCLK_RC = CLOCK_LFCLKSRC_SRC_LFRC, /**< Internal 32 kHz RC oscillator. */
#endif
#if defined(CLOCK_LFCLKSRC_SRC_Xtal) || defined(__NRFX_DOXYGEN__)
NRF_CLOCK_LFCLK_Xtal = CLOCK_LFCLKSRC_SRC_Xtal, /**< External 32 kHz crystal. */
#else
NRF_CLOCK_LFCLK_Xtal = CLOCK_LFCLKSRC_SRC_LFXO, /**< External 32 kHz crystal. */
#endif
#if defined(CLOCK_LFCLKSRC_SRC_Synth) || defined(__NRFX_DOXYGEN__)
NRF_CLOCK_LFCLK_Synth = CLOCK_LFCLKSRC_SRC_Synth, /**< Internal 32 kHz synthesizer from HFCLK system clock. */
#endif
#if defined(NRF_CLOCK_USE_EXTERNAL_LFCLK_SOURCES) || defined(__NRFX_DOXYGEN__)
/**
* External 32 kHz low swing signal. Used only with the LFCLKSRC register.
* For the others @ref NRF_CLOCK_LFCLK_Xtal is returned for this setting.
*/
NRF_CLOCK_LFCLK_Xtal_Low_Swing = (CLOCK_LFCLKSRC_SRC_Xtal |
(CLOCK_LFCLKSRC_EXTERNAL_Enabled << CLOCK_LFCLKSRC_EXTERNAL_Pos)),
/**
* External 32 kHz full swing signal. Used only with the LFCLKSRC register.
* For the others @ref NRF_CLOCK_LFCLK_Xtal is returned for this setting.
*/
NRF_CLOCK_LFCLK_Xtal_Full_Swing = (CLOCK_LFCLKSRC_SRC_Xtal |
(CLOCK_LFCLKSRC_BYPASS_Enabled << CLOCK_LFCLKSRC_BYPASS_Pos) |
(CLOCK_LFCLKSRC_EXTERNAL_Enabled << CLOCK_LFCLKSRC_EXTERNAL_Pos)),
#endif // defined(NRF_CLOCK_USE_EXTERNAL_LFCLK_SOURCES) || defined(__NRFX_DOXYGEN__)
} nrf_clock_lfclk_t;
/** @brief High-frequency clock sources. */
typedef enum
{
#if defined(CLOCK_HFCLKSTAT_SRC_RC) || defined(__NRFX_DOXYGEN__)
NRF_CLOCK_HFCLK_LOW_ACCURACY = CLOCK_HFCLKSTAT_SRC_RC, /**< Internal 16 MHz RC oscillator. */
#endif
#if defined(CLOCK_HFCLKSTAT_SRC_Xtal) || defined(__NRFX_DOXYGEN__)
NRF_CLOCK_HFCLK_HIGH_ACCURACY = CLOCK_HFCLKSTAT_SRC_Xtal /**< External 16 MHz/32 MHz crystal oscillator. */
#else
NRF_CLOCK_HFCLK_HIGH_ACCURACY = CLOCK_HFCLKSTAT_SRC_HFXO /**< External 32 MHz crystal oscillator. */
#endif
} nrf_clock_hfclk_t;
/**
* @brief Trigger status of task LFCLKSTART/HFCLKSTART.
* @details Used by LFCLKRUN and HFCLKRUN registers.
*/
typedef enum
{
NRF_CLOCK_START_TASK_NOT_TRIGGERED = CLOCK_LFCLKRUN_STATUS_NotTriggered, /**< Task LFCLKSTART/HFCLKSTART has not been triggered. */
NRF_CLOCK_START_TASK_TRIGGERED = CLOCK_LFCLKRUN_STATUS_Triggered /**< Task LFCLKSTART/HFCLKSTART has been triggered. */
} nrf_clock_start_task_status_t;
/** @brief Interrupts. */
typedef enum
{
NRF_CLOCK_INT_HF_STARTED_MASK = CLOCK_INTENSET_HFCLKSTARTED_Msk, /**< Interrupt on HFCLKSTARTED event. */
NRF_CLOCK_INT_LF_STARTED_MASK = CLOCK_INTENSET_LFCLKSTARTED_Msk, /**< Interrupt on LFCLKSTARTED event. */
#if (NRF_CLOCK_HAS_CALIBRATION) || defined(__NRFX_DOXYGEN__)
NRF_CLOCK_INT_DONE_MASK = CLOCK_INTENSET_DONE_Msk, /**< Interrupt on DONE event. */
NRF_CLOCK_INT_CTTO_MASK = CLOCK_INTENSET_CTTO_Msk, /**< Interrupt on CTTO event. */
#endif
#if defined(CLOCK_INTENSET_CTSTARTED_Msk) || defined(__NRFX_DOXYGEN__)
NRF_CLOCK_INT_CTSTARTED_MASK = CLOCK_INTENSET_CTSTARTED_Msk, /**< Interrupt on CTSTARTED event. */
NRF_CLOCK_INT_CTSTOPPED_MASK = CLOCK_INTENSET_CTSTOPPED_Msk /**< Interrupt on CTSTOPPED event. */
#endif
} nrf_clock_int_mask_t;
/**
* @brief Tasks.
*
* @details The NRF_CLOCK_TASK_LFCLKSTOP task cannot be set when the low-frequency clock is not running.
* The NRF_CLOCK_TASK_HFCLKSTOP task cannot be set when the high-frequency clock is not running.
*/
typedef enum
{
NRF_CLOCK_TASK_HFCLKSTART = offsetof(NRF_CLOCK_Type, TASKS_HFCLKSTART), /**< Start HFCLK clock source.*/
NRF_CLOCK_TASK_HFCLKSTOP = offsetof(NRF_CLOCK_Type, TASKS_HFCLKSTOP), /**< Stop HFCLK clock source.*/
NRF_CLOCK_TASK_LFCLKSTART = offsetof(NRF_CLOCK_Type, TASKS_LFCLKSTART), /**< Start LFCLK clock source.*/
NRF_CLOCK_TASK_LFCLKSTOP = offsetof(NRF_CLOCK_Type, TASKS_LFCLKSTOP), /**< Stop LFCLK clock source.*/
#if (NRF_CLOCK_HAS_CALIBRATION) || defined(__NRFX_DOXYGEN__)
NRF_CLOCK_TASK_CAL = offsetof(NRF_CLOCK_Type, TASKS_CAL), /**< Start calibration of LFCLK RC oscillator.*/
NRF_CLOCK_TASK_CTSTART = offsetof(NRF_CLOCK_Type, TASKS_CTSTART), /**< Start calibration timer.*/
NRF_CLOCK_TASK_CTSTOP = offsetof(NRF_CLOCK_Type, TASKS_CTSTOP) /**< Stop calibration timer.*/
#endif
} nrf_clock_task_t;
/** @brief Events. */
typedef enum
{
NRF_CLOCK_EVENT_HFCLKSTARTED = offsetof(NRF_CLOCK_Type, EVENTS_HFCLKSTARTED), /**< HFCLK oscillator started.*/
NRF_CLOCK_EVENT_LFCLKSTARTED = offsetof(NRF_CLOCK_Type, EVENTS_LFCLKSTARTED), /**< LFCLK oscillator started.*/
#if (NRF_CLOCK_HAS_CALIBRATION) || defined(__NRFX_DOXYGEN__)
NRF_CLOCK_EVENT_DONE = offsetof(NRF_CLOCK_Type, EVENTS_DONE), /**< Calibration of LFCLK RC oscillator completed.*/
NRF_CLOCK_EVENT_CTTO = offsetof(NRF_CLOCK_Type, EVENTS_CTTO), /**< Calibration timer time-out.*/
#endif
#if defined(CLOCK_INTENSET_CTSTARTED_Msk) || defined(__NRFX_DOXYGEN__)
NRF_CLOCK_EVENT_CTSTARTED = offsetof(NRF_CLOCK_Type, EVENTS_CTSTARTED), /**< Calibration timer started.*/
NRF_CLOCK_EVENT_CTSTOPPED = offsetof(NRF_CLOCK_Type, EVENTS_CTSTOPPED) /**< Calibration timer stopped.*/
#endif
} nrf_clock_event_t;
/**
* @brief Function for enabling the specified interrupt.
*
* @param[in] int_mask Interrupt.
*/
__STATIC_INLINE void nrf_clock_int_enable(uint32_t int_mask);
/**
* @brief Function for disabling the specified interrupt.
*
* @param[in] int_mask Interrupt.
*/
__STATIC_INLINE void nrf_clock_int_disable(uint32_t int_mask);
/**
* @brief Function for retrieving the state of the specified interrupt.
*
* @param[in] int_mask Interrupt.
*
* @retval true The interrupt is enabled.
* @retval false The interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_clock_int_enable_check(nrf_clock_int_mask_t int_mask);
/**
* @brief Function for retrieving the address of the specified task.
* @details This function can be used by the PPI module.
*
* @param[in] task CLOCK Task.
*
* @return Address of the requested task register.
*/
__STATIC_INLINE uint32_t nrf_clock_task_address_get(nrf_clock_task_t task);
/**
* @brief Function for setting the specified task.
*
* @param[in] task Task to be activated.
*/
__STATIC_INLINE void nrf_clock_task_trigger(nrf_clock_task_t task);
/**
* @brief Function for retrieving the address of the specified event.
* @details This function can be used by the PPI module.
*
* @param[in] event CLOCK Event.
*
* @return Address of the specified event register.
*/
__STATIC_INLINE uint32_t nrf_clock_event_address_get(nrf_clock_event_t event);
/**
* @brief Function for clearing the specified event.
*
* @param[in] event Event to clear.
*/
__STATIC_INLINE void nrf_clock_event_clear(nrf_clock_event_t event);
/**
* @brief Function for retrieving the state of the specified event.
*
* @param[in] event Event to be checked.
*
* @retval true The event has been generated.
* @retval false The event has not been generated.
*/
__STATIC_INLINE bool nrf_clock_event_check(nrf_clock_event_t event);
/**
* @brief Function for changing the low-frequency clock source.
* @details This function cannot be called when the low-frequency clock is running.
*
* @param[in] source New low-frequency clock source.
*/
__STATIC_INLINE void nrf_clock_lf_src_set(nrf_clock_lfclk_t source);
/**
* @brief Function for retrieving the selected source for the low-frequency clock.
*
* @retval NRF_CLOCK_LFCLK_RC The internal 32 kHz RC oscillator
* is the selected source for the low-frequency clock.
* @retval NRF_CLOCK_LFCLK_Xtal An external 32 kHz crystal oscillator
* is the selected source for the low-frequency clock.
* @retval NRF_CLOCK_LFCLK_Synth The internal 32 kHz synthesizer from
* the HFCLK is the selected source for the low-frequency clock.
*/
__STATIC_INLINE nrf_clock_lfclk_t nrf_clock_lf_src_get(void);
/**
* @brief Function for retrieving the active source of the low-frequency clock.
*
* @retval NRF_CLOCK_LFCLK_RC The internal 32 kHz RC oscillator
* is the active source of the low-frequency clock.
* @retval NRF_CLOCK_LFCLK_Xtal An external 32 kHz crystal oscillator
* is the active source of the low-frequency clock.
* @retval NRF_CLOCK_LFCLK_Synth The internal 32 kHz synthesizer from
* the HFCLK is the active source of the low-frequency clock.
*/
__STATIC_INLINE nrf_clock_lfclk_t nrf_clock_lf_actv_src_get(void);
/**
* @brief Function for retrieving the clock source for the LFCLK clock when
* the task LKCLKSTART is triggered.
*
* @retval NRF_CLOCK_LFCLK_RC The internal 32 kHz RC oscillator
* is running and generating the LFCLK clock.
* @retval NRF_CLOCK_LFCLK_Xtal An external 32 kHz crystal oscillator
* is running and generating the LFCLK clock.
* @retval NRF_CLOCK_LFCLK_Synth The internal 32 kHz synthesizer from
* the HFCLK is running and generating the LFCLK clock.
*/
__STATIC_INLINE nrf_clock_lfclk_t nrf_clock_lf_srccopy_get(void);
/**
* @brief Function for retrieving the state of the LFCLK clock.
*
* @retval false The LFCLK clock is not running.
* @retval true The LFCLK clock is running.
*/
__STATIC_INLINE bool nrf_clock_lf_is_running(void);
/**
* @brief Function for retrieving the trigger status of the task LFCLKSTART.
*
* @retval NRF_CLOCK_START_TASK_NOT_TRIGGERED The task LFCLKSTART has not been triggered.
* @retval NRF_CLOCK_START_TASK_TRIGGERED The task LFCLKSTART has been triggered.
*/
__STATIC_INLINE nrf_clock_start_task_status_t nrf_clock_lf_start_task_status_get(void);
/**
* @brief Function for retrieving the active source of the high-frequency clock.
*
* @retval NRF_CLOCK_HFCLK_LOW_ACCURACY The internal RC oscillator is the active
* source of the high-frequency clock.
* @retval NRF_CLOCK_HFCLK_HIGH_ACCURACY An external crystal oscillator is the active
* source of the high-frequency clock.
*/
__STATIC_INLINE nrf_clock_hfclk_t nrf_clock_hf_src_get(void);
/**
* @brief Function for retrieving the state of the HFCLK clock.
*
* @param[in] clk_src Clock source to be checked.
*
* @retval false The HFCLK clock is not running.
* @retval true The HFCLK clock is running.
*/
__STATIC_INLINE bool nrf_clock_hf_is_running(nrf_clock_hfclk_t clk_src);
/**
* @brief Function for retrieving the trigger status of the task HFCLKSTART.
*
* @retval NRF_CLOCK_START_TASK_NOT_TRIGGERED The task HFCLKSTART has not been triggered.
* @retval NRF_CLOCK_START_TASK_TRIGGERED The task HFCLKSTART has been triggered.
*/
__STATIC_INLINE nrf_clock_start_task_status_t nrf_clock_hf_start_task_status_get(void);
#if (NRF_CLOCK_HAS_CALIBRATION) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for changing the calibration timer interval.
*
* @param[in] interval New calibration timer interval in 0.25 s resolution
* (range: 0.25 seconds to 31.75 seconds).
*/
__STATIC_INLINE void nrf_clock_cal_timer_timeout_set(uint32_t interval);
#endif
#if defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting the subscribe configuration for a given
* CLOCK task.
*
* @param[in] task Task for which to set the configuration.
* @param[in] channel Channel through which to subscribe events.
*/
__STATIC_INLINE void nrf_clock_subscribe_set(nrf_clock_task_t task,
uint8_t channel);
/**
* @brief Function for clearing the subscribe configuration for a given
* CLOCK task.
*
* @param[in] task Task for which to clear the configuration.
*/
__STATIC_INLINE void nrf_clock_subscribe_clear(nrf_clock_task_t task);
/**
* @brief Function for setting the publish configuration for a given
* CLOCK event.
*
* @param[in] event Event for which to set the configuration.
* @param[in] channel Channel through which to publish the event.
*/
__STATIC_INLINE void nrf_clock_publish_set(nrf_clock_event_t event,
uint8_t channel);
/**
* @brief Function for clearing the publish configuration for a given
* CLOCK event.
*
* @param[in] event Event for which to clear the configuration.
*/
__STATIC_INLINE void nrf_clock_publish_clear(nrf_clock_event_t event);
#endif // defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_clock_int_enable(uint32_t int_mask)
{
NRF_CLOCK->INTENSET = int_mask;
}
__STATIC_INLINE void nrf_clock_int_disable(uint32_t int_mask)
{
NRF_CLOCK->INTENCLR = int_mask;
}
__STATIC_INLINE bool nrf_clock_int_enable_check(nrf_clock_int_mask_t int_mask)
{
return (bool)(NRF_CLOCK->INTENCLR & int_mask);
}
__STATIC_INLINE uint32_t nrf_clock_task_address_get(nrf_clock_task_t task)
{
return ((uint32_t )NRF_CLOCK + task);
}
__STATIC_INLINE void nrf_clock_task_trigger(nrf_clock_task_t task)
{
*((volatile uint32_t *)((uint8_t *)NRF_CLOCK + task)) = 0x1UL;
}
__STATIC_INLINE uint32_t nrf_clock_event_address_get(nrf_clock_event_t event)
{
return ((uint32_t)NRF_CLOCK + event);
}
__STATIC_INLINE void nrf_clock_event_clear(nrf_clock_event_t event)
{
*((volatile uint32_t *)((uint8_t *)NRF_CLOCK + event)) = 0x0UL;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)NRF_CLOCK + (uint32_t)event));
(void)dummy;
#endif
}
__STATIC_INLINE bool nrf_clock_event_check(nrf_clock_event_t event)
{
return (bool)*((volatile uint32_t *)((uint8_t *)NRF_CLOCK + event));
}
__STATIC_INLINE void nrf_clock_lf_src_set(nrf_clock_lfclk_t source)
{
NRF_CLOCK->LFCLKSRC = (uint32_t)(source);
}
__STATIC_INLINE nrf_clock_lfclk_t nrf_clock_lf_src_get(void)
{
return (nrf_clock_lfclk_t)(NRF_CLOCK->LFCLKSRC);
}
__STATIC_INLINE nrf_clock_lfclk_t nrf_clock_lf_actv_src_get(void)
{
return (nrf_clock_lfclk_t)((NRF_CLOCK->LFCLKSTAT &
CLOCK_LFCLKSTAT_SRC_Msk) >> CLOCK_LFCLKSTAT_SRC_Pos);
}
__STATIC_INLINE nrf_clock_lfclk_t nrf_clock_lf_srccopy_get(void)
{
return (nrf_clock_lfclk_t)((NRF_CLOCK->LFCLKSRCCOPY &
CLOCK_LFCLKSRCCOPY_SRC_Msk) >> CLOCK_LFCLKSRCCOPY_SRC_Pos);
}
__STATIC_INLINE bool nrf_clock_lf_is_running(void)
{
return ((NRF_CLOCK->LFCLKSTAT &
CLOCK_LFCLKSTAT_STATE_Msk) >> CLOCK_LFCLKSTAT_STATE_Pos);
}
__STATIC_INLINE nrf_clock_start_task_status_t nrf_clock_lf_start_task_status_get(void)
{
return (nrf_clock_start_task_status_t)((NRF_CLOCK->LFCLKRUN &
CLOCK_LFCLKRUN_STATUS_Msk) >> CLOCK_LFCLKRUN_STATUS_Pos);
}
__STATIC_INLINE nrf_clock_hfclk_t nrf_clock_hf_src_get(void)
{
return (nrf_clock_hfclk_t)((NRF_CLOCK->HFCLKSTAT &
CLOCK_HFCLKSTAT_SRC_Msk) >> CLOCK_HFCLKSTAT_SRC_Pos);
}
__STATIC_INLINE bool nrf_clock_hf_is_running(nrf_clock_hfclk_t clk_src)
{
return (NRF_CLOCK->HFCLKSTAT & (CLOCK_HFCLKSTAT_STATE_Msk | CLOCK_HFCLKSTAT_SRC_Msk)) ==
(CLOCK_HFCLKSTAT_STATE_Msk | (clk_src << CLOCK_HFCLKSTAT_SRC_Pos));
}
__STATIC_INLINE nrf_clock_start_task_status_t nrf_clock_hf_start_task_status_get(void)
{
return (nrf_clock_start_task_status_t)((NRF_CLOCK->HFCLKRUN &
CLOCK_HFCLKRUN_STATUS_Msk) >> CLOCK_HFCLKRUN_STATUS_Pos);
}
#if (NRF_CLOCK_HAS_CALIBRATION)
__STATIC_INLINE void nrf_clock_cal_timer_timeout_set(uint32_t interval)
{
NRF_CLOCK->CTIV = ((interval << CLOCK_CTIV_CTIV_Pos) & CLOCK_CTIV_CTIV_Msk);
}
#endif
#if defined(DPPI_PRESENT)
__STATIC_INLINE void nrf_clock_subscribe_set(nrf_clock_task_t task,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) NRF_CLOCK + (uint32_t) task + 0x80uL)) =
((uint32_t)channel | CLOCK_SUBSCRIBE_HFCLKSTART_EN_Msk);
}
__STATIC_INLINE void nrf_clock_subscribe_clear(nrf_clock_task_t task)
{
*((volatile uint32_t *) ((uint8_t *) NRF_CLOCK + (uint32_t) task + 0x80uL)) = 0;
}
__STATIC_INLINE void nrf_clock_publish_set(nrf_clock_event_t event,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) NRF_CLOCK + (uint32_t) event + 0x80uL)) =
((uint32_t)channel | CLOCK_PUBLISH_HFCLKSTARTED_EN_Msk);
}
__STATIC_INLINE void nrf_clock_publish_clear(nrf_clock_event_t event)
{
*((volatile uint32_t *) ((uint8_t *) NRF_CLOCK + (uint32_t) event + 0x80uL)) = 0;
}
#endif // defined(DPPI_PRESENT)
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_CLOCK_H__
+91
View File
@@ -0,0 +1,91 @@
/**
* Copyright (c) 2012 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include <nrfx.h>
#include "nrf_ecb.h"
#include <string.h>
static uint8_t ecb_data[48]; ///< ECB data structure for RNG peripheral to access.
static uint8_t* ecb_key; ///< Key: Starts at ecb_data
static uint8_t* ecb_cleartext; ///< Cleartext: Starts at ecb_data + 16 bytes.
static uint8_t* ecb_ciphertext; ///< Ciphertext: Starts at ecb_data + 32 bytes.
bool nrf_ecb_init(void)
{
ecb_key = ecb_data;
ecb_cleartext = ecb_data + 16;
ecb_ciphertext = ecb_data + 32;
NRF_ECB->ECBDATAPTR = (uint32_t)ecb_data;
return true;
}
bool nrf_ecb_crypt(uint8_t * dest_buf, const uint8_t * src_buf)
{
uint32_t counter = 0x1000000;
if (src_buf != ecb_cleartext)
{
memcpy(ecb_cleartext,src_buf,16);
}
NRF_ECB->EVENTS_ENDECB = 0;
NRF_ECB->TASKS_STARTECB = 1;
while (NRF_ECB->EVENTS_ENDECB == 0)
{
counter--;
if (counter == 0)
{
return false;
}
}
NRF_ECB->EVENTS_ENDECB = 0;
if (dest_buf != ecb_ciphertext)
{
memcpy(dest_buf,ecb_ciphertext,16);
}
return true;
}
void nrf_ecb_set_key(const uint8_t * key)
{
memcpy(ecb_key,key,16);
}
+287
View File
@@ -0,0 +1,287 @@
/**
* Copyright (c) 2012 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_ECB_H__
#define NRF_ECB_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_ecb_drv AES ECB encryption driver
* @{
* @ingroup nrf_ecb
* @brief Driver for the Advanced Encryption Standard (AES) Electronic Code Book (ECB) peripheral.
*
* To encrypt data, the peripheral must first be powered on
* using @ref nrf_ecb_init. Next, the key must be set using @ref nrf_ecb_set_key.
*/
/**
* @brief Function for initializing and powering on the ECB peripheral.
*
* This function allocates memory for the ECBDATAPTR.
*
* @retval true The initialization was successful.
* @retval false The power-on failed.
*/
bool nrf_ecb_init(void);
/**
* @brief Function for encrypting 16-byte data using current key.
*
* This function avoids unnecessary copying of data if the parameters point to the
* correct locations in the ECB data structure.
*
* @param dst Result of encryption, 16 bytes will be written.
* @param src Source with 16-byte data to be encrypted.
*
* @retval true The encryption operation completed.
* @retval false The encryption operation did not complete.
*/
bool nrf_ecb_crypt(uint8_t * dst, const uint8_t * src);
/**
* @brief Function for setting the key to be used for encryption.
*
* @param key Pointer to the key. 16 bytes will be read.
*/
void nrf_ecb_set_key(const uint8_t * key);
/** @} */
/**
* @defgroup nrf_ecb_hal AES ECB encryption HAL
* @{
* @ingroup nrf_ecb
* @brief Hardware access layer (HAL) for managing the Advanced Encryption Standard (AES) Electronic Codebook (ECB) peripheral.
*/
/** @brief ECB tasks. */
typedef enum
{
NRF_ECB_TASK_STARTECB = offsetof(NRF_ECB_Type, TASKS_STARTECB), /**< Task for starting the ECB block encryption. */
NRF_ECB_TASK_STOPECB = offsetof(NRF_ECB_Type, TASKS_STOPECB), /**< Task for stopping the ECB block encryption. */
} nrf_ecb_task_t;
/** @brief ECB events. */
typedef enum
{
NRF_ECB_EVENT_ENDECB = offsetof(NRF_ECB_Type, EVENTS_ENDECB), /**< ECB block encrypt complete. */
NRF_ECB_EVENT_ERRORECB = offsetof(NRF_ECB_Type, EVENTS_ERRORECB), /**< ECB block encrypt aborted because of a STOPECB task or due to an error. */
} nrf_ecb_event_t;
/** @brief ECB interrupts. */
typedef enum
{
NRF_ECB_INT_ENDECB_MASK = ECB_INTENSET_ENDECB_Msk, ///< Interrupt on ENDECB event.
NRF_ECB_INT_ERRORECB_MASK = ECB_INTENSET_ERRORECB_Msk, ///< Interrupt on ERRORECB event.
} nrf_ecb_int_mask_t;
/**
* @brief Function for activating the specified ECB task.
*
* @param[in] p_reg Pointer to the peripheral register structure.
* @param[in] task Task to be activated.
*/
__STATIC_INLINE void nrf_ecb_task_trigger(NRF_ECB_Type * p_reg, nrf_ecb_task_t task);
/**
* @brief Function for getting the address of the specified ECB task register.
*
* @param[in] p_reg Pointer to the peripheral register structure.
* @param[in] task Requested task.
*
* @return Address of the specified task register.
*/
__STATIC_INLINE uint32_t nrf_ecb_task_address_get(NRF_ECB_Type const * p_reg,
nrf_ecb_task_t task);
/**
* @brief Function for clearing the specified ECB event.
*
* @param[in] p_reg Pointer to the peripheral register structure.
* @param[in] event Event to clear.
*/
__STATIC_INLINE void nrf_ecb_event_clear(NRF_ECB_Type * p_reg, nrf_ecb_event_t event);
/**
* @brief Function for retrieving the state of the ECB event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be checked.
*
* @retval true The event has been generated.
* @retval false The event has not been generated.
*/
__STATIC_INLINE bool nrf_ecb_event_check(NRF_ECB_Type const * p_reg, nrf_ecb_event_t event);
/**
* @brief Function for getting the address of the specified ECB event register.
*
* @param[in] p_reg Pointer to the peripheral register structure.
* @param[in] event Requested event.
*
* @return Address of the specified event register.
*/
__STATIC_INLINE uint32_t nrf_ecb_event_address_get(NRF_ECB_Type const * p_reg,
nrf_ecb_event_t event);
/**
* @brief Function for enabling the specified interrupts.
*
* @param[in] p_reg Pointer to the peripheral register structure.
* @param[in] mask Interrupts to be enabled.
*/
__STATIC_INLINE void nrf_ecb_int_enable(NRF_ECB_Type * p_reg, uint32_t mask);
/**
* @brief Function for disabling the specified interrupts.
*
* @param[in] p_reg Pointer to the peripheral register structure.
* @param[in] mask Interrupts to be disabled.
*/
__STATIC_INLINE void nrf_ecb_int_disable(NRF_ECB_Type * p_reg, uint32_t mask);
/**
* @brief Function for retrieving the state of a given interrupt.
*
* @param[in] p_reg Pointer to the peripheral register structure.
* @param[in] ecb_int Interrupt to be checked.
*
* @retval true The interrupt is enabled.
* @retval false The interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_ecb_int_enable_check(NRF_ECB_Type const * p_reg,
nrf_ecb_int_mask_t ecb_int);
/**
* @brief Function for setting the pointer to the ECB data buffer.
*
* @note The buffer has to be placed in the Data RAM region.
* For description of the data structure in this buffer, see the Product Specification.
*
* @param[in] p_reg Pointer to the peripheral register structure.
* @param[in] p_buffer Pointer to the ECB data buffer.
*/
__STATIC_INLINE void nrf_ecb_data_pointer_set(NRF_ECB_Type * p_reg, void const * p_buffer);
/**
* @brief Function for getting the pointer to the ECB data buffer.
*
* @param[in] p_reg Pointer to the peripheral register structure.
*
* @return Pointer to the ECB data buffer.
*/
__STATIC_INLINE void * nrf_ecb_data_pointer_get(NRF_ECB_Type const * p_reg);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_ecb_task_trigger(NRF_ECB_Type * p_reg, nrf_ecb_task_t task)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)task)) = 0x1UL;
}
__STATIC_INLINE uint32_t nrf_ecb_task_address_get(NRF_ECB_Type const * p_reg,
nrf_ecb_task_t task)
{
return ((uint32_t)p_reg + (uint32_t)task);
}
__STATIC_INLINE void nrf_ecb_event_clear(NRF_ECB_Type * p_reg, nrf_ecb_event_t event)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0x0UL;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event));
(void)dummy;
#endif
}
__STATIC_INLINE bool nrf_ecb_event_check(NRF_ECB_Type const * p_reg, nrf_ecb_event_t event)
{
return (bool)*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE uint32_t nrf_ecb_event_address_get(NRF_ECB_Type const * p_reg,
nrf_ecb_event_t event)
{
return ((uint32_t)p_reg + (uint32_t)event);
}
__STATIC_INLINE void nrf_ecb_int_enable(NRF_ECB_Type * p_reg, uint32_t mask)
{
p_reg->INTENSET = mask;
}
__STATIC_INLINE void nrf_ecb_int_disable(NRF_ECB_Type * p_reg, uint32_t mask)
{
p_reg->INTENCLR = mask;
}
__STATIC_INLINE bool nrf_ecb_int_enable_check(NRF_ECB_Type const * p_reg,
nrf_ecb_int_mask_t ecb_int)
{
return (bool)(p_reg->INTENSET & ecb_int);
}
__STATIC_INLINE void nrf_ecb_data_pointer_set(NRF_ECB_Type * p_reg, void const * p_buffer)
{
p_reg->ECBDATAPTR = (uint32_t)p_buffer;
}
__STATIC_INLINE void * nrf_ecb_data_pointer_get(NRF_ECB_Type const * p_reg)
{
return (void *)(p_reg->ECBDATAPTR);
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_ECB_H__
+467
View File
@@ -0,0 +1,467 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_EGU_H__
#define NRF_EGU_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_egu_hal EGU HAL
* @{
* @ingroup nrf_swi_egu
* @brief Hardware access layer for managing the Event Generator Unit (EGU) peripheral.
*/
/** @brief EGU tasks. */
typedef enum
{
NRF_EGU_TASK_TRIGGER0 = offsetof(NRF_EGU_Type, TASKS_TRIGGER[0]), /**< Trigger 0 for triggering the corresponding TRIGGERED[0] event. */
NRF_EGU_TASK_TRIGGER1 = offsetof(NRF_EGU_Type, TASKS_TRIGGER[1]), /**< Trigger 1 for triggering the corresponding TRIGGERED[1] event. */
NRF_EGU_TASK_TRIGGER2 = offsetof(NRF_EGU_Type, TASKS_TRIGGER[2]), /**< Trigger 2 for triggering the corresponding TRIGGERED[2] event. */
NRF_EGU_TASK_TRIGGER3 = offsetof(NRF_EGU_Type, TASKS_TRIGGER[3]), /**< Trigger 3 for triggering the corresponding TRIGGERED[3] event. */
NRF_EGU_TASK_TRIGGER4 = offsetof(NRF_EGU_Type, TASKS_TRIGGER[4]), /**< Trigger 4 for triggering the corresponding TRIGGERED[4] event. */
NRF_EGU_TASK_TRIGGER5 = offsetof(NRF_EGU_Type, TASKS_TRIGGER[5]), /**< Trigger 5 for triggering the corresponding TRIGGERED[5] event. */
NRF_EGU_TASK_TRIGGER6 = offsetof(NRF_EGU_Type, TASKS_TRIGGER[6]), /**< Trigger 6 for triggering the corresponding TRIGGERED[6] event. */
NRF_EGU_TASK_TRIGGER7 = offsetof(NRF_EGU_Type, TASKS_TRIGGER[7]), /**< Trigger 7 for triggering the corresponding TRIGGERED[7] event. */
NRF_EGU_TASK_TRIGGER8 = offsetof(NRF_EGU_Type, TASKS_TRIGGER[8]), /**< Trigger 8 for triggering the corresponding TRIGGERED[8] event. */
NRF_EGU_TASK_TRIGGER9 = offsetof(NRF_EGU_Type, TASKS_TRIGGER[9]), /**< Trigger 9 for triggering the corresponding TRIGGERED[9] event. */
NRF_EGU_TASK_TRIGGER10 = offsetof(NRF_EGU_Type, TASKS_TRIGGER[10]), /**< Trigger 10 for triggering the corresponding TRIGGERED[10] event. */
NRF_EGU_TASK_TRIGGER11 = offsetof(NRF_EGU_Type, TASKS_TRIGGER[11]), /**< Trigger 11 for triggering the corresponding TRIGGERED[11] event. */
NRF_EGU_TASK_TRIGGER12 = offsetof(NRF_EGU_Type, TASKS_TRIGGER[12]), /**< Trigger 12 for triggering the corresponding TRIGGERED[12] event. */
NRF_EGU_TASK_TRIGGER13 = offsetof(NRF_EGU_Type, TASKS_TRIGGER[13]), /**< Trigger 13 for triggering the corresponding TRIGGERED[13] event. */
NRF_EGU_TASK_TRIGGER14 = offsetof(NRF_EGU_Type, TASKS_TRIGGER[14]), /**< Trigger 14 for triggering the corresponding TRIGGERED[14] event. */
NRF_EGU_TASK_TRIGGER15 = offsetof(NRF_EGU_Type, TASKS_TRIGGER[15]) /**< Trigger 15 for triggering the corresponding TRIGGERED[15] event. */
} nrf_egu_task_t;
/** @brief EGU events. */
typedef enum
{
NRF_EGU_EVENT_TRIGGERED0 = offsetof(NRF_EGU_Type, EVENTS_TRIGGERED[0]), /**< Event number 0 generated by triggering the corresponding TRIGGER[0] task. */
NRF_EGU_EVENT_TRIGGERED1 = offsetof(NRF_EGU_Type, EVENTS_TRIGGERED[1]), /**< Event number 1 generated by triggering the corresponding TRIGGER[1] task. */
NRF_EGU_EVENT_TRIGGERED2 = offsetof(NRF_EGU_Type, EVENTS_TRIGGERED[2]), /**< Event number 2 generated by triggering the corresponding TRIGGER[2] task. */
NRF_EGU_EVENT_TRIGGERED3 = offsetof(NRF_EGU_Type, EVENTS_TRIGGERED[3]), /**< Event number 3 generated by triggering the corresponding TRIGGER[3] task. */
NRF_EGU_EVENT_TRIGGERED4 = offsetof(NRF_EGU_Type, EVENTS_TRIGGERED[4]), /**< Event number 4 generated by triggering the corresponding TRIGGER[4] task. */
NRF_EGU_EVENT_TRIGGERED5 = offsetof(NRF_EGU_Type, EVENTS_TRIGGERED[5]), /**< Event number 5 generated by triggering the corresponding TRIGGER[5] task. */
NRF_EGU_EVENT_TRIGGERED6 = offsetof(NRF_EGU_Type, EVENTS_TRIGGERED[6]), /**< Event number 6 generated by triggering the corresponding TRIGGER[6] task. */
NRF_EGU_EVENT_TRIGGERED7 = offsetof(NRF_EGU_Type, EVENTS_TRIGGERED[7]), /**< Event number 7 generated by triggering the corresponding TRIGGER[7] task. */
NRF_EGU_EVENT_TRIGGERED8 = offsetof(NRF_EGU_Type, EVENTS_TRIGGERED[8]), /**< Event number 8 generated by triggering the corresponding TRIGGER[8] task. */
NRF_EGU_EVENT_TRIGGERED9 = offsetof(NRF_EGU_Type, EVENTS_TRIGGERED[9]), /**< Event number 9 generated by triggering the corresponding TRIGGER[9] task. */
NRF_EGU_EVENT_TRIGGERED10 = offsetof(NRF_EGU_Type, EVENTS_TRIGGERED[10]), /**< Event number 10 generated by triggering the corresponding TRIGGER[10] task. */
NRF_EGU_EVENT_TRIGGERED11 = offsetof(NRF_EGU_Type, EVENTS_TRIGGERED[11]), /**< Event number 11 generated by triggering the corresponding TRIGGER[11] task. */
NRF_EGU_EVENT_TRIGGERED12 = offsetof(NRF_EGU_Type, EVENTS_TRIGGERED[12]), /**< Event number 12 generated by triggering the corresponding TRIGGER[12] task. */
NRF_EGU_EVENT_TRIGGERED13 = offsetof(NRF_EGU_Type, EVENTS_TRIGGERED[13]), /**< Event number 13 generated by triggering the corresponding TRIGGER[13] task. */
NRF_EGU_EVENT_TRIGGERED14 = offsetof(NRF_EGU_Type, EVENTS_TRIGGERED[14]), /**< Event number 14 generated by triggering the corresponding TRIGGER[14] task. */
NRF_EGU_EVENT_TRIGGERED15 = offsetof(NRF_EGU_Type, EVENTS_TRIGGERED[15]) /**< Event number 15 generated by triggering the corresponding TRIGGER[15] task. */
} nrf_egu_event_t;
/** @brief EGU interrupts. */
typedef enum
{
NRF_EGU_INT_TRIGGERED0 = EGU_INTENSET_TRIGGERED0_Msk, /**< Interrupt on EVENTS_TRIGGERED[0] event. */
NRF_EGU_INT_TRIGGERED1 = EGU_INTENSET_TRIGGERED1_Msk, /**< Interrupt on EVENTS_TRIGGERED[1] event. */
NRF_EGU_INT_TRIGGERED2 = EGU_INTENSET_TRIGGERED2_Msk, /**< Interrupt on EVENTS_TRIGGERED[2] event. */
NRF_EGU_INT_TRIGGERED3 = EGU_INTENSET_TRIGGERED3_Msk, /**< Interrupt on EVENTS_TRIGGERED[3] event. */
NRF_EGU_INT_TRIGGERED4 = EGU_INTENSET_TRIGGERED4_Msk, /**< Interrupt on EVENTS_TRIGGERED[4] event. */
NRF_EGU_INT_TRIGGERED5 = EGU_INTENSET_TRIGGERED5_Msk, /**< Interrupt on EVENTS_TRIGGERED[5] event. */
NRF_EGU_INT_TRIGGERED6 = EGU_INTENSET_TRIGGERED6_Msk, /**< Interrupt on EVENTS_TRIGGERED[6] event. */
NRF_EGU_INT_TRIGGERED7 = EGU_INTENSET_TRIGGERED7_Msk, /**< Interrupt on EVENTS_TRIGGERED[7] event. */
NRF_EGU_INT_TRIGGERED8 = EGU_INTENSET_TRIGGERED8_Msk, /**< Interrupt on EVENTS_TRIGGERED[8] event. */
NRF_EGU_INT_TRIGGERED9 = EGU_INTENSET_TRIGGERED9_Msk, /**< Interrupt on EVENTS_TRIGGERED[9] event. */
NRF_EGU_INT_TRIGGERED10 = EGU_INTENSET_TRIGGERED10_Msk, /**< Interrupt on EVENTS_TRIGGERED[10] event. */
NRF_EGU_INT_TRIGGERED11 = EGU_INTENSET_TRIGGERED11_Msk, /**< Interrupt on EVENTS_TRIGGERED[11] event. */
NRF_EGU_INT_TRIGGERED12 = EGU_INTENSET_TRIGGERED12_Msk, /**< Interrupt on EVENTS_TRIGGERED[12] event. */
NRF_EGU_INT_TRIGGERED13 = EGU_INTENSET_TRIGGERED13_Msk, /**< Interrupt on EVENTS_TRIGGERED[13] event. */
NRF_EGU_INT_TRIGGERED14 = EGU_INTENSET_TRIGGERED14_Msk, /**< Interrupt on EVENTS_TRIGGERED[14] event. */
NRF_EGU_INT_TRIGGERED15 = EGU_INTENSET_TRIGGERED15_Msk, /**< Interrupt on EVENTS_TRIGGERED[15] event. */
NRF_EGU_INT_ALL = 0xFFFFuL
} nrf_egu_int_mask_t;
/**
* @brief Function for getting the maximum channel number of the given EGU.
*
* @param NRF_EGUx EGU instance.
*
* @return Number of available channels.
*/
__STATIC_INLINE uint32_t nrf_egu_channel_count(NRF_EGU_Type * NRF_EGUx);
/**
* @brief Function for triggering the specified EGU task.
*
* @param NRF_EGUx EGU instance.
* @param egu_task EGU task.
*/
__STATIC_INLINE void nrf_egu_task_trigger(NRF_EGU_Type * NRF_EGUx, nrf_egu_task_t egu_task);
/**
* @brief Function for returning the address of the specified EGU task register.
*
* @param NRF_EGUx EGU instance.
* @param egu_task EGU task.
*
* @return Address of the specified EGU task register.
*/
__STATIC_INLINE uint32_t * nrf_egu_task_address_get(NRF_EGU_Type * NRF_EGUx,
nrf_egu_task_t egu_task);
/**
* @brief Function for returning the address of the specified EGU TRIGGER task register.
*
* @param NRF_EGUx EGU instance.
* @param channel Channel number.
*
* @return Address of the specified EGU TRIGGER task register.
*/
__STATIC_INLINE uint32_t * nrf_egu_task_trigger_address_get(NRF_EGU_Type * NRF_EGUx,
uint8_t channel);
/**
* @brief Function for returning the specified EGU TRIGGER task.
*
* @param NRF_EGUx EGU instance.
* @param channel Channel number.
*
* @return The specified EGU TRIGGER task.
*/
__STATIC_INLINE nrf_egu_task_t nrf_egu_task_trigger_get(NRF_EGU_Type * NRF_EGUx, uint8_t channel);
/**
* @brief Function for retrieving the state of the UARTE event.
*
* @param NRF_EGUx EGU instance.
* @param egu_event EGU event to be checked.
*
* @retval true The event has been generated.
* @retval false The event has not been generated.
*/
__STATIC_INLINE bool nrf_egu_event_check(NRF_EGU_Type * NRF_EGUx,
nrf_egu_event_t egu_event);
/**
* @brief Function for clearing the specified EGU event.
*
* @param NRF_EGUx EGU instance.
* @param egu_event EGU event to clear.
*/
__STATIC_INLINE void nrf_egu_event_clear(NRF_EGU_Type * NRF_EGUx,
nrf_egu_event_t egu_event);
/**
* @brief Function for returning the address of the specified EGU event register.
*
* @param NRF_EGUx EGU instance.
* @param egu_event EGU event.
*
* @return Address of the specified EGU event register.
*/
__STATIC_INLINE uint32_t * nrf_egu_event_address_get(NRF_EGU_Type * NRF_EGUx,
nrf_egu_event_t egu_event);
/**
* @brief Function for returning address of the specified EGU TRIGGERED event register.
*
* @param NRF_EGUx EGU instance.
* @param channel Channel number.
*
* @return Address of the specified EGU TRIGGERED event register.
*/
__STATIC_INLINE uint32_t * nrf_egu_event_triggered_address_get(NRF_EGU_Type * NRF_EGUx,
uint8_t channel);
/**
* @brief Function for returning the specified EGU TRIGGERED event.
*
* @param NRF_EGUx EGU instance.
* @param channel Channel number.
*
* @return The specified EGU TRIGGERED event.
*/
__STATIC_INLINE nrf_egu_event_t nrf_egu_event_triggered_get(NRF_EGU_Type * NRF_EGUx,
uint8_t channel);
/**
* @brief Function for enabling one or more of the EGU interrupts.
*
* @param NRF_EGUx EGU instance.
* @param mask Mask of interrupts to be enabled.
*/
__STATIC_INLINE void nrf_egu_int_enable(NRF_EGU_Type * NRF_EGUx, uint32_t mask);
/**
* @brief Function for retrieving the state of one or more of the EGU interrupts.
*
* @param NRF_EGUx EGU instance.
* @param mask Mask of interrupts to be checked.
*
* @retval true All of the specified interrupts are enabled.
* @retval false At least one of the specified interrupts is disabled.
*/
__STATIC_INLINE bool nrf_egu_int_enable_check(NRF_EGU_Type * NRF_EGUx, uint32_t mask);
/**
* @brief Function for disabling one or more of the EGU interrupts.
*
* @param NRF_EGUx EGU instance.
* @param mask Mask of interrupts to be disabled.
*/
__STATIC_INLINE void nrf_egu_int_disable(NRF_EGU_Type * NRF_EGUx, uint32_t mask);
/**
* @brief Function for retrieving one or more of the EGU interrupts.
*
* @param NRF_EGUx EGU instance.
* @param channel Channel number.
*
* @return EGU interrupt mask.
*/
__STATIC_INLINE nrf_egu_int_mask_t nrf_egu_int_get(NRF_EGU_Type * NRF_EGUx, uint8_t channel);
#if defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting the subscribe configuration for a given
* EGU task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task for which to set the configuration.
* @param[in] channel Channel through which to subscribe events.
*/
__STATIC_INLINE void nrf_egu_subscribe_set(NRF_EGU_Type * p_reg,
nrf_egu_task_t task,
uint8_t channel);
/**
* @brief Function for clearing the subscribe configuration for a given
* EGU task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task for which to clear the configuration.
*/
__STATIC_INLINE void nrf_egu_subscribe_clear(NRF_EGU_Type * p_reg,
nrf_egu_task_t task);
/**
* @brief Function for setting the publish configuration for a given
* EGU event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event for which to set the configuration.
* @param[in] channel Channel through which to publish the event.
*/
__STATIC_INLINE void nrf_egu_publish_set(NRF_EGU_Type * p_reg,
nrf_egu_event_t event,
uint8_t channel);
/**
* @brief Function for clearing the publish configuration for a given
* EGU event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event for which to clear the configuration.
*/
__STATIC_INLINE void nrf_egu_publish_clear(NRF_EGU_Type * p_reg,
nrf_egu_event_t event);
#endif // defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE uint32_t nrf_egu_channel_count(NRF_EGU_Type * NRF_EGUx)
{
if (NRF_EGUx == NRF_EGU0){
return EGU0_CH_NUM;
}
if (NRF_EGUx == NRF_EGU1){
return EGU1_CH_NUM;
}
#if EGU_COUNT > 2
if (NRF_EGUx == NRF_EGU2){
return EGU2_CH_NUM;
}
if (NRF_EGUx == NRF_EGU3){
return EGU3_CH_NUM;
}
if (NRF_EGUx == NRF_EGU4){
return EGU4_CH_NUM;
}
if (NRF_EGUx == NRF_EGU5){
return EGU5_CH_NUM;
}
#endif
return 0;
}
__STATIC_INLINE void nrf_egu_task_trigger(NRF_EGU_Type * NRF_EGUx, nrf_egu_task_t egu_task)
{
NRFX_ASSERT(NRF_EGUx);
*((volatile uint32_t *)((uint8_t *)NRF_EGUx + (uint32_t)egu_task)) = 0x1UL;
}
__STATIC_INLINE uint32_t * nrf_egu_task_address_get(NRF_EGU_Type * NRF_EGUx,
nrf_egu_task_t egu_task)
{
NRFX_ASSERT(NRF_EGUx);
return (uint32_t *)((uint8_t *)NRF_EGUx + (uint32_t)egu_task);
}
__STATIC_INLINE uint32_t * nrf_egu_task_trigger_address_get(NRF_EGU_Type * NRF_EGUx,
uint8_t channel)
{
NRFX_ASSERT(NRF_EGUx);
NRFX_ASSERT(channel < nrf_egu_channel_count(NRF_EGUx));
return (uint32_t*)&NRF_EGUx->TASKS_TRIGGER[channel];
}
__STATIC_INLINE nrf_egu_task_t nrf_egu_task_trigger_get(NRF_EGU_Type * NRF_EGUx, uint8_t channel)
{
NRFX_ASSERT(NRF_EGUx);
NRFX_ASSERT(channel < nrf_egu_channel_count(NRF_EGUx));
return (nrf_egu_task_t)((uint32_t) NRF_EGU_TASK_TRIGGER0 + (channel * sizeof(uint32_t)));
}
__STATIC_INLINE bool nrf_egu_event_check(NRF_EGU_Type * NRF_EGUx,
nrf_egu_event_t egu_event)
{
NRFX_ASSERT(NRF_EGUx);
return (bool)*(volatile uint32_t *)((uint8_t *)NRF_EGUx + (uint32_t)egu_event);
}
__STATIC_INLINE void nrf_egu_event_clear(NRF_EGU_Type * NRF_EGUx,
nrf_egu_event_t egu_event)
{
NRFX_ASSERT(NRF_EGUx);
*((volatile uint32_t *)((uint8_t *)NRF_EGUx + (uint32_t)egu_event)) = 0x0UL;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)NRF_EGUx + (uint32_t)egu_event));
(void)dummy;
#endif
}
__STATIC_INLINE uint32_t * nrf_egu_event_address_get(NRF_EGU_Type * NRF_EGUx,
nrf_egu_event_t egu_event)
{
NRFX_ASSERT(NRF_EGUx);
return (uint32_t *)((uint8_t *)NRF_EGUx + (uint32_t)egu_event);
}
__STATIC_INLINE uint32_t * nrf_egu_event_triggered_address_get(NRF_EGU_Type * NRF_EGUx,
uint8_t channel)
{
NRFX_ASSERT(NRF_EGUx);
NRFX_ASSERT(channel < nrf_egu_channel_count(NRF_EGUx));
return (uint32_t*)&NRF_EGUx->EVENTS_TRIGGERED[channel];
}
__STATIC_INLINE nrf_egu_event_t nrf_egu_event_triggered_get(NRF_EGU_Type * NRF_EGUx,
uint8_t channel)
{
NRFX_ASSERT(NRF_EGUx);
NRFX_ASSERT(channel < nrf_egu_channel_count(NRF_EGUx));
return (nrf_egu_event_t)((uint32_t) NRF_EGU_EVENT_TRIGGERED0 + (channel * sizeof(uint32_t)));
}
__STATIC_INLINE void nrf_egu_int_enable(NRF_EGU_Type * NRF_EGUx, uint32_t mask)
{
NRFX_ASSERT(NRF_EGUx);
NRF_EGUx->INTENSET = mask;
}
__STATIC_INLINE bool nrf_egu_int_enable_check(NRF_EGU_Type * NRF_EGUx, uint32_t mask)
{
NRFX_ASSERT(NRF_EGUx);
return (bool)(NRF_EGUx->INTENSET & mask);
}
__STATIC_INLINE void nrf_egu_int_disable(NRF_EGU_Type * NRF_EGUx, uint32_t mask)
{
NRFX_ASSERT(NRF_EGUx);
NRF_EGUx->INTENCLR = mask;
}
__STATIC_INLINE nrf_egu_int_mask_t nrf_egu_int_get(NRF_EGU_Type * NRF_EGUx, uint8_t channel)
{
NRFX_ASSERT(NRF_EGUx);
NRFX_ASSERT(channel < nrf_egu_channel_count(NRF_EGUx));
return (nrf_egu_int_mask_t)((uint32_t) (EGU_INTENSET_TRIGGERED0_Msk << channel));
}
#if defined(DPPI_PRESENT)
__STATIC_INLINE void nrf_egu_subscribe_set(NRF_EGU_Type * p_reg,
nrf_egu_task_t task,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) task + 0x80uL)) =
((uint32_t)channel | EGU_SUBSCRIBE_TRIGGER_EN_Msk);
}
__STATIC_INLINE void nrf_egu_subscribe_clear(NRF_EGU_Type * p_reg,
nrf_egu_task_t task)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) task + 0x80uL)) = 0;
}
__STATIC_INLINE void nrf_egu_publish_set(NRF_EGU_Type * p_reg,
nrf_egu_event_t event,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) event + 0x80uL)) =
((uint32_t)channel | EGU_PUBLISH_TRIGGERED_EN_Msk);
}
__STATIC_INLINE void nrf_egu_publish_clear(NRF_EGU_Type * p_reg,
nrf_egu_event_t event)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) event + 0x80uL)) = 0;
}
#endif // defined(DPPI_PRESENT)
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif
+159
View File
@@ -0,0 +1,159 @@
/**
* Copyright (c) 2018 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_FICR_H__
#define NRF_FICR_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_ficr_hal FICR HAL
* @{
* @ingroup nrf_ficr
* @brief Hardware access layer (HAL) for getting data from
* the Factory Information Configuration Registers (FICR).
*/
/**
* @brief Function for getting the size of the code memory page.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Code memory page size in bytes.
*/
__STATIC_INLINE uint32_t nrf_ficr_codepagesize_get(NRF_FICR_Type const * p_reg);
/**
* @brief Function for getting the size of the code memory rendered as number of pages.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Code memory size rendered as number of pages.
*/
__STATIC_INLINE uint32_t nrf_ficr_codesize_get(NRF_FICR_Type const * p_reg);
/**
* @brief Function for getting the unique device identifier.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] reg_id Register index.
*
* @return Unique device identifier.
*/
__STATIC_INLINE uint32_t nrf_ficr_deviceid_get(NRF_FICR_Type const * p_reg, uint32_t reg_id);
#if defined(FICR_NFC_TAGHEADER0_MFGID_Msk) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for getting the default header values for the NFC tag.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] tagheader_id Tag header index.
*
* @return The default header value of the NFC tag for the specified header index.
*/
__STATIC_INLINE uint32_t nrf_ficr_nfc_tagheader_get(NRF_FICR_Type const * p_reg,
uint32_t tagheader_id);
#endif // defined(FICR_NFC_TAGHEADER0_MFGID_Msk) || defined(__NRFX_DOXYGEN__)
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE uint32_t nrf_ficr_codepagesize_get(NRF_FICR_Type const * p_reg)
{
#if defined(FICR_INFO_CODEPAGESIZE_CODEPAGESIZE_Msk)
return p_reg->INFO.CODEPAGESIZE;
#else
return p_reg->CODEPAGESIZE;
#endif
}
__STATIC_INLINE uint32_t nrf_ficr_codesize_get(NRF_FICR_Type const * p_reg)
{
#if defined(FICR_INFO_CODESIZE_CODESIZE_Msk)
return p_reg->INFO.CODESIZE;
#else
return p_reg->CODESIZE;
#endif
}
__STATIC_INLINE uint32_t nrf_ficr_deviceid_get(NRF_FICR_Type const * p_reg, uint32_t reg_id)
{
#if defined(FICR_INFO_DEVICEID_DEVICEID_Msk)
return p_reg->INFO.DEVICEID[reg_id];
#else
return p_reg->DEVICEID[reg_id];
#endif
}
#if defined(FICR_NFC_TAGHEADER0_MFGID_Msk)
__STATIC_INLINE uint32_t nrf_ficr_nfc_tagheader_get(NRF_FICR_Type const * p_reg,
uint32_t tagheader_id)
{
switch(tagheader_id) {
case 0:
return p_reg->NFC.TAGHEADER0;
break;
case 1:
return p_reg->NFC.TAGHEADER1;
break;
case 2:
return p_reg->NFC.TAGHEADER2;
break;
case 3:
return p_reg->NFC.TAGHEADER3;
break;
default:
return 0;
}
}
#endif // defined(FICR_NFC_TAGHEADER0_MFGID_Msk)
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_FICR_H__
+899
View File
@@ -0,0 +1,899 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_GPIO_H__
#define NRF_GPIO_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef NRF_P0
#define NRF_P0 NRF_GPIO
#endif
#if (GPIO_COUNT == 1)
#define NUMBER_OF_PINS (P0_PIN_NUM)
#define GPIO_REG_LIST {NRF_P0}
#elif (GPIO_COUNT == 2)
#define NUMBER_OF_PINS (P0_PIN_NUM + P1_PIN_NUM)
#define GPIO_REG_LIST {NRF_P0, NRF_P1}
#else
#error "Not supported."
#endif
#if defined(NRF52820_XXAA)
#include <nrf_erratas.h>
#endif
/**
* @defgroup nrf_gpio_hal GPIO HAL
* @{
* @ingroup nrf_gpio
* @brief Hardware access layer for managing the GPIO peripheral.
*/
#if defined(GPIO_LATCH_PIN0_Msk) || defined(__NRFX_DOXYGEN__)
/** @brief Symbol indicating whether the functionality of latching GPIO state change is present. */
#define NRF_GPIO_LATCH_PRESENT
#endif
/** @brief Macro for mapping port and pin numbers to values understandable for nrf_gpio functions. */
#define NRF_GPIO_PIN_MAP(port, pin) (((port) << 5) | ((pin) & 0x1F))
/** @brief Pin direction definitions. */
typedef enum
{
NRF_GPIO_PIN_DIR_INPUT = GPIO_PIN_CNF_DIR_Input, ///< Input.
NRF_GPIO_PIN_DIR_OUTPUT = GPIO_PIN_CNF_DIR_Output ///< Output.
} nrf_gpio_pin_dir_t;
/** @brief Connection of input buffer. */
typedef enum
{
NRF_GPIO_PIN_INPUT_CONNECT = GPIO_PIN_CNF_INPUT_Connect, ///< Connect input buffer.
NRF_GPIO_PIN_INPUT_DISCONNECT = GPIO_PIN_CNF_INPUT_Disconnect ///< Disconnect input buffer.
} nrf_gpio_pin_input_t;
/**
* @brief Enumerator used for selecting the pin to be pulled down or up at the time of pin
* configuration.
*/
typedef enum
{
NRF_GPIO_PIN_NOPULL = GPIO_PIN_CNF_PULL_Disabled, ///< Pin pull-up resistor disabled.
NRF_GPIO_PIN_PULLDOWN = GPIO_PIN_CNF_PULL_Pulldown, ///< Pin pull-down resistor enabled.
NRF_GPIO_PIN_PULLUP = GPIO_PIN_CNF_PULL_Pullup, ///< Pin pull-up resistor enabled.
} nrf_gpio_pin_pull_t;
/** @brief Enumerator used for selecting output drive mode. */
typedef enum
{
NRF_GPIO_PIN_S0S1 = GPIO_PIN_CNF_DRIVE_S0S1, ///< !< Standard '0', standard '1'.
NRF_GPIO_PIN_H0S1 = GPIO_PIN_CNF_DRIVE_H0S1, ///< !< High-drive '0', standard '1'.
NRF_GPIO_PIN_S0H1 = GPIO_PIN_CNF_DRIVE_S0H1, ///< !< Standard '0', high-drive '1'.
NRF_GPIO_PIN_H0H1 = GPIO_PIN_CNF_DRIVE_H0H1, ///< !< High drive '0', high-drive '1'.
NRF_GPIO_PIN_D0S1 = GPIO_PIN_CNF_DRIVE_D0S1, ///< !< Disconnect '0' standard '1'.
NRF_GPIO_PIN_D0H1 = GPIO_PIN_CNF_DRIVE_D0H1, ///< !< Disconnect '0', high-drive '1'.
NRF_GPIO_PIN_S0D1 = GPIO_PIN_CNF_DRIVE_S0D1, ///< !< Standard '0', disconnect '1'.
NRF_GPIO_PIN_H0D1 = GPIO_PIN_CNF_DRIVE_H0D1, ///< !< High-drive '0', disconnect '1'.
} nrf_gpio_pin_drive_t;
/** @brief Enumerator used for selecting the pin to sense high or low level on the pin input. */
typedef enum
{
NRF_GPIO_PIN_NOSENSE = GPIO_PIN_CNF_SENSE_Disabled, ///< Pin sense level disabled.
NRF_GPIO_PIN_SENSE_LOW = GPIO_PIN_CNF_SENSE_Low, ///< Pin sense low level.
NRF_GPIO_PIN_SENSE_HIGH = GPIO_PIN_CNF_SENSE_High, ///< Pin sense high level.
} nrf_gpio_pin_sense_t;
/**
* @brief Function for configuring the GPIO pin range as output pins with normal drive strength.
* This function can be used to configure pin range as simple output with gate driving GPIO_PIN_CNF_DRIVE_S0S1 (normal cases).
*
* @note For configuring only one pin as output, use @ref nrf_gpio_cfg_output.
* Sense capability on the pin is disabled and input is disconnected from the buffer as the pins are configured as output.
*
* @param pin_range_start Specifies the start number (inclusive) in the range of pin numbers to be configured (allowed values 0-30).
* @param pin_range_end Specifies the end number (inclusive) in the range of pin numbers to be configured (allowed values 0-30).
*/
__STATIC_INLINE void nrf_gpio_range_cfg_output(uint32_t pin_range_start, uint32_t pin_range_end);
/**
* @brief Function for configuring the GPIO pin range as input pins with given initial value set, hiding inner details.
* This function can be used to configure pin range as simple input.
*
* @note For configuring only one pin as input, use @ref nrf_gpio_cfg_input.
* Sense capability on the pin is disabled and input is connected to buffer so that the GPIO->IN register is readable.
*
* @param pin_range_start Specifies the start number (inclusive) in the range of pin numbers to be configured (allowed values 0-30).
* @param pin_range_end Specifies the end number (inclusive) in the range of pin numbers to be configured (allowed values 0-30).
* @param pull_config State of the pin range pull resistor (no pull, pulled down, or pulled high).
*/
__STATIC_INLINE void nrf_gpio_range_cfg_input(uint32_t pin_range_start,
uint32_t pin_range_end,
nrf_gpio_pin_pull_t pull_config);
/**
* @brief Pin configuration function.
*
* The main pin configuration function.
* This function allows to set any aspect in PIN_CNF register.
*
* @param pin_number Specifies the pin number.
* @param dir Pin direction.
* @param input Connect or disconnect the input buffer.
* @param pull Pull configuration.
* @param drive Drive configuration.
* @param sense Pin sensing mechanism.
*/
__STATIC_INLINE void nrf_gpio_cfg(
uint32_t pin_number,
nrf_gpio_pin_dir_t dir,
nrf_gpio_pin_input_t input,
nrf_gpio_pin_pull_t pull,
nrf_gpio_pin_drive_t drive,
nrf_gpio_pin_sense_t sense);
/**
* @brief Function for configuring the given GPIO pin number as output, hiding inner details.
* This function can be used to configure a pin as simple output with gate driving GPIO_PIN_CNF_DRIVE_S0S1 (normal cases).
*
* @note Sense capability on the pin is disabled and input is disconnected from the buffer as the pins are configured as output.
*
* @param pin_number Specifies the pin number.
*/
__STATIC_INLINE void nrf_gpio_cfg_output(uint32_t pin_number);
/**
* @brief Function for configuring the given GPIO pin number as input, hiding inner details.
* This function can be used to configure a pin as simple input.
*
* @note Sense capability on the pin is disabled and input is connected to buffer so that the GPIO->IN register is readable.
*
* @param pin_number Specifies the pin number.
* @param pull_config State of the pin range pull resistor (no pull, pulled down, or pulled high).
*/
__STATIC_INLINE void nrf_gpio_cfg_input(uint32_t pin_number, nrf_gpio_pin_pull_t pull_config);
/**
* @brief Function for resetting pin configuration to its default state.
*
* @param pin_number Specifies the pin number.
*/
__STATIC_INLINE void nrf_gpio_cfg_default(uint32_t pin_number);
/**
* @brief Function for configuring the given GPIO pin number as a watcher. Only input is connected.
*
* @param pin_number Specifies the pin number.
*
*/
__STATIC_INLINE void nrf_gpio_cfg_watcher(uint32_t pin_number);
/**
* @brief Function for disconnecting input for the given GPIO.
*
* @param pin_number Specifies the pin number.
*/
__STATIC_INLINE void nrf_gpio_input_disconnect(uint32_t pin_number);
/**
* @brief Function for configuring the given GPIO pin number as input, hiding inner details.
* This function can be used to configure pin range as simple input.
* Sense capability on the pin is configurable and input is connected to buffer so that the GPIO->IN register is readable.
*
* @param pin_number Specifies the pin number.
* @param pull_config State of the pin pull resistor (no pull, pulled down, or pulled high).
* @param sense_config Sense level of the pin (no sense, sense low, or sense high).
*/
__STATIC_INLINE void nrf_gpio_cfg_sense_input(uint32_t pin_number,
nrf_gpio_pin_pull_t pull_config,
nrf_gpio_pin_sense_t sense_config);
/**
* @brief Function for configuring sense level for the given GPIO.
*
* @param pin_number Specifies the pin number.
* @param sense_config Sense configuration.
*/
__STATIC_INLINE void nrf_gpio_cfg_sense_set(uint32_t pin_number, nrf_gpio_pin_sense_t sense_config);
/**
* @brief Function for setting the direction for a GPIO pin.
*
* @param pin_number Specifies the pin number for which to set the direction.
* @param direction Specifies the direction.
*/
__STATIC_INLINE void nrf_gpio_pin_dir_set(uint32_t pin_number, nrf_gpio_pin_dir_t direction);
/**
* @brief Function for setting a GPIO pin.
*
* For this function to have any effect, the pin must be configured as an output.
*
* @param pin_number Specifies the pin number to be set.
*/
__STATIC_INLINE void nrf_gpio_pin_set(uint32_t pin_number);
/**
* @brief Function for clearing a GPIO pin.
*
* For this function to have any effect, the pin must be configured as an output.
*
* @param pin_number Specifies the pin number to clear.
*/
__STATIC_INLINE void nrf_gpio_pin_clear(uint32_t pin_number);
/**
* @brief Function for toggling a GPIO pin.
*
* For this function to have any effect, the pin must be configured as an output.
*
* @param pin_number Specifies the pin number to toggle.
*/
__STATIC_INLINE void nrf_gpio_pin_toggle(uint32_t pin_number);
/**
* @brief Function for writing a value to a GPIO pin.
*
* For this function to have any effect, the pin must be configured as an output.
*
* @param pin_number Specifies the pin number to write.
* @param value Specifies the value to be written to the pin.
* @arg 0 Clears the pin.
* @arg >=1 Sets the pin.
*/
__STATIC_INLINE void nrf_gpio_pin_write(uint32_t pin_number, uint32_t value);
/**
* @brief Function for reading the input level of a GPIO pin.
*
* If the value returned by this function is to be valid, the pin's input buffer must be connected.
*
* @param pin_number Specifies the pin number to read.
*
* @return 0 if the pin input level is low. Positive value if the pin is high.
*/
__STATIC_INLINE uint32_t nrf_gpio_pin_read(uint32_t pin_number);
/**
* @brief Function for reading the output level of a GPIO pin.
*
* @param pin_number Specifies the pin number to read.
*
* @return 0 if the pin output level is low. Positive value if pin output is high.
*/
__STATIC_INLINE uint32_t nrf_gpio_pin_out_read(uint32_t pin_number);
/**
* @brief Function for reading the sense configuration of a GPIO pin.
*
* @param pin_number Specifies the pin number to read.
*
* @return Sense configuration.
*/
__STATIC_INLINE nrf_gpio_pin_sense_t nrf_gpio_pin_sense_get(uint32_t pin_number);
/**
* @brief Function for reading the direction configuration of a GPIO pin.
*
* @param pin_number Specifies the pin number to read.
*
* @return Direction configuration.
*/
__STATIC_INLINE nrf_gpio_pin_dir_t nrf_gpio_pin_dir_get(uint32_t pin_number);
/**
* @brief Function for reading the status of GPIO pin input buffer.
*
* @param pin_number Pin number to be read.
*
* @retval Input buffer configuration.
*/
__STATIC_INLINE nrf_gpio_pin_input_t nrf_gpio_pin_input_get(uint32_t pin_number);
/**
* @brief Function for reading the pull configuration of a GPIO pin.
*
* @param pin_number Specifies the pin number to read.
*
* @retval Pull configuration.
*/
__STATIC_INLINE nrf_gpio_pin_pull_t nrf_gpio_pin_pull_get(uint32_t pin_number);
/**
* @brief Function for setting output direction on the selected pins on the given port.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param out_mask Mask specifying the pins to set as output.
*/
__STATIC_INLINE void nrf_gpio_port_dir_output_set(NRF_GPIO_Type * p_reg, uint32_t out_mask);
/**
* @brief Function for setting input direction on selected pins on a given port.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param in_mask Mask that specifies the pins to be set as input.
*/
__STATIC_INLINE void nrf_gpio_port_dir_input_set(NRF_GPIO_Type * p_reg, uint32_t in_mask);
/**
* @brief Function for writing the direction configuration of the GPIO pins in the given port.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param dir_mask Mask that specifies the direction of pins. Bit set means that the given pin is configured as output.
*/
__STATIC_INLINE void nrf_gpio_port_dir_write(NRF_GPIO_Type * p_reg, uint32_t dir_mask);
/**
* @brief Function for reading the direction configuration of a GPIO port.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return Pin configuration of the current direction settings. Bit set means that the given pin is configured as output.
*/
__STATIC_INLINE uint32_t nrf_gpio_port_dir_read(NRF_GPIO_Type const * p_reg);
/**
* @brief Function for reading the input signals of the GPIO pins on the given port.
*
* @param p_reg Pointer to the peripheral registers structure.
*
* @return Port input values.
*/
__STATIC_INLINE uint32_t nrf_gpio_port_in_read(NRF_GPIO_Type const * p_reg);
/**
* @brief Function for reading the output signals of the GPIO pins on the given port.
*
* @param p_reg Pointer to the peripheral registers structure.
*
* @return Port output values.
*/
__STATIC_INLINE uint32_t nrf_gpio_port_out_read(NRF_GPIO_Type const * p_reg);
/**
* @brief Function for writing the GPIO pins output on a given port.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param value Output port mask.
*/
__STATIC_INLINE void nrf_gpio_port_out_write(NRF_GPIO_Type * p_reg, uint32_t value);
/**
* @brief Function for setting high level on selected the GPIO pins on the given port.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param set_mask Mask with pins to be set as logical high level.
*/
__STATIC_INLINE void nrf_gpio_port_out_set(NRF_GPIO_Type * p_reg, uint32_t set_mask);
/**
* @brief Function for setting low level on selected the GPIO pins on the given port.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param clr_mask Mask with pins to be set as logical low level.
*/
__STATIC_INLINE void nrf_gpio_port_out_clear(NRF_GPIO_Type * p_reg, uint32_t clr_mask);
/**
* @brief Function for reading pin state of multiple consecutive ports.
*
* @param start_port Index of the first port to read.
* @param length Number of ports to read.
* @param p_masks Pointer to output array where port states will be stored.
*/
__STATIC_INLINE void nrf_gpio_ports_read(uint32_t start_port, uint32_t length, uint32_t * p_masks);
#if defined(NRF_GPIO_LATCH_PRESENT)
/**
* @brief Function for reading latch state of multiple consecutive ports.
*
* @param start_port Index of the first port to read.
* @param length Number of ports to read.
* @param p_masks Pointer to output array where latch states will be stored.
*/
__STATIC_INLINE void nrf_gpio_latches_read(uint32_t start_port,
uint32_t length,
uint32_t * p_masks);
/**
* @brief Function for reading and immediate clearing latch state of multiple consecutive ports.
*
* @param start_port Index of the first port to read and clear.
* @param length Number of ports to read and clear.
* @param p_masks Pointer to output array where latch states will be stored.
*/
__STATIC_INLINE void nrf_gpio_latches_read_and_clear(uint32_t start_port,
uint32_t length,
uint32_t * p_masks);
/**
* @brief Function for reading latch state of single pin.
*
* @param pin_number Pin number.
*
* @return 0 if latch is not set. Positive value otherwise.
*/
__STATIC_INLINE uint32_t nrf_gpio_pin_latch_get(uint32_t pin_number);
/**
* @brief Function for clearing latch state of a single pin.
*
* @param pin_number Pin number.
*/
__STATIC_INLINE void nrf_gpio_pin_latch_clear(uint32_t pin_number);
#endif // defined(NRF_GPIO_LATCH_PRESENT)
/**
* @brief Function for checking if provided pin is present on the MCU.
*
* @param[in] pin_number Number of the pin to be checked.
*
* @retval true Pin is present.
* @retval false Pin is not present.
*/
__STATIC_INLINE bool nrf_gpio_pin_present_check(uint32_t pin_number);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
/**
* @brief Function for extracting port and the relative pin number from the absolute pin number.
*
* @param[in,out] p_pin Pointer to the absolute pin number overriden by the pin number that is relative to the port.
*
* @return Pointer to port register set.
*/
__STATIC_INLINE NRF_GPIO_Type * nrf_gpio_pin_port_decode(uint32_t * p_pin)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(*p_pin));
#if (GPIO_COUNT == 1)
return NRF_P0;
#else
if (*p_pin < P0_PIN_NUM)
{
return NRF_P0;
}
else
{
*p_pin = *p_pin & 0x1F;
return NRF_P1;
}
#endif
}
__STATIC_INLINE void nrf_gpio_range_cfg_output(uint32_t pin_range_start, uint32_t pin_range_end)
{
/*lint -e{845} // A zero has been given as right argument to operator '|'" */
for (; pin_range_start <= pin_range_end; pin_range_start++)
{
nrf_gpio_cfg_output(pin_range_start);
}
}
__STATIC_INLINE void nrf_gpio_range_cfg_input(uint32_t pin_range_start,
uint32_t pin_range_end,
nrf_gpio_pin_pull_t pull_config)
{
/*lint -e{845} // A zero has been given as right argument to operator '|'" */
for (; pin_range_start <= pin_range_end; pin_range_start++)
{
nrf_gpio_cfg_input(pin_range_start, pull_config);
}
}
__STATIC_INLINE void nrf_gpio_cfg(
uint32_t pin_number,
nrf_gpio_pin_dir_t dir,
nrf_gpio_pin_input_t input,
nrf_gpio_pin_pull_t pull,
nrf_gpio_pin_drive_t drive,
nrf_gpio_pin_sense_t sense)
{
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
reg->PIN_CNF[pin_number] = ((uint32_t)dir << GPIO_PIN_CNF_DIR_Pos)
| ((uint32_t)input << GPIO_PIN_CNF_INPUT_Pos)
| ((uint32_t)pull << GPIO_PIN_CNF_PULL_Pos)
| ((uint32_t)drive << GPIO_PIN_CNF_DRIVE_Pos)
| ((uint32_t)sense << GPIO_PIN_CNF_SENSE_Pos);
}
__STATIC_INLINE void nrf_gpio_cfg_output(uint32_t pin_number)
{
nrf_gpio_cfg(
pin_number,
NRF_GPIO_PIN_DIR_OUTPUT,
NRF_GPIO_PIN_INPUT_DISCONNECT,
NRF_GPIO_PIN_NOPULL,
NRF_GPIO_PIN_S0S1,
NRF_GPIO_PIN_NOSENSE);
}
__STATIC_INLINE void nrf_gpio_cfg_input(uint32_t pin_number, nrf_gpio_pin_pull_t pull_config)
{
nrf_gpio_cfg(
pin_number,
NRF_GPIO_PIN_DIR_INPUT,
NRF_GPIO_PIN_INPUT_CONNECT,
pull_config,
NRF_GPIO_PIN_S0S1,
NRF_GPIO_PIN_NOSENSE);
}
__STATIC_INLINE void nrf_gpio_cfg_default(uint32_t pin_number)
{
nrf_gpio_cfg(
pin_number,
NRF_GPIO_PIN_DIR_INPUT,
NRF_GPIO_PIN_INPUT_DISCONNECT,
NRF_GPIO_PIN_NOPULL,
NRF_GPIO_PIN_S0S1,
NRF_GPIO_PIN_NOSENSE);
}
__STATIC_INLINE void nrf_gpio_cfg_watcher(uint32_t pin_number)
{
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
/*lint -e{845} // A zero has been given as right argument to operator '|'" */
uint32_t cnf = reg->PIN_CNF[pin_number] & ~GPIO_PIN_CNF_INPUT_Msk;
reg->PIN_CNF[pin_number] = cnf | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos);
}
__STATIC_INLINE void nrf_gpio_input_disconnect(uint32_t pin_number)
{
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
/*lint -e{845} // A zero has been given as right argument to operator '|'" */
uint32_t cnf = reg->PIN_CNF[pin_number] & ~GPIO_PIN_CNF_INPUT_Msk;
reg->PIN_CNF[pin_number] = cnf | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos);
}
__STATIC_INLINE void nrf_gpio_cfg_sense_input(uint32_t pin_number,
nrf_gpio_pin_pull_t pull_config,
nrf_gpio_pin_sense_t sense_config)
{
nrf_gpio_cfg(
pin_number,
NRF_GPIO_PIN_DIR_INPUT,
NRF_GPIO_PIN_INPUT_CONNECT,
pull_config,
NRF_GPIO_PIN_S0S1,
sense_config);
}
__STATIC_INLINE void nrf_gpio_cfg_sense_set(uint32_t pin_number, nrf_gpio_pin_sense_t sense_config)
{
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
/*lint -e{845} // A zero has been given as right argument to operator '|'" */
reg->PIN_CNF[pin_number] &= ~GPIO_PIN_CNF_SENSE_Msk;
reg->PIN_CNF[pin_number] |= (sense_config << GPIO_PIN_CNF_SENSE_Pos);
}
__STATIC_INLINE void nrf_gpio_pin_dir_set(uint32_t pin_number, nrf_gpio_pin_dir_t direction)
{
if (direction == NRF_GPIO_PIN_DIR_INPUT)
{
nrf_gpio_cfg(
pin_number,
NRF_GPIO_PIN_DIR_INPUT,
NRF_GPIO_PIN_INPUT_CONNECT,
NRF_GPIO_PIN_NOPULL,
NRF_GPIO_PIN_S0S1,
NRF_GPIO_PIN_NOSENSE);
}
else
{
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
reg->DIRSET = (1UL << pin_number);
}
}
__STATIC_INLINE void nrf_gpio_pin_set(uint32_t pin_number)
{
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
nrf_gpio_port_out_set(reg, 1UL << pin_number);
}
__STATIC_INLINE void nrf_gpio_pin_clear(uint32_t pin_number)
{
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
nrf_gpio_port_out_clear(reg, 1UL << pin_number);
}
__STATIC_INLINE void nrf_gpio_pin_toggle(uint32_t pin_number)
{
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
uint32_t pins_state = reg->OUT;
reg->OUTSET = (~pins_state & (1UL << pin_number));
reg->OUTCLR = (pins_state & (1UL << pin_number));
}
__STATIC_INLINE void nrf_gpio_pin_write(uint32_t pin_number, uint32_t value)
{
if (value == 0)
{
nrf_gpio_pin_clear(pin_number);
}
else
{
nrf_gpio_pin_set(pin_number);
}
}
__STATIC_INLINE uint32_t nrf_gpio_pin_read(uint32_t pin_number)
{
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
return ((nrf_gpio_port_in_read(reg) >> pin_number) & 1UL);
}
__STATIC_INLINE uint32_t nrf_gpio_pin_out_read(uint32_t pin_number)
{
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
return ((nrf_gpio_port_out_read(reg) >> pin_number) & 1UL);
}
__STATIC_INLINE nrf_gpio_pin_sense_t nrf_gpio_pin_sense_get(uint32_t pin_number)
{
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
return (nrf_gpio_pin_sense_t)((reg->PIN_CNF[pin_number] &
GPIO_PIN_CNF_SENSE_Msk) >> GPIO_PIN_CNF_SENSE_Pos);
}
__STATIC_INLINE nrf_gpio_pin_dir_t nrf_gpio_pin_dir_get(uint32_t pin_number)
{
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
return (nrf_gpio_pin_dir_t)((reg->PIN_CNF[pin_number] &
GPIO_PIN_CNF_DIR_Msk) >> GPIO_PIN_CNF_DIR_Pos);
}
__STATIC_INLINE nrf_gpio_pin_input_t nrf_gpio_pin_input_get(uint32_t pin_number)
{
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
return (nrf_gpio_pin_input_t)((reg->PIN_CNF[pin_number] &
GPIO_PIN_CNF_INPUT_Msk) >> GPIO_PIN_CNF_INPUT_Pos);
}
__STATIC_INLINE nrf_gpio_pin_pull_t nrf_gpio_pin_pull_get(uint32_t pin_number)
{
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
return (nrf_gpio_pin_pull_t)((reg->PIN_CNF[pin_number] &
GPIO_PIN_CNF_PULL_Msk) >> GPIO_PIN_CNF_PULL_Pos);
}
__STATIC_INLINE void nrf_gpio_port_dir_output_set(NRF_GPIO_Type * p_reg, uint32_t out_mask)
{
p_reg->DIRSET = out_mask;
}
__STATIC_INLINE void nrf_gpio_port_dir_input_set(NRF_GPIO_Type * p_reg, uint32_t in_mask)
{
p_reg->DIRCLR = in_mask;
}
__STATIC_INLINE void nrf_gpio_port_dir_write(NRF_GPIO_Type * p_reg, uint32_t value)
{
p_reg->DIR = value;
}
__STATIC_INLINE uint32_t nrf_gpio_port_dir_read(NRF_GPIO_Type const * p_reg)
{
return p_reg->DIR;
}
__STATIC_INLINE uint32_t nrf_gpio_port_in_read(NRF_GPIO_Type const * p_reg)
{
return p_reg->IN;
}
__STATIC_INLINE uint32_t nrf_gpio_port_out_read(NRF_GPIO_Type const * p_reg)
{
return p_reg->OUT;
}
__STATIC_INLINE void nrf_gpio_port_out_write(NRF_GPIO_Type * p_reg, uint32_t value)
{
p_reg->OUT = value;
}
__STATIC_INLINE void nrf_gpio_port_out_set(NRF_GPIO_Type * p_reg, uint32_t set_mask)
{
p_reg->OUTSET = set_mask;
}
__STATIC_INLINE void nrf_gpio_port_out_clear(NRF_GPIO_Type * p_reg, uint32_t clr_mask)
{
p_reg->OUTCLR = clr_mask;
}
__STATIC_INLINE void nrf_gpio_ports_read(uint32_t start_port, uint32_t length, uint32_t * p_masks)
{
NRF_GPIO_Type * gpio_regs[GPIO_COUNT] = GPIO_REG_LIST;
NRFX_ASSERT(start_port + length <= GPIO_COUNT);
uint32_t i;
for (i = start_port; i < (start_port + length); i++)
{
*p_masks = nrf_gpio_port_in_read(gpio_regs[i]);
p_masks++;
}
}
#if defined(NRF_GPIO_LATCH_PRESENT)
__STATIC_INLINE void nrf_gpio_latches_read(uint32_t start_port,
uint32_t length,
uint32_t * p_masks)
{
NRF_GPIO_Type * gpio_regs[GPIO_COUNT] = GPIO_REG_LIST;
uint32_t i;
for (i = start_port; i < (start_port + length); i++)
{
*p_masks = gpio_regs[i]->LATCH;
p_masks++;
}
}
__STATIC_INLINE void nrf_gpio_latches_read_and_clear(uint32_t start_port,
uint32_t length,
uint32_t * p_masks)
{
NRF_GPIO_Type * gpio_regs[GPIO_COUNT] = GPIO_REG_LIST;
uint32_t i;
for (i = start_port; i < (start_port + length); i++)
{
*p_masks = gpio_regs[i]->LATCH;
// The LATCH register is cleared by writing a '1' to the bit that shall be cleared.
gpio_regs[i]->LATCH = *p_masks;
p_masks++;
}
}
__STATIC_INLINE uint32_t nrf_gpio_pin_latch_get(uint32_t pin_number)
{
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
return (reg->LATCH & (1 << pin_number)) ? 1 : 0;
}
__STATIC_INLINE void nrf_gpio_pin_latch_clear(uint32_t pin_number)
{
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
reg->LATCH = (1 << pin_number);
}
#endif // defined(NRF_GPIO_LATCH_PRESENT)
__STATIC_INLINE bool nrf_gpio_pin_present_check(uint32_t pin_number)
{
uint32_t port = pin_number >> 5;
uint32_t mask = 0;
switch (port)
{
#ifdef P0_FEATURE_PINS_PRESENT
case 0:
mask = P0_FEATURE_PINS_PRESENT;
#if defined(NRF52820_XXAA) && defined(DEVELOP_IN_NRF52833)
/* Allow use of the following additional GPIOs that are connected to LEDs and buttons
* on the nRF52833 DK:
* - P0.11 - Button 1
* - P0.12 - Button 2
* - P0.13 - LED 1
* - P0.24 - Button 3
* - P0.25 - Button 4
*/
mask |= 0x03003800;
#endif // defined(NRF52820_XXAA) && defined(DEVELOP_IN_NRF52833)
break;
#endif
#ifdef P1_FEATURE_PINS_PRESENT
case 1:
mask = P1_FEATURE_PINS_PRESENT;
break;
#endif
}
pin_number &= 0x1F;
return (mask & (1UL << pin_number)) ? true : false;
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_GPIO_H__
+582
View File
@@ -0,0 +1,582 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_GPIOTE_H__
#define NRF_GPIOTE_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_gpiote_hal GPIOTE HAL
* @{
* @ingroup nrf_gpiote
* @brief Hardware access layer (HAL) for managing the GPIOTE peripheral.
*/
#if defined(GPIOTE_CONFIG_PORT_Msk) || defined(__NRFX_DOXYGEN__)
/** @brief Mask for covering port and pin bits in registers. */
#define GPIOTE_CONFIG_PORT_PIN_Msk (GPIOTE_CONFIG_PORT_Msk | GPIOTE_CONFIG_PSEL_Msk)
#else
#define GPIOTE_CONFIG_PORT_PIN_Msk GPIOTE_CONFIG_PSEL_Msk
#endif
/** @brief Polarity for the GPIOTE channel. */
typedef enum
{
NRF_GPIOTE_POLARITY_LOTOHI = GPIOTE_CONFIG_POLARITY_LoToHi, ///< Low to high.
NRF_GPIOTE_POLARITY_HITOLO = GPIOTE_CONFIG_POLARITY_HiToLo, ///< High to low.
NRF_GPIOTE_POLARITY_TOGGLE = GPIOTE_CONFIG_POLARITY_Toggle ///< Toggle.
} nrf_gpiote_polarity_t;
/** @brief Initial output value for the GPIOTE channel. */
typedef enum
{
NRF_GPIOTE_INITIAL_VALUE_LOW = GPIOTE_CONFIG_OUTINIT_Low, ///< Low to high.
NRF_GPIOTE_INITIAL_VALUE_HIGH = GPIOTE_CONFIG_OUTINIT_High ///< High to low.
} nrf_gpiote_outinit_t;
/** @brief GPIOTE tasks. */
typedef enum
{
NRF_GPIOTE_TASKS_OUT_0 = offsetof(NRF_GPIOTE_Type, TASKS_OUT[0]), /**< Out task 0. */
NRF_GPIOTE_TASKS_OUT_1 = offsetof(NRF_GPIOTE_Type, TASKS_OUT[1]), /**< Out task 1. */
NRF_GPIOTE_TASKS_OUT_2 = offsetof(NRF_GPIOTE_Type, TASKS_OUT[2]), /**< Out task 2. */
NRF_GPIOTE_TASKS_OUT_3 = offsetof(NRF_GPIOTE_Type, TASKS_OUT[3]), /**< Out task 3. */
#if (GPIOTE_CH_NUM > 4) || defined(__NRFX_DOXYGEN__)
NRF_GPIOTE_TASKS_OUT_4 = offsetof(NRF_GPIOTE_Type, TASKS_OUT[4]), /**< Out task 4. */
NRF_GPIOTE_TASKS_OUT_5 = offsetof(NRF_GPIOTE_Type, TASKS_OUT[5]), /**< Out task 5. */
NRF_GPIOTE_TASKS_OUT_6 = offsetof(NRF_GPIOTE_Type, TASKS_OUT[6]), /**< Out task 6. */
NRF_GPIOTE_TASKS_OUT_7 = offsetof(NRF_GPIOTE_Type, TASKS_OUT[7]), /**< Out task 7. */
#endif
#if defined(GPIOTE_FEATURE_SET_PRESENT) || defined(__NRFX_DOXYGEN__)
NRF_GPIOTE_TASKS_SET_0 = offsetof(NRF_GPIOTE_Type, TASKS_SET[0]), /**< Set task 0. */
NRF_GPIOTE_TASKS_SET_1 = offsetof(NRF_GPIOTE_Type, TASKS_SET[1]), /**< Set task 1. */
NRF_GPIOTE_TASKS_SET_2 = offsetof(NRF_GPIOTE_Type, TASKS_SET[2]), /**< Set task 2. */
NRF_GPIOTE_TASKS_SET_3 = offsetof(NRF_GPIOTE_Type, TASKS_SET[3]), /**< Set task 3. */
NRF_GPIOTE_TASKS_SET_4 = offsetof(NRF_GPIOTE_Type, TASKS_SET[4]), /**< Set task 4. */
NRF_GPIOTE_TASKS_SET_5 = offsetof(NRF_GPIOTE_Type, TASKS_SET[5]), /**< Set task 5. */
NRF_GPIOTE_TASKS_SET_6 = offsetof(NRF_GPIOTE_Type, TASKS_SET[6]), /**< Set task 6. */
NRF_GPIOTE_TASKS_SET_7 = offsetof(NRF_GPIOTE_Type, TASKS_SET[7]), /**< Set task 7. */
#endif
#if defined(GPIOTE_FEATURE_CLR_PRESENT) || defined(__NRFX_DOXYGEN__)
NRF_GPIOTE_TASKS_CLR_0 = offsetof(NRF_GPIOTE_Type, TASKS_CLR[0]), /**< Clear task 0. */
NRF_GPIOTE_TASKS_CLR_1 = offsetof(NRF_GPIOTE_Type, TASKS_CLR[1]), /**< Clear task 1. */
NRF_GPIOTE_TASKS_CLR_2 = offsetof(NRF_GPIOTE_Type, TASKS_CLR[2]), /**< Clear task 2. */
NRF_GPIOTE_TASKS_CLR_3 = offsetof(NRF_GPIOTE_Type, TASKS_CLR[3]), /**< Clear task 3. */
NRF_GPIOTE_TASKS_CLR_4 = offsetof(NRF_GPIOTE_Type, TASKS_CLR[4]), /**< Clear task 4. */
NRF_GPIOTE_TASKS_CLR_5 = offsetof(NRF_GPIOTE_Type, TASKS_CLR[5]), /**< Clear task 5. */
NRF_GPIOTE_TASKS_CLR_6 = offsetof(NRF_GPIOTE_Type, TASKS_CLR[6]), /**< Clear task 6. */
NRF_GPIOTE_TASKS_CLR_7 = offsetof(NRF_GPIOTE_Type, TASKS_CLR[7]), /**< Clear task 7. */
#endif
} nrf_gpiote_tasks_t;
/** @brief GPIOTE events. */
typedef enum
{
NRF_GPIOTE_EVENTS_IN_0 = offsetof(NRF_GPIOTE_Type, EVENTS_IN[0]), /**< In event 0. */
NRF_GPIOTE_EVENTS_IN_1 = offsetof(NRF_GPIOTE_Type, EVENTS_IN[1]), /**< In event 1. */
NRF_GPIOTE_EVENTS_IN_2 = offsetof(NRF_GPIOTE_Type, EVENTS_IN[2]), /**< In event 2. */
NRF_GPIOTE_EVENTS_IN_3 = offsetof(NRF_GPIOTE_Type, EVENTS_IN[3]), /**< In event 3. */
#if (GPIOTE_CH_NUM > 4) || defined(__NRFX_DOXYGEN__)
NRF_GPIOTE_EVENTS_IN_4 = offsetof(NRF_GPIOTE_Type, EVENTS_IN[4]), /**< In event 4. */
NRF_GPIOTE_EVENTS_IN_5 = offsetof(NRF_GPIOTE_Type, EVENTS_IN[5]), /**< In event 5. */
NRF_GPIOTE_EVENTS_IN_6 = offsetof(NRF_GPIOTE_Type, EVENTS_IN[6]), /**< In event 6. */
NRF_GPIOTE_EVENTS_IN_7 = offsetof(NRF_GPIOTE_Type, EVENTS_IN[7]), /**< In event 7. */
#endif
NRF_GPIOTE_EVENTS_PORT = offsetof(NRF_GPIOTE_Type, EVENTS_PORT), /**< Port event. */
} nrf_gpiote_events_t;
/** @brief GPIOTE interrupts. */
typedef enum
{
NRF_GPIOTE_INT_IN0_MASK = GPIOTE_INTENSET_IN0_Msk, /**< GPIOTE interrupt from IN0. */
NRF_GPIOTE_INT_IN1_MASK = GPIOTE_INTENSET_IN1_Msk, /**< GPIOTE interrupt from IN1. */
NRF_GPIOTE_INT_IN2_MASK = GPIOTE_INTENSET_IN2_Msk, /**< GPIOTE interrupt from IN2. */
NRF_GPIOTE_INT_IN3_MASK = GPIOTE_INTENSET_IN3_Msk, /**< GPIOTE interrupt from IN3. */
#if (GPIOTE_CH_NUM > 4) || defined(__NRFX_DOXYGEN__)
NRF_GPIOTE_INT_IN4_MASK = GPIOTE_INTENSET_IN4_Msk, /**< GPIOTE interrupt from IN4. */
NRF_GPIOTE_INT_IN5_MASK = GPIOTE_INTENSET_IN5_Msk, /**< GPIOTE interrupt from IN5. */
NRF_GPIOTE_INT_IN6_MASK = GPIOTE_INTENSET_IN6_Msk, /**< GPIOTE interrupt from IN6. */
NRF_GPIOTE_INT_IN7_MASK = GPIOTE_INTENSET_IN7_Msk, /**< GPIOTE interrupt from IN7. */
#endif
NRF_GPIOTE_INT_PORT_MASK = (int)GPIOTE_INTENSET_PORT_Msk, /**< GPIOTE interrupt from PORT event. */
} nrf_gpiote_int_t;
#if (GPIOTE_CH_NUM == 4) || defined(__NRFX_DOXYGEN__)
/** @brief Mask holding positions of available GPIOTE input interrupts. */
#define NRF_GPIOTE_INT_IN_MASK (NRF_GPIOTE_INT_IN0_MASK | NRF_GPIOTE_INT_IN1_MASK |\
NRF_GPIOTE_INT_IN2_MASK | NRF_GPIOTE_INT_IN3_MASK)
#else
#define NRF_GPIOTE_INT_IN_MASK (NRF_GPIOTE_INT_IN0_MASK | NRF_GPIOTE_INT_IN1_MASK |\
NRF_GPIOTE_INT_IN2_MASK | NRF_GPIOTE_INT_IN3_MASK |\
NRF_GPIOTE_INT_IN4_MASK | NRF_GPIOTE_INT_IN5_MASK |\
NRF_GPIOTE_INT_IN6_MASK | NRF_GPIOTE_INT_IN7_MASK)
#endif
/**
* @brief Function for activating the specified GPIOTE task.
*
* @param[in] task Task.
*/
__STATIC_INLINE void nrf_gpiote_task_set(nrf_gpiote_tasks_t task);
/**
* @brief Function for getting the address of the specified GPIOTE task.
*
* @param[in] task Task.
*
* @return Address of the specified task.
*/
__STATIC_INLINE uint32_t nrf_gpiote_task_addr_get(nrf_gpiote_tasks_t task);
/**
* @brief Function for getting the state of the specified GPIOTE event.
*
* @param[in] event Event.
*
* @retval true The event is set.
* @retval false The event is not set.
*/
__STATIC_INLINE bool nrf_gpiote_event_is_set(nrf_gpiote_events_t event);
/**
* @brief Function for clearing the specified GPIOTE event.
*
* @param[in] event Event.
*/
__STATIC_INLINE void nrf_gpiote_event_clear(nrf_gpiote_events_t event);
/**
* @brief Function for getting the address of the specified GPIOTE event.
*
* @param[in] event Event.
*
* @return Address of the specified event.
*/
__STATIC_INLINE uint32_t nrf_gpiote_event_addr_get(nrf_gpiote_events_t event);
/**
* @brief Function for enabling interrupts.
*
* @param[in] mask Mask of interrupts to be enabled.
*/
__STATIC_INLINE void nrf_gpiote_int_enable(uint32_t mask);
/**
* @brief Function for disabling interrupts.
*
* @param[in] mask Mask of interrupts to be disabled.
*/
__STATIC_INLINE void nrf_gpiote_int_disable(uint32_t mask);
/**
* @brief Function for checking if interrupts are enabled.
*
* @param[in] mask Mask of interrupts to be checked.
*
* @return Mask with enabled interrupts.
*/
__STATIC_INLINE uint32_t nrf_gpiote_int_is_enabled(uint32_t mask);
#if defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting the subscribe configuration for a given
* GPIOTE task.
*
* @param[in] task Task for which to set the configuration.
* @param[in] channel Channel through which to subscribe events.
*/
__STATIC_INLINE void nrf_gpiote_subscribe_set(nrf_gpiote_tasks_t task,
uint8_t channel);
/**
* @brief Function for clearing the subscribe configuration for a given
* GPIOTE task.
*
* @param[in] task Task for which to clear the configuration.
*/
__STATIC_INLINE void nrf_gpiote_subscribe_clear(nrf_gpiote_tasks_t task);
/**
* @brief Function for setting the publish configuration for a given
* GPIOTE event.
*
* @param[in] event Event for which to set the configuration.
* @param[in] channel Channel through which to publish the event.
*/
__STATIC_INLINE void nrf_gpiote_publish_set(nrf_gpiote_events_t event,
uint8_t channel);
/**
* @brief Function for clearing the publish configuration for a given
* GPIOTE event.
*
* @param[in] event Event for which to clear the configuration.
*/
__STATIC_INLINE void nrf_gpiote_publish_clear(nrf_gpiote_events_t event);
#endif // defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for enabling a GPIOTE event.
*
* @param[in] idx Task-Event index.
*/
__STATIC_INLINE void nrf_gpiote_event_enable(uint32_t idx);
/**
* @brief Function for disabling a GPIOTE event.
*
* @param[in] idx Task-Event index.
*/
__STATIC_INLINE void nrf_gpiote_event_disable(uint32_t idx);
/**
* @brief Function for configuring a GPIOTE event.
*
* @param[in] idx Task-Event index.
* @param[in] pin Pin associated with event.
* @param[in] polarity Transition that should generate an event.
*/
__STATIC_INLINE void nrf_gpiote_event_configure(uint32_t idx,
uint32_t pin,
nrf_gpiote_polarity_t polarity);
/**
* @brief Function for getting the pin associated with a GPIOTE event.
*
* @param[in] idx Task-Event index.
*
* @return Pin number.
*/
__STATIC_INLINE uint32_t nrf_gpiote_event_pin_get(uint32_t idx);
/**
* @brief Function for getting the polarity associated with a GPIOTE event.
*
* @param[in] idx Task-Event index.
*
* @return Polarity.
*/
__STATIC_INLINE nrf_gpiote_polarity_t nrf_gpiote_event_polarity_get(uint32_t idx);
/**
* @brief Function for enabling a GPIOTE task.
*
* @param[in] idx Task-Event index.
*/
__STATIC_INLINE void nrf_gpiote_task_enable(uint32_t idx);
/**
* @brief Function for disabling a GPIOTE task.
*
* @param[in] idx Task-Event index.
*/
__STATIC_INLINE void nrf_gpiote_task_disable(uint32_t idx);
/**
* @brief Function for configuring a GPIOTE task.
*
* @note Function is not configuring mode field so task is disabled after this function is called.
*
* @param[in] idx Task-Event index.
* @param[in] pin Pin associated with event.
* @param[in] polarity Transition that should generate an event.
* @param[in] init_val Initial value of the pin.
*/
__STATIC_INLINE void nrf_gpiote_task_configure(uint32_t idx,
uint32_t pin,
nrf_gpiote_polarity_t polarity,
nrf_gpiote_outinit_t init_val);
/**
* @brief Function for forcing the specified state on the pin connected to GPIOTE.
*
* @param[in] idx Task-Event index.
* @param[in] init_val Pin state.
*/
__STATIC_INLINE void nrf_gpiote_task_force(uint32_t idx, nrf_gpiote_outinit_t init_val);
/**
* @brief Function for resetting a GPIOTE task event configuration to the default state.
*
* @param[in] idx Task-Event index.
*/
__STATIC_INLINE void nrf_gpiote_te_default(uint32_t idx);
/**@brief Function for checking if particular Task-Event is enabled.
*
* @param[in] idx Task-Event index.
*
* @retval true The Task-Event mode is set to Task or Event.
* @retval false The Task-Event mode is set to Disabled.
*/
__STATIC_INLINE bool nrf_gpiote_te_is_enabled(uint32_t idx);
/**
* @brief Function for getting the OUT task associated with the specified GPIOTE channel.
*
* @param[in] index Channel index.
*
* @return Requested OUT task.
*/
__STATIC_INLINE nrf_gpiote_tasks_t nrf_gpiote_out_task_get(uint8_t index);
#if defined(GPIOTE_FEATURE_SET_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for getting the SET task associated with the specified GPIOTE channel.
*
* @param[in] index Channel index.
*
* @return Requested SET task.
*/
__STATIC_INLINE nrf_gpiote_tasks_t nrf_gpiote_set_task_get(uint8_t index);
#endif
#if defined(GPIOTE_FEATURE_CLR_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for getting the CLR task associated with the specified GPIOTE channel.
*
* @param[in] index Channel index.
*
* @return Requested CLR task.
*/
__STATIC_INLINE nrf_gpiote_tasks_t nrf_gpiote_clr_task_get(uint8_t index);
#endif
/**
* @brief Function for getting the IN event associated with the specified GPIOTE channel.
*
* @param[in] index Channel index.
*
* @return Requested IN event.
*/
__STATIC_INLINE nrf_gpiote_events_t nrf_gpiote_in_event_get(uint8_t index);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_gpiote_task_set(nrf_gpiote_tasks_t task)
{
*(__IO uint32_t *)((uint32_t)NRF_GPIOTE + task) = 0x1UL;
}
__STATIC_INLINE uint32_t nrf_gpiote_task_addr_get(nrf_gpiote_tasks_t task)
{
return ((uint32_t)NRF_GPIOTE + task);
}
__STATIC_INLINE bool nrf_gpiote_event_is_set(nrf_gpiote_events_t event)
{
return (*(uint32_t *)nrf_gpiote_event_addr_get(event) == 0x1UL) ? true : false;
}
__STATIC_INLINE void nrf_gpiote_event_clear(nrf_gpiote_events_t event)
{
*(uint32_t *)nrf_gpiote_event_addr_get(event) = 0;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)nrf_gpiote_event_addr_get(event));
(void)dummy;
#endif
}
__STATIC_INLINE uint32_t nrf_gpiote_event_addr_get(nrf_gpiote_events_t event)
{
return ((uint32_t)NRF_GPIOTE + event);
}
__STATIC_INLINE void nrf_gpiote_int_enable(uint32_t mask)
{
NRF_GPIOTE->INTENSET = mask;
}
__STATIC_INLINE void nrf_gpiote_int_disable(uint32_t mask)
{
NRF_GPIOTE->INTENCLR = mask;
}
__STATIC_INLINE uint32_t nrf_gpiote_int_is_enabled(uint32_t mask)
{
return (NRF_GPIOTE->INTENSET & mask);
}
#if defined(DPPI_PRESENT)
__STATIC_INLINE void nrf_gpiote_subscribe_set(nrf_gpiote_tasks_t task,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) NRF_GPIOTE + (uint32_t) task + 0x80uL)) =
((uint32_t)channel | GPIOTE_SUBSCRIBE_OUT_EN_Msk);
}
__STATIC_INLINE void nrf_gpiote_subscribe_clear(nrf_gpiote_tasks_t task)
{
*((volatile uint32_t *) ((uint8_t *) NRF_GPIOTE + (uint32_t) task + 0x80uL)) = 0;
}
__STATIC_INLINE void nrf_gpiote_publish_set(nrf_gpiote_events_t event,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) NRF_GPIOTE + (uint32_t) event + 0x80uL)) =
((uint32_t)channel | GPIOTE_PUBLISH_IN_EN_Msk);
}
__STATIC_INLINE void nrf_gpiote_publish_clear(nrf_gpiote_events_t event)
{
*((volatile uint32_t *) ((uint8_t *) NRF_GPIOTE + (uint32_t) event + 0x80uL)) = 0;
}
#endif // defined(DPPI_PRESENT)
__STATIC_INLINE void nrf_gpiote_event_enable(uint32_t idx)
{
NRF_GPIOTE->CONFIG[idx] |= GPIOTE_CONFIG_MODE_Event;
}
__STATIC_INLINE void nrf_gpiote_event_disable(uint32_t idx)
{
NRF_GPIOTE->CONFIG[idx] &= ~GPIOTE_CONFIG_MODE_Event;
}
__STATIC_INLINE void nrf_gpiote_event_configure(uint32_t idx, uint32_t pin, nrf_gpiote_polarity_t polarity)
{
NRF_GPIOTE->CONFIG[idx] &= ~(GPIOTE_CONFIG_PORT_PIN_Msk | GPIOTE_CONFIG_POLARITY_Msk);
NRF_GPIOTE->CONFIG[idx] |= ((pin << GPIOTE_CONFIG_PSEL_Pos) & GPIOTE_CONFIG_PORT_PIN_Msk) |
((polarity << GPIOTE_CONFIG_POLARITY_Pos) & GPIOTE_CONFIG_POLARITY_Msk);
}
__STATIC_INLINE uint32_t nrf_gpiote_event_pin_get(uint32_t idx)
{
return ((NRF_GPIOTE->CONFIG[idx] & GPIOTE_CONFIG_PORT_PIN_Msk) >> GPIOTE_CONFIG_PSEL_Pos);
}
__STATIC_INLINE nrf_gpiote_polarity_t nrf_gpiote_event_polarity_get(uint32_t idx)
{
return (nrf_gpiote_polarity_t)((NRF_GPIOTE->CONFIG[idx] & GPIOTE_CONFIG_POLARITY_Msk) >> GPIOTE_CONFIG_POLARITY_Pos);
}
__STATIC_INLINE void nrf_gpiote_task_enable(uint32_t idx)
{
uint32_t final_config = NRF_GPIOTE->CONFIG[idx] | GPIOTE_CONFIG_MODE_Task;
#ifdef NRF51
/* Workaround for the OUTINIT PAN. When nrf_gpiote_task_config() is called a glitch happens
on the GPIO if the GPIO in question is already assigned to GPIOTE and the pin is in the
correct state in GPIOTE, but not in the OUT register. */
/* Configure channel to not existing, not connected to the pin, and configure as a tasks that will set it to proper level */
NRF_GPIOTE->CONFIG[idx] = final_config | (((31) << GPIOTE_CONFIG_PSEL_Pos) & GPIOTE_CONFIG_PORT_PIN_Msk);
__NOP();
__NOP();
__NOP();
#endif
NRF_GPIOTE->CONFIG[idx] = final_config;
}
__STATIC_INLINE void nrf_gpiote_task_disable(uint32_t idx)
{
NRF_GPIOTE->CONFIG[idx] &= ~GPIOTE_CONFIG_MODE_Task;
}
__STATIC_INLINE void nrf_gpiote_task_configure(uint32_t idx, uint32_t pin,
nrf_gpiote_polarity_t polarity,
nrf_gpiote_outinit_t init_val)
{
NRF_GPIOTE->CONFIG[idx] &= ~(GPIOTE_CONFIG_PORT_PIN_Msk |
GPIOTE_CONFIG_POLARITY_Msk |
GPIOTE_CONFIG_OUTINIT_Msk);
NRF_GPIOTE->CONFIG[idx] |= ((pin << GPIOTE_CONFIG_PSEL_Pos) & GPIOTE_CONFIG_PORT_PIN_Msk) |
((polarity << GPIOTE_CONFIG_POLARITY_Pos) & GPIOTE_CONFIG_POLARITY_Msk) |
((init_val << GPIOTE_CONFIG_OUTINIT_Pos) & GPIOTE_CONFIG_OUTINIT_Msk);
}
__STATIC_INLINE void nrf_gpiote_task_force(uint32_t idx, nrf_gpiote_outinit_t init_val)
{
NRF_GPIOTE->CONFIG[idx] = (NRF_GPIOTE->CONFIG[idx] & ~GPIOTE_CONFIG_OUTINIT_Msk)
| ((init_val << GPIOTE_CONFIG_OUTINIT_Pos) & GPIOTE_CONFIG_OUTINIT_Msk);
}
__STATIC_INLINE void nrf_gpiote_te_default(uint32_t idx)
{
NRF_GPIOTE->CONFIG[idx] = 0;
}
__STATIC_INLINE bool nrf_gpiote_te_is_enabled(uint32_t idx)
{
return (NRF_GPIOTE->CONFIG[idx] & GPIOTE_CONFIG_MODE_Msk) != GPIOTE_CONFIG_MODE_Disabled;
}
__STATIC_INLINE nrf_gpiote_tasks_t nrf_gpiote_out_task_get(uint8_t index)
{
NRFX_ASSERT(index < NRFX_ARRAY_SIZE(NRF_GPIOTE->TASKS_OUT));
return (nrf_gpiote_tasks_t)NRFX_OFFSETOF(NRF_GPIOTE_Type, TASKS_OUT[index]);
}
#if defined(GPIOTE_FEATURE_SET_PRESENT)
__STATIC_INLINE nrf_gpiote_tasks_t nrf_gpiote_set_task_get(uint8_t index)
{
NRFX_ASSERT(index < NRFX_ARRAY_SIZE(NRF_GPIOTE->TASKS_SET));
return (nrf_gpiote_tasks_t)NRFX_OFFSETOF(NRF_GPIOTE_Type, TASKS_SET[index]);
}
#endif
#if defined(GPIOTE_FEATURE_CLR_PRESENT)
__STATIC_INLINE nrf_gpiote_tasks_t nrf_gpiote_clr_task_get(uint8_t index)
{
NRFX_ASSERT(index < NRFX_ARRAY_SIZE(NRF_GPIOTE->TASKS_CLR));
return (nrf_gpiote_tasks_t)NRFX_OFFSETOF(NRF_GPIOTE_Type, TASKS_CLR[index]);
}
#endif
__STATIC_INLINE nrf_gpiote_events_t nrf_gpiote_in_event_get(uint8_t index)
{
NRFX_ASSERT(index < NRFX_ARRAY_SIZE(NRF_GPIOTE->EVENTS_IN));
return (nrf_gpiote_events_t)NRFX_OFFSETOF(NRF_GPIOTE_Type, EVENTS_IN[index]);
}
#endif //SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif
+278
View File
@@ -0,0 +1,278 @@
/**
* Copyright (c) 2018 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_KMU_H__
#define NRF_KMU_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_kmu_hal KMU HAL
* @{
* @ingroup nrf_kmu
* @brief Hardware access layer for managing the Key Management Unit (KMU) peripheral.
*/
/** @brief KMU tasks. */
typedef enum
{
NRF_KMU_TASK_PUSH_KEYSLOT = offsetof(NRF_KMU_Type, TASKS_PUSH_KEYSLOT), ///< Push a key slot over secure APB.
} nrf_kmu_task_t;
/** @brief KMU events. */
typedef enum
{
NRF_KMU_EVENT_KEYSLOT_PUSHED = offsetof(NRF_KMU_Type, EVENTS_KEYSLOT_PUSHED), ///< Key successfully pushed over secure APB.
NRF_KMU_EVENT_KEYSLOT_REVOKED = offsetof(NRF_KMU_Type, EVENTS_KEYSLOT_REVOKED), ///< Key has been revoked and cannot be tasked for selection.
NRF_KMU_EVENT_KEYSLOT_ERROR = offsetof(NRF_KMU_Type, EVENTS_KEYSLOT_ERROR) ///< No key slot selected or no destination address defined or error during push mechanism.
} nrf_kmu_event_t;
/** @brief KMU interrupts. */
typedef enum
{
NRF_KMU_INT_PUSHED_MASK = KMU_INTEN_KEYSLOT_PUSHED_Msk, ///< Interrupt on KEYSLOT_PUSHED event.
NRF_KMU_INT_REVOKED_MASK = KMU_INTEN_KEYSLOT_REVOKED_Msk, ///< Interrupt on KEYSLOT_REVOKED event.
NRF_KMU_INT_ERROR_MASK = KMU_INTEN_KEYSLOT_ERROR_Msk ///< Interrupt on KEYSLOT_ERROR event.
} nrf_kmu_int_mask_t;
/** @brief KMU operation status. */
typedef enum
{
NRF_KMU_STATUS_BLOCKED_MASK = KMU_STATUS_BLOCKED_Msk, ///< Access violation detected and blocked.
NRF_KMU_STATUS_SELECTED_MASK = KMU_STATUS_SELECTED_Msk, ///< Key slot ID successfully selected by KMU
} nrf_kmu_status_t;
/**
* @brief Function for activating a specific KMU task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task to be activated.
*/
__STATIC_INLINE void nrf_kmu_task_trigger(NRF_KMU_Type * p_reg, nrf_kmu_task_t task);
/**
* @brief Function for getting the address of a specific KMU task register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Requested task.
*
* @return Address of the specified task register.
*/
__STATIC_INLINE uint32_t nrf_kmu_task_address_get(NRF_KMU_Type const * p_reg, nrf_kmu_task_t task);
/**
* @brief Function for clearing a specific KMU event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to clear.
*/
__STATIC_INLINE void nrf_kmu_event_clear(NRF_KMU_Type * p_reg, nrf_kmu_event_t event);
/**
* @brief Function for retrieving the state of the KMU event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be checked.
*
* @retval true The event has been generated.
* @retval false The event has not been generated.
*/
__STATIC_INLINE bool nrf_kmu_event_check(NRF_KMU_Type const * p_reg, nrf_kmu_event_t event);
/**
* @brief Function for getting the address of a specific KMU event register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Requested event.
*
* @return Address of the specified event register.
*/
__STATIC_INLINE uint32_t nrf_kmu_event_address_get(NRF_KMU_Type const * p_reg,
nrf_kmu_event_t event);
/**
* @brief Function for enabling specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Interrupts to be enabled.
*/
__STATIC_INLINE void nrf_kmu_int_enable(NRF_KMU_Type * p_reg, uint32_t mask);
/**
* @brief Function for disabling specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Interrupts to be disabled.
*/
__STATIC_INLINE void nrf_kmu_int_disable(NRF_KMU_Type * p_reg, uint32_t mask);
/**
* @brief Function for retrieving the state of a given interrupt.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] kmu_int Interrupt to be checked.
*
* @retval true The interrupt is enabled.
* @retval false The interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_kmu_int_enable_check(NRF_KMU_Type const * p_reg,
nrf_kmu_int_mask_t kmu_int);
/**
* @brief Function for retrieving the state of interrupts.
*
* Function returns bitmask. Please use @ref nrf_kmu_int_mask_t to check interrupts status.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Bitmask with pending interrupts bits.
*/
__STATIC_INLINE uint32_t nrf_kmu_intpend_get(NRF_KMU_Type const * p_reg);
/**
* @brief Function for getting status bits of the KMU operation.
*
* Function returns bitmask. Please use @ref nrf_kmu_status_t to check operations status.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Bitmask with operation status bits.
*/
__STATIC_INLINE uint32_t nrf_kmu_status_get(NRF_KMU_Type const * p_reg);
/**
* @brief Function for selecting the key slot ID.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] keyslot_id Key slot ID to be read over AHB or pushed over
* secure APB when TASKS_PUSH_KEYSLOT is started.
*/
__STATIC_INLINE void nrf_kmu_keyslot_set(NRF_KMU_Type * p_reg, uint8_t keyslot_id);
/**
* @brief Function for getting the key slot ID.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Key slot ID.
*/
__STATIC_INLINE uint8_t nrf_kmu_keyslot_get(NRF_KMU_Type const * p_reg);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_kmu_task_trigger(NRF_KMU_Type * p_reg, nrf_kmu_task_t task)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)task)) = 0x1UL;
}
__STATIC_INLINE uint32_t nrf_kmu_task_address_get(NRF_KMU_Type const * p_reg, nrf_kmu_task_t task)
{
return ((uint32_t)p_reg + (uint32_t)task);
}
__STATIC_INLINE void nrf_kmu_event_clear(NRF_KMU_Type * p_reg, nrf_kmu_event_t event)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0x0UL;
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event));
(void)dummy;
}
__STATIC_INLINE bool nrf_kmu_event_check(NRF_KMU_Type const * p_reg, nrf_kmu_event_t event)
{
return (bool)*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE uint32_t nrf_kmu_event_address_get(NRF_KMU_Type const * p_reg,
nrf_kmu_event_t event)
{
return ((uint32_t)p_reg + (uint32_t)event);
}
__STATIC_INLINE void nrf_kmu_int_enable(NRF_KMU_Type * p_reg, uint32_t mask)
{
p_reg->INTENSET = mask;
}
__STATIC_INLINE void nrf_kmu_int_disable(NRF_KMU_Type * p_reg, uint32_t mask)
{
p_reg->INTENCLR = mask;
}
__STATIC_INLINE bool nrf_kmu_int_enable_check(NRF_KMU_Type const * p_reg,
nrf_kmu_int_mask_t kmu_int)
{
return (bool)(p_reg->INTENSET & kmu_int);
}
__STATIC_INLINE uint32_t nrf_kmu_intpend_get(NRF_KMU_Type const * p_reg)
{
return p_reg->INTPEND;
}
__STATIC_INLINE uint32_t nrf_kmu_status_get(NRF_KMU_Type const * p_reg)
{
return p_reg->STATUS;
}
__STATIC_INLINE void nrf_kmu_keyslot_set(NRF_KMU_Type * p_reg, uint8_t keyslot_id)
{
p_reg->SELECTKEYSLOT = (uint32_t) keyslot_id;
}
__STATIC_INLINE uint8_t nrf_kmu_keyslot_get(NRF_KMU_Type const * p_reg)
{
return (uint8_t) p_reg->SELECTKEYSLOT;
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_KMU_H__
+185
View File
@@ -0,0 +1,185 @@
/**
* Copyright (c) 2019 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_MPU_H__
#define NRF_MPU_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_mpu_hal MPU HAL
* @{
* @ingroup nrf_mpu
* @brief Hardware access layer for managing the Memory Protection Unit (MPU) peripheral.
*/
/**
* @brief Macro for getting MPU region configuration mask for the specified peripheral.
*
* @param[in] base_addr Peripheral base address.
*
* @return MPU configuration mask for the specified peripheral.
*/
#define NRF_MPU_PERIPHERAL_MASK_GET(base_addr) (1UL << NRFX_PERIPHERAL_ID_GET(base_addr))
/**
* @brief Function for setting the size of the RAM region 0.
*
* When memory protection is enabled, the Memory Protection Unit enforces
* runtime protection and readback protection of resources classified as region 0.
* See the product specification for more information.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] size Size of the RAM region 0, in bytes. Must be word-aligned.
*/
__STATIC_INLINE void nrf_mpu_region0_ram_size_set(NRF_MPU_Type * p_reg, uint32_t size);
/**
* @brief Function for configuring specified peripherals in the memory region 0.
*
* When the memory protection is enabled, the Memory Protection Unit enforces
* runtime protection and readback protection of resources classified as region 0.
* See the product specification for more information.
*
* After reset, all peripherals are configured as *not* assigned to region 0.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] peripheral_mask Mask that specifies peripherals to be configured in the memory region 0.
* Compose this mask using @ref NRF_MPU_PERIPHERAL_MASK_GET macro.
*/
__STATIC_INLINE void nrf_mpu_region0_peripherals_set(NRF_MPU_Type * p_reg,
uint32_t peripheral_mask);
/**
* @brief Function for getting the bitmask that specifies peripherals configured in the memory region 0.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Bitmask representing peripherals configured in region 0.
*/
__STATIC_INLINE uint32_t nrf_mpu_region0_peripherals_get(NRF_MPU_Type const * p_reg);
/**
* @brief Function for enabling protection for specified non-volatile memory blocks.
*
* Blocks are arranged into groups of 32 blocks each. Each block size is 4 kB.
* Any attempt to write or erase a protected block will result in hard fault.
* The memory block protection can be disabled only by resetting the device.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] group_idx Non-volatile memory group containing memory blocks to protect.
* @param[in] block_mask Non-volatile memory blocks to protect. Each bit in bitmask represents
* one memory block in the specified group.
*/
__STATIC_INLINE void nrf_mpu_nvm_blocks_protection_enable(NRF_MPU_Type * p_reg,
uint8_t group_idx,
uint32_t block_mask);
/**
* @brief Function for setting the non-volatile memory (NVM) protection during debug.
*
* NVM protection during debug is disabled by default.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] enable True if NVM protection during debug is to be enabled.
* False if otherwise.
*/
__STATIC_INLINE void nrf_mpu_nvm_protection_in_debug_set(NRF_MPU_Type * p_reg,
bool enable);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_mpu_region0_ram_size_set(NRF_MPU_Type * p_reg, uint32_t size)
{
NRFX_ASSERT(nrfx_is_word_aligned((const void *)size));
p_reg->RLENR0 = size;
}
__STATIC_INLINE void nrf_mpu_region0_peripherals_set(NRF_MPU_Type * p_reg,
uint32_t peripheral_mask)
{
p_reg->PERR0 = peripheral_mask;
}
__STATIC_INLINE uint32_t nrf_mpu_region0_peripherals_get(NRF_MPU_Type const * p_reg)
{
return p_reg->PERR0;
}
__STATIC_INLINE void nrf_mpu_nvm_blocks_protection_enable(NRF_MPU_Type * p_reg,
uint8_t group_idx,
uint32_t block_mask)
{
switch (group_idx)
{
case 0:
p_reg->PROTENSET0 = block_mask;
break;
case 1:
p_reg->PROTENSET1 = block_mask;
break;
default:
NRFX_ASSERT(false);
break;
}
}
__STATIC_INLINE void nrf_mpu_nvm_protection_in_debug_set(NRF_MPU_Type * p_reg,
bool enable)
{
p_reg->DISABLEINDEBUG =
(enable ? 0 : MPU_DISABLEINDEBUG_DISABLEINDEBUG_Msk);
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_MPU_H__
+425
View File
@@ -0,0 +1,425 @@
/**
* Copyright (c) 2019 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_MWU_H__
#define NRF_MWU_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_mwu_hal MWU HAL
* @{
* @ingroup nrf_mwu
* @brief Hardware access layer for managing the Memory Watch Unit (MWU) peripheral.
*/
/** @brief MWU events. */
typedef enum
{
NRF_MWU_EVENT_REGION0_WRITE = offsetof(NRF_MWU_Type, EVENTS_REGION[0].WA), ///< Write access to region 0 detected.
NRF_MWU_EVENT_REGION0_READ = offsetof(NRF_MWU_Type, EVENTS_REGION[0].RA), ///< Read access to region 0 detected.
NRF_MWU_EVENT_REGION1_WRITE = offsetof(NRF_MWU_Type, EVENTS_REGION[1].WA), ///< Write access to region 1 detected.
NRF_MWU_EVENT_REGION1_READ = offsetof(NRF_MWU_Type, EVENTS_REGION[1].RA), ///< Read access to region 1 detected.
NRF_MWU_EVENT_REGION2_WRITE = offsetof(NRF_MWU_Type, EVENTS_REGION[2].WA), ///< Write access to region 2 detected.
NRF_MWU_EVENT_REGION2_READ = offsetof(NRF_MWU_Type, EVENTS_REGION[2].RA), ///< Read access to region 2 detected.
NRF_MWU_EVENT_REGION3_WRITE = offsetof(NRF_MWU_Type, EVENTS_REGION[3].WA), ///< Write access to region 3 detected.
NRF_MWU_EVENT_REGION3_READ = offsetof(NRF_MWU_Type, EVENTS_REGION[3].RA), ///< Read access to region 3 detected.
NRF_MWU_EVENT_PREGION0_WRITE = offsetof(NRF_MWU_Type, EVENTS_PREGION[0].WA), ///< Write access to peripheral region 0 detected.
NRF_MWU_EVENT_PREGION0_READ = offsetof(NRF_MWU_Type, EVENTS_PREGION[0].RA), ///< Read access to peripheral region 0 detected.
NRF_MWU_EVENT_PREGION1_WRITE = offsetof(NRF_MWU_Type, EVENTS_PREGION[1].WA), ///< Write access to peripheral region 1 detected.
NRF_MWU_EVENT_PREGION1_READ = offsetof(NRF_MWU_Type, EVENTS_PREGION[1].RA), ///< Read access to peripheral region 1 detected.
} nrf_mwu_event_t;
/** @brief MWU interrupt masks. */
typedef enum
{
NRF_MWU_INT_REGION0_WRITE_MASK = MWU_INTEN_REGION0WA_Msk, ///< Interrupt on REGION[0].WA event.
NRF_MWU_INT_REGION0_READ_MASK = MWU_INTEN_REGION0RA_Msk, ///< Interrupt on REGION[0].RA event.
NRF_MWU_INT_REGION1_WRITE_MASK = MWU_INTEN_REGION1WA_Msk, ///< Interrupt on REGION[1].WA event.
NRF_MWU_INT_REGION1_READ_MASK = MWU_INTEN_REGION1RA_Msk, ///< Interrupt on REGION[1].RA event.
NRF_MWU_INT_REGION2_WRITE_MASK = MWU_INTEN_REGION2WA_Msk, ///< Interrupt on REGION[2].WA event.
NRF_MWU_INT_REGION2_READ_MASK = MWU_INTEN_REGION2RA_Msk, ///< Interrupt on REGION[2].RA event.
NRF_MWU_INT_REGION3_WRITE_MASK = MWU_INTEN_REGION3WA_Msk, ///< Interrupt on REGION[3].WA event.
NRF_MWU_INT_REGION3_READ_MASK = MWU_INTEN_REGION3RA_Msk, ///< Interrupt on REGION[3].RA event.
NRF_MWU_INT_PREGION0_WRITE_MASK = MWU_INTEN_PREGION0WA_Msk, ///< Interrupt on PREGION[0].WA event.
NRF_MWU_INT_PREGION0_READ_MASK = MWU_INTEN_PREGION0RA_Msk, ///< Interrupt on PREGION[0].RA event.
NRF_MWU_INT_PREGION1_WRITE_MASK = MWU_INTEN_PREGION1WA_Msk, ///< Interrupt on PREGION[1].WA event.
NRF_MWU_INT_PREGION1_READ_MASK = MWU_INTEN_PREGION1RA_Msk, ///< Interrupt on PREGION[1].RA event.
} nrf_mwu_int_mask_t;
/** @brief MWU region watch masks. */
typedef enum
{
NRF_MWU_WATCH_REGION0_WRITE = MWU_REGIONEN_RGN0WA_Msk, ///< Region 0 write access watch mask.
NRF_MWU_WATCH_REGION0_READ = MWU_REGIONEN_RGN0RA_Msk, ///< Region 0 read access watch mask.
NRF_MWU_WATCH_REGION1_WRITE = MWU_REGIONEN_RGN1WA_Msk, ///< Region 1 write access watch mask.
NRF_MWU_WATCH_REGION1_READ = MWU_REGIONEN_RGN1RA_Msk, ///< Region 1 read access watch mask.
NRF_MWU_WATCH_REGION2_WRITE = MWU_REGIONEN_RGN2WA_Msk, ///< Region 2 write access watch mask.
NRF_MWU_WATCH_REGION2_READ = MWU_REGIONEN_RGN2RA_Msk, ///< Region 2 read access watch mask.
NRF_MWU_WATCH_REGION3_WRITE = MWU_REGIONEN_RGN3WA_Msk, ///< Region 3 write access watch mask.
NRF_MWU_WATCH_REGION3_READ = MWU_REGIONEN_RGN3RA_Msk, ///< Region 3 read access watch mask.
NRF_MWU_WATCH_PREGION0_WRITE = MWU_REGIONEN_PRGN0WA_Msk, ///< Peripheral region 0 write access watch mask.
NRF_MWU_WATCH_PREGION0_READ = MWU_REGIONEN_PRGN0RA_Msk, ///< Peripheral region 0 read access watch mask.
NRF_MWU_WATCH_PREGION1_WRITE = MWU_REGIONEN_PRGN1WA_Msk, ///< Peripheral region 1 write access watch mask.
NRF_MWU_WATCH_PREGION1_READ = MWU_REGIONEN_PRGN1RA_Msk, ///< Peripheral region 1 read access watch mask.
} nrf_mwu_region_watch_t;
/**
* @brief Function for retrieving the state of the MWU event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be checked.
*
* @retval true The event has been generated.
* @retval false The event has not been generated.
*/
__STATIC_INLINE bool nrf_mwu_event_check(NRF_MWU_Type const * p_reg,
nrf_mwu_event_t event);
/**
* @brief Function for clearing a specific MWU event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to clear.
*/
__STATIC_INLINE void nrf_mwu_event_clear(NRF_MWU_Type * p_reg,
nrf_mwu_event_t event);
/**
* @brief Function for getting the address of a specific MWU event register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Requested event.
*
* @return Address of the specified event register.
*/
__STATIC_INLINE uint32_t nrf_mwu_event_address_get(NRF_MWU_Type const * p_reg,
nrf_mwu_event_t event);
/**
* @brief Function for enabling specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] int_mask Interrupts to be enabled.
*/
__STATIC_INLINE void nrf_mwu_int_enable(NRF_MWU_Type * p_reg, uint32_t int_mask);
/**
* @brief Function for retrieving the state of a specific interrupt.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mwu_int Interrupt to be checked.
*
* @retval true The interrupt is enabled.
* @retval false The interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_mwu_int_enable_check(NRF_MWU_Type const * p_reg,
nrf_mwu_int_mask_t mwu_int);
/**
* @brief Function for disabling specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] int_mask Interrupts to be disabled.
*/
__STATIC_INLINE void nrf_mwu_int_disable(NRF_MWU_Type * p_reg, uint32_t int_mask);
/**
* @brief Function for enabling specified non-maskable interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] int_mask Interrupts to be enabled.
*/
__STATIC_INLINE void nrf_mwu_nmi_enable(NRF_MWU_Type * p_reg, uint32_t int_mask);
/**
* @brief Function for retrieving the state of a specific non-maskable interrupt.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mwu_int Interrupt to be checked.
*
* @retval true The interrupt is enabled.
* @retval false The interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_mwu_nmi_enable_check(NRF_MWU_Type const * p_reg,
nrf_mwu_int_mask_t mwu_int);
/**
* @brief Function for disabling specified non-maskable interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] int_mask Interrupts to be disabled.
*/
__STATIC_INLINE void nrf_mwu_nmi_disable(NRF_MWU_Type * p_reg, uint32_t int_mask);
/**
* @brief Function for setting address range of the specified user region.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] region_idx Region number to configure.
* @param[in] start_addr Memory address defining the beginning of the region.
* @param[in] end_addr Memory address defining the end of the region.
*/
__STATIC_INLINE void nrf_mwu_user_region_range_set(NRF_MWU_Type * p_reg,
uint8_t region_idx,
uint32_t start_addr,
uint32_t end_addr);
/**
* @brief Function for enabling memory access watch mechanism.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] reg_watch_mask Mask that defines regions and access types to watch.
* Compose this mask from @ref nrf_mwu_region_watch_t values.
*/
__STATIC_INLINE void nrf_mwu_region_watch_enable(NRF_MWU_Type * p_reg, uint32_t reg_watch_mask);
/**
* @brief Function for disabling memory access watch mechanism.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] reg_watch_mask Mask that defines regions and access types to stop watching.
* Compose this mask from @ref nrf_mwu_region_watch_t values.
*/
__STATIC_INLINE void nrf_mwu_region_watch_disable(NRF_MWU_Type * p_reg, uint32_t reg_watch_mask);
/**
* @brief Function for getting memory access watch configuration mask.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Mask that defines regions and access types being watched.
*/
__STATIC_INLINE uint32_t nrf_mwu_region_watch_get(NRF_MWU_Type const * p_reg);
/**
* @brief Function for configuring peripheral subregions for watching.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] per_reg_idx Peripheral region containing specified subregions.
* @param[in] subregion_mask Mask that defines subregions to include into the specified peripheral region.
*/
__STATIC_INLINE void nrf_mwu_subregions_configure(NRF_MWU_Type * p_reg,
uint8_t per_reg_idx,
uint32_t subregion_mask);
/**
* @brief Function for getting the mask of the write access flags of peripheral subregions
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] per_reg_idx Peripheral region containing subregions to be checked.
*
* @return Mask specifying subregions that were write accessed.
*/
__STATIC_INLINE uint32_t nrf_mwu_subregions_write_accesses_get(NRF_MWU_Type const * p_reg,
uint8_t per_reg_idx);
/**
* @brief Function for clearing write access flags of peripheral subregions.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] per_reg_idx Peripheral region containing subregion accesses to clear.
* @param[in] subregion_mask Mask that defines subregion write accesses to clear.
*/
__STATIC_INLINE void nrf_mwu_subregions_write_accesses_clear(NRF_MWU_Type * p_reg,
uint8_t per_reg_idx,
uint32_t subregion_mask);
/**
* @brief Function for getting the mask of the read access flags of peripheral subregions
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] per_reg_idx Peripheral region containing subregions to be checked.
*
* @return Mask specifying subregions that were read accessed.
*/
__STATIC_INLINE uint32_t nrf_mwu_subregions_read_accesses_get(NRF_MWU_Type const * p_reg,
uint8_t per_reg_idx);
/**
* @brief Function for clearing read access flags of peripheral subregions.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] per_reg_idx Peripheral region containing subregion accesses to clear.
* @param[in] subregion_mask Mask that defines subregion read accesses to clear.
*/
__STATIC_INLINE void nrf_mwu_subregions_read_accesses_clear(NRF_MWU_Type * p_reg,
uint8_t per_reg_idx,
uint32_t subregion_mask);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE bool nrf_mwu_event_check(NRF_MWU_Type const * p_reg,
nrf_mwu_event_t event)
{
return (bool)*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE void nrf_mwu_event_clear(NRF_MWU_Type * p_reg,
nrf_mwu_event_t event)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event));
(void)dummy;
#endif
}
__STATIC_INLINE uint32_t nrf_mwu_event_address_get(NRF_MWU_Type const * p_reg,
nrf_mwu_event_t event)
{
return (uint32_t)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE void nrf_mwu_int_enable(NRF_MWU_Type * p_reg, uint32_t int_mask)
{
p_reg->INTENSET = int_mask;
}
__STATIC_INLINE bool nrf_mwu_int_enable_check(NRF_MWU_Type const * p_reg,
nrf_mwu_int_mask_t mwu_int)
{
return (bool)(p_reg->INTENSET & mwu_int);
}
__STATIC_INLINE void nrf_mwu_int_disable(NRF_MWU_Type * p_reg, uint32_t int_mask)
{
p_reg->INTENCLR = int_mask;
}
__STATIC_INLINE void nrf_mwu_nmi_enable(NRF_MWU_Type * p_reg, uint32_t int_mask)
{
p_reg->NMIENSET = int_mask;
}
__STATIC_INLINE bool nrf_mwu_nmi_enable_check(NRF_MWU_Type const * p_reg,
nrf_mwu_int_mask_t mwu_int)
{
return (bool)(p_reg->NMIENSET & mwu_int);
}
__STATIC_INLINE void nrf_mwu_nmi_disable(NRF_MWU_Type * p_reg, uint32_t int_mask)
{
p_reg->NMIENCLR = int_mask;
}
__STATIC_INLINE void nrf_mwu_user_region_range_set(NRF_MWU_Type * p_reg,
uint8_t region_idx,
uint32_t start_addr,
uint32_t end_addr)
{
NRFX_ASSERT(region_idx < NRFX_ARRAY_SIZE(NRF_MWU->REGION));
NRFX_ASSERT(end_addr >= start_addr);
p_reg->REGION[region_idx].START = start_addr;
p_reg->REGION[region_idx].END = end_addr;
}
__STATIC_INLINE void nrf_mwu_region_watch_enable(NRF_MWU_Type * p_reg, uint32_t reg_watch_mask)
{
p_reg->REGIONENSET = reg_watch_mask;
}
__STATIC_INLINE void nrf_mwu_region_watch_disable(NRF_MWU_Type * p_reg, uint32_t reg_watch_mask)
{
p_reg->REGIONENCLR = reg_watch_mask;
}
__STATIC_INLINE uint32_t nrf_mwu_region_watch_get(NRF_MWU_Type const * p_reg)
{
return p_reg->REGIONENSET;
}
__STATIC_INLINE void nrf_mwu_subregions_configure(NRF_MWU_Type * p_reg,
uint8_t per_reg_idx,
uint32_t subregion_mask)
{
NRFX_ASSERT(per_reg_idx < NRFX_ARRAY_SIZE(NRF_MWU->PREGION));
p_reg->PREGION[per_reg_idx].SUBS = subregion_mask;
}
__STATIC_INLINE uint32_t nrf_mwu_subregions_write_accesses_get(NRF_MWU_Type const * p_reg,
uint8_t per_reg_idx)
{
NRFX_ASSERT(per_reg_idx < NRFX_ARRAY_SIZE(NRF_MWU->PREGION));
return p_reg->PERREGION[per_reg_idx].SUBSTATWA;
}
__STATIC_INLINE void nrf_mwu_subregions_write_accesses_clear(NRF_MWU_Type * p_reg,
uint8_t per_reg_idx,
uint32_t subregion_mask)
{
NRFX_ASSERT(per_reg_idx < NRFX_ARRAY_SIZE(NRF_MWU->PREGION));
p_reg->PERREGION[per_reg_idx].SUBSTATWA = subregion_mask;
}
__STATIC_INLINE uint32_t nrf_mwu_subregions_read_accesses_get(NRF_MWU_Type const * p_reg,
uint8_t per_reg_idx)
{
NRFX_ASSERT(per_reg_idx < NRFX_ARRAY_SIZE(NRF_MWU->PREGION));
return p_reg->PERREGION[per_reg_idx].SUBSTATRA;
}
__STATIC_INLINE void nrf_mwu_subregions_read_accesses_clear(NRF_MWU_Type * p_reg,
uint8_t per_reg_idx,
uint32_t subregion_mask)
{
NRFX_ASSERT(per_reg_idx < NRFX_ARRAY_SIZE(NRF_MWU->PREGION));
p_reg->PERREGION[per_reg_idx].SUBSTATRA = subregion_mask;
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_MWU_H__
+133
View File
@@ -0,0 +1,133 @@
/**
* Copyright (c) 2012 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
/**
*@file
*@brief NMVC driver implementation
*/
#include <nrfx.h>
#include "nrf_nvmc.h"
static inline void wait_for_flash_ready(void)
{
while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {;}
}
void nrf_nvmc_page_erase(uint32_t address)
{
// Enable erase.
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Een;
__ISB();
__DSB();
// Erase the page
NRF_NVMC->ERASEPAGE = address;
wait_for_flash_ready();
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
__ISB();
__DSB();
}
void nrf_nvmc_write_byte(uint32_t address, uint8_t value)
{
uint32_t byte_shift = address & (uint32_t)0x03;
uint32_t address32 = address & ~byte_shift; // Address to the word this byte is in.
uint32_t value32 = (*(uint32_t*)address32 & ~((uint32_t)0xFF << (byte_shift << (uint32_t)3)));
value32 = value32 + ((uint32_t)value << (byte_shift << 3));
// Enable write.
NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);
__ISB();
__DSB();
*(uint32_t*)address32 = value32;
wait_for_flash_ready();
NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
__ISB();
__DSB();
}
void nrf_nvmc_write_word(uint32_t address, uint32_t value)
{
// Enable write.
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen;
__ISB();
__DSB();
*(uint32_t*)address = value;
wait_for_flash_ready();
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
__ISB();
__DSB();
}
void nrf_nvmc_write_bytes(uint32_t address, const uint8_t * src, uint32_t num_bytes)
{
uint32_t i;
for (i = 0; i < num_bytes; i++)
{
nrf_nvmc_write_byte(address + i,src[i]);
}
}
void nrf_nvmc_write_words(uint32_t address, const uint32_t * src, uint32_t num_words)
{
uint32_t i;
// Enable write.
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen;
__ISB();
__DSB();
for (i = 0; i < num_words; i++)
{
((uint32_t*)address)[i] = src[i];
wait_for_flash_ready();
}
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
__ISB();
__DSB();
}
+460
View File
@@ -0,0 +1,460 @@
/**
* Copyright (c) 2012 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_NVMC_H__
#define NRF_NVMC_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_nvmc_hal_deprecated NVMC HAL (deprecated)
* @{
* @ingroup nrf_nvmc
* @brief Hardware access layer (HAL) for managing the Non-Volatile Memory Controller (NVMC) peripheral.
*
* This driver allows writing to the non-volatile memory (NVM) regions
* of the chip. To write to NVM, the controller must be powered
* on and the relevant page must be erased.
*/
/**
* @brief Erase a page in flash. This is required before writing to any address in the page.
*
* @param address Start address of the page.
*/
void nrf_nvmc_page_erase(uint32_t address);
/**
* @brief Write a single byte to flash.
*
* The function reads the word containing the byte, and then rewrites the entire word.
*
* @param address Address to write to.
* @param value Value to write.
*/
void nrf_nvmc_write_byte(uint32_t address , uint8_t value);
/**
* @brief Write a 32-bit word to flash.
*
* @param address Address to write to.
* @param value Value to write.
*/
void nrf_nvmc_write_word(uint32_t address, uint32_t value);
/**
* @brief Write consecutive bytes to flash.
*
* @param address Address to write to.
* @param src Pointer to data to copy from.
* @param num_bytes Number of bytes in src to write.
*/
void nrf_nvmc_write_bytes(uint32_t address, const uint8_t * src, uint32_t num_bytes);
/**
* @brief Write consecutive words to flash.
*
* @param address Address to write to.
* @param src Pointer to data to copy from.
* @param num_words Number of words in src to write.
*/
void nrf_nvmc_write_words(uint32_t address, const uint32_t * src, uint32_t num_words);
/** @} */
/**
* @defgroup nrf_nvmc_hal NVMC HAL
* @{
* @ingroup nrf_nvmc
* @brief Hardware access layer (HAL) for managing the Non-Volatile Memory Controller (NVMC) peripheral.
*/
#if defined(NVMC_ICACHECNF_CACHEEN_Msk) || defined(__NRFX_DOXYGEN__)
/** @brief Symbol indicating whether Instruction Cache (ICache) is present. */
#define NRF_NVMC_ICACHE_PRESENT
#endif
#if defined(NVMC_ERASEPAGEPARTIALCFG_DURATION_Msk) || defined(__NRFX_DOXYGEN__)
/** @brief Symbol indicating whether the option of page partial erase is present. */
#define NRF_NVMC_PARTIAL_ERASE_PRESENT
#endif
/** @brief NVMC modes. */
typedef enum
{
NRF_NVMC_MODE_READONLY = NVMC_CONFIG_WEN_Ren, ///< NVMC in read-only mode.
NRF_NVMC_MODE_WRITE = NVMC_CONFIG_WEN_Wen, ///< NVMC in read and write mode.
NRF_NVMC_MODE_ERASE = NVMC_CONFIG_WEN_Een, ///< NVMC in read and erase mode.
#if defined(NVMC_CONFIG_WEN_PEen)
NRF_NVMC_MODE_PARTIAL_ERASE = NVMC_CONFIG_WEN_PEen ///< NVMC in read and partial erase mode.
#endif
} nrf_nvmc_mode_t;
#if defined(NVMC_CONFIGNS_WEN_Msk) || defined(__NRFX_DOXYGEN__)
/** @brief Non-secure NVMC modes. */
typedef enum
{
NRF_NVMC_NS_MODE_READONLY = NVMC_CONFIGNS_WEN_Ren, ///< Non-secure NVMC in read-only mode.
NRF_NVMC_NS_MODE_WRITE = NVMC_CONFIGNS_WEN_Wen, ///< Non-secure NVMC in read and write mode.
NRF_NVMC_NS_MODE_ERASE = NVMC_CONFIGNS_WEN_Een, ///< Non-secure NVMC in read and erase mode.
} nrf_nvmc_ns_mode_t;
#endif
#if defined(NRF_NVMC_ICACHE_PRESENT)
/** @brief NVMC ICache configuration. */
typedef enum
{
NRF_NVMC_ICACHE_DISABLE = NVMC_ICACHECNF_CACHEEN_Disabled, ///< Instruction Cache disabled.
NRF_NVMC_ICACHE_ENABLE = NVMC_ICACHECNF_CACHEEN_Enabled, ///< Instruction Cache enabled.
NRF_NVMC_ICACHE_ENABLE_WITH_PROFILING = NVMC_ICACHECNF_CACHEEN_Enabled | ///< Instruction Cache with cache profiling enabled.
NVMC_ICACHECNF_CACHEPROFEN_Msk
} nrf_nvmc_icache_config_t;
#endif // defined(NRF_NVMC_ICACHE_PRESENT)
/**
* @brief Function for checking if NVMC is ready to perform write or erase operation.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @retval true NVMC can perform write or erase.
* @retval false NVMC is busy and cannot perform next operation yet.
*/
__STATIC_INLINE bool nrf_nvmc_ready_check(NRF_NVMC_Type const * p_reg);
#if defined(NVMC_READYNEXT_READYNEXT_Msk) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for checking if NVMC is ready to accept the next write operation.
*
* NVM writing time can be reduced by using this function.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @retval true NVMC can accept the next write. It will be buffered and will be taken
* into account as soon as the ongoing write operation is completed.
* @retval false NVMC is busy and cannot accept the next write yet.
*/
__STATIC_INLINE bool nrf_nvmc_write_ready_check(NRF_NVMC_Type const * p_reg);
#endif // defined(NVMC_READYNEXT_READYNEXT_Msk) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting the NVMC mode.
*
* Only activate erase and write modes when they are actively used.
* If Instruction Cache (ICache) is present, enabling write or erase will
* invalidate the cache and keep it invalidated.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mode Desired operating mode for NVMC.
*/
__STATIC_INLINE void nrf_nvmc_mode_set(NRF_NVMC_Type * p_reg,
nrf_nvmc_mode_t mode);
#if defined(NVMC_CONFIGNS_WEN_Msk) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting the NVMC mode for non-secure Flash page operations.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mode Desired operating mode for NVMC.
*/
__STATIC_INLINE void nrf_nvmc_nonsecure_mode_set(NRF_NVMC_Type * p_reg,
nrf_nvmc_ns_mode_t mode);
#endif
/**
* @brief Function for starting a single page erase in the Flash memory.
*
* The NVMC mode must be correctly configured with @ref nrf_nvmc_mode_set
* before starting the erase operation.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] page_addr Address of the first word of the page to erase.
*/
__STATIC_INLINE void nrf_nvmc_page_erase_start(NRF_NVMC_Type * p_reg,
uint32_t page_addr);
#if defined(NVMC_ERASEUICR_ERASEUICR_Msk) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for starting the user information configuration registers (UICR) erase.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_nvmc_uicr_erase_start(NRF_NVMC_Type * p_reg);
#endif
/**
* @brief Function for starting the erase of the whole NVM, including UICR.
*
* This function purges all user code.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_nvmc_erase_all_start(NRF_NVMC_Type * p_reg);
#if defined(NRF_NVMC_PARTIAL_ERASE_PRESENT)
/**
* @brief Function for configuring the page partial erase duration in milliseconds.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] duration_ms Page partial erase duration in milliseconds.
*/
__STATIC_INLINE void nrf_nvmc_partial_erase_duration_set(NRF_NVMC_Type * p_reg,
uint32_t duration_ms);
/**
* @brief Function for getting the current setting for the page partial erase duration.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @retval Interval duration setting in milliseconds.
*/
__STATIC_INLINE uint32_t nrf_nvmc_partial_erase_duration_get(NRF_NVMC_Type const * p_reg);
/**
* @brief Function for starting a partial erase operation.
*
* It must be called successively until the page erase time is reached.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] page_addr Address of the first word of the page to erase.
*/
__STATIC_INLINE void nrf_nvmc_page_partial_erase_start(NRF_NVMC_Type * p_reg,
uint32_t page_addr);
#endif // defined(NRF_NVMC_PARTIAL_ERASE_PRESENT)
#if defined(NRF_NVMC_ICACHE_PRESENT)
/**
* @brief Function for applying the Instruction Cache (ICache) configuration.
*
* Enabling the cache can increase CPU performance and reduce power
* consumption by reducing the number of wait cycles and the number
* of flash accesses.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] config ICache configuration.
*/
__STATIC_INLINE void nrf_nvmc_icache_config_set(NRF_NVMC_Type * p_reg,
nrf_nvmc_icache_config_t config);
/**
* @brief Function for checking if ICache is enabled.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @retval true ICache enabled.
* @retval false ICache disabled.
*/
__STATIC_INLINE bool nrf_nvmc_icache_enable_check(NRF_NVMC_Type const * p_reg);
/**
* @brief Function for checking if the ICache profiling option is enabled.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @retval true ICache profiling enabled.
* @retval false ICache profiling disabled.
*/
__STATIC_INLINE bool nrf_nvmc_icache_profiling_enable_check(NRF_NVMC_Type const * p_reg);
/**
* @brief Function for getting the number of ICache hits.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @retval Number of the ICache hits.
*/
__STATIC_INLINE uint32_t nrf_nvmc_icache_hit_get(NRF_NVMC_Type const * p_reg);
/**
* @brief Function for getting the number of ICache misses.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @retval Number of the ICache misses.
*/
__STATIC_INLINE uint32_t nrf_nvmc_icache_miss_get(NRF_NVMC_Type const * p_reg);
/**
* @brief Function for resetting the ICache hit and miss counters.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_nvmc_icache_hit_miss_reset(NRF_NVMC_Type * p_reg);
#endif // defined(NRF_NVMC_ICACHE_PRESENT)
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE bool nrf_nvmc_ready_check(NRF_NVMC_Type const * p_reg)
{
return (bool)(p_reg->READY & NVMC_READY_READY_Msk);
}
#if defined(NVMC_READYNEXT_READYNEXT_Msk)
__STATIC_INLINE bool nrf_nvmc_write_ready_check(NRF_NVMC_Type const * p_reg)
{
return (bool)(p_reg->READYNEXT & NVMC_READYNEXT_READYNEXT_Msk);
}
#endif
__STATIC_INLINE void nrf_nvmc_mode_set(NRF_NVMC_Type * p_reg,
nrf_nvmc_mode_t mode)
{
p_reg->CONFIG = (uint32_t)mode;
}
#if defined(NVMC_CONFIGNS_WEN_Msk)
__STATIC_INLINE void nrf_nvmc_nonsecure_mode_set(NRF_NVMC_Type * p_reg,
nrf_nvmc_ns_mode_t mode)
{
p_reg->CONFIGNS = (uint32_t)mode;
}
#endif
__STATIC_INLINE void nrf_nvmc_page_erase_start(NRF_NVMC_Type * p_reg,
uint32_t page_addr)
{
#if defined(NRF51)
/* On nRF51, the code area can be divided into two regions: CR0 and CR1.
* The length of CR0 is specified in the CLENR0 register of UICR.
* If CLENR0 contains the 0xFFFFFFFF value, CR0 is not set.
* Moreover, the page from CR0 can be written or erased only from code
* running in CR0.*/
uint32_t cr0_len = NRF_UICR->CLENR0 == 0xFFFFFFFF ? 0 : NRF_UICR->CLENR0;
if (page_addr < cr0_len)
{
p_reg->ERASEPCR0 = page_addr;
}
else
{
p_reg->ERASEPCR1 = page_addr;
}
#elif defined(NRF52_SERIES)
p_reg->ERASEPAGE = page_addr;
#elif defined(NRF9160_XXAA)
*(volatile uint32_t *)page_addr = 0xFFFFFFFF;
(void)p_reg;
#else
#error "Unknown device."
#endif
}
#if defined(NVMC_ERASEUICR_ERASEUICR_Msk)
__STATIC_INLINE void nrf_nvmc_uicr_erase_start(NRF_NVMC_Type * p_reg)
{
p_reg->ERASEUICR = 1;
}
#endif
__STATIC_INLINE void nrf_nvmc_erase_all_start(NRF_NVMC_Type * p_reg)
{
p_reg->ERASEALL = 1;
}
#if defined(NRF_NVMC_PARTIAL_ERASE_PRESENT)
__STATIC_INLINE void nrf_nvmc_partial_erase_duration_set(NRF_NVMC_Type * p_reg,
uint32_t duration_ms)
{
p_reg->ERASEPAGEPARTIALCFG = duration_ms;
}
__STATIC_INLINE uint32_t nrf_nvmc_partial_erase_duration_get(NRF_NVMC_Type const * p_reg)
{
return p_reg->ERASEPAGEPARTIALCFG;
}
__STATIC_INLINE void nrf_nvmc_page_partial_erase_start(NRF_NVMC_Type * p_reg,
uint32_t page_addr)
{
#if defined(NVMC_ERASEPAGEPARTIAL_ERASEPAGEPARTIAL_Msk)
p_reg->ERASEPAGEPARTIAL = page_addr;
#elif defined(NRF9160_XXAA)
nrf_nvmc_page_erase_start(p_reg, page_addr);
#else
#error "Unknown device."
#endif
}
#endif // defined(NRF_NVMC_PARTIAL_ERASE_PRESENT)
#if defined(NRF_NVMC_ICACHE_PRESENT)
__STATIC_INLINE void nrf_nvmc_icache_config_set(NRF_NVMC_Type * p_reg,
nrf_nvmc_icache_config_t config)
{
p_reg->ICACHECNF = (uint32_t)config;
}
__STATIC_INLINE bool nrf_nvmc_icache_enable_check(NRF_NVMC_Type const * p_reg)
{
return (bool)(p_reg->ICACHECNF & NVMC_ICACHECNF_CACHEEN_Msk);
}
__STATIC_INLINE bool nrf_nvmc_icache_profiling_enable_check(NRF_NVMC_Type const * p_reg)
{
return (bool)(p_reg->ICACHECNF & NVMC_ICACHECNF_CACHEPROFEN_Msk);
}
__STATIC_INLINE uint32_t nrf_nvmc_icache_hit_get(NRF_NVMC_Type const * p_reg)
{
return p_reg->IHIT;
}
__STATIC_INLINE uint32_t nrf_nvmc_icache_miss_get(NRF_NVMC_Type const * p_reg)
{
return p_reg->IMISS;
}
__STATIC_INLINE void nrf_nvmc_icache_hit_miss_reset(NRF_NVMC_Type * p_reg)
{
p_reg->IHIT = 0;
p_reg->IMISS = 0;
}
#endif // defined(NRF_NVMC_ICACHE_PRESENT)
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_NVMC_H__
File diff suppressed because it is too large Load Diff
+524
View File
@@ -0,0 +1,524 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_PPI_H__
#define NRF_PPI_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_ppi_hal PPI HAL
* @{
* @ingroup nrf_ppi
* @brief Hardware access layer (HAL) for managing the Programmable Peripheral Interconnect (PPI)
* channels.
*/
/** @brief PPI channels. */
typedef enum
{
NRF_PPI_CHANNEL0 = PPI_CHEN_CH0_Pos, /**< Channel 0. */
NRF_PPI_CHANNEL1 = PPI_CHEN_CH1_Pos, /**< Channel 1. */
NRF_PPI_CHANNEL2 = PPI_CHEN_CH2_Pos, /**< Channel 2. */
NRF_PPI_CHANNEL3 = PPI_CHEN_CH3_Pos, /**< Channel 3. */
NRF_PPI_CHANNEL4 = PPI_CHEN_CH4_Pos, /**< Channel 4. */
NRF_PPI_CHANNEL5 = PPI_CHEN_CH5_Pos, /**< Channel 5. */
NRF_PPI_CHANNEL6 = PPI_CHEN_CH6_Pos, /**< Channel 6. */
NRF_PPI_CHANNEL7 = PPI_CHEN_CH7_Pos, /**< Channel 7. */
NRF_PPI_CHANNEL8 = PPI_CHEN_CH8_Pos, /**< Channel 8. */
NRF_PPI_CHANNEL9 = PPI_CHEN_CH9_Pos, /**< Channel 9. */
NRF_PPI_CHANNEL10 = PPI_CHEN_CH10_Pos, /**< Channel 10. */
NRF_PPI_CHANNEL11 = PPI_CHEN_CH11_Pos, /**< Channel 11. */
NRF_PPI_CHANNEL12 = PPI_CHEN_CH12_Pos, /**< Channel 12. */
NRF_PPI_CHANNEL13 = PPI_CHEN_CH13_Pos, /**< Channel 13. */
NRF_PPI_CHANNEL14 = PPI_CHEN_CH14_Pos, /**< Channel 14. */
NRF_PPI_CHANNEL15 = PPI_CHEN_CH15_Pos, /**< Channel 15. */
#if (PPI_CH_NUM > 16) || defined(__NRFX_DOXYGEN__)
NRF_PPI_CHANNEL16 = PPI_CHEN_CH16_Pos, /**< Channel 16. */
NRF_PPI_CHANNEL17 = PPI_CHEN_CH17_Pos, /**< Channel 17. */
NRF_PPI_CHANNEL18 = PPI_CHEN_CH18_Pos, /**< Channel 18. */
NRF_PPI_CHANNEL19 = PPI_CHEN_CH19_Pos, /**< Channel 19. */
#endif
NRF_PPI_CHANNEL20 = PPI_CHEN_CH20_Pos, /**< Channel 20. */
NRF_PPI_CHANNEL21 = PPI_CHEN_CH21_Pos, /**< Channel 21. */
NRF_PPI_CHANNEL22 = PPI_CHEN_CH22_Pos, /**< Channel 22. */
NRF_PPI_CHANNEL23 = PPI_CHEN_CH23_Pos, /**< Channel 23. */
NRF_PPI_CHANNEL24 = PPI_CHEN_CH24_Pos, /**< Channel 24. */
NRF_PPI_CHANNEL25 = PPI_CHEN_CH25_Pos, /**< Channel 25. */
NRF_PPI_CHANNEL26 = PPI_CHEN_CH26_Pos, /**< Channel 26. */
NRF_PPI_CHANNEL27 = PPI_CHEN_CH27_Pos, /**< Channel 27. */
NRF_PPI_CHANNEL28 = PPI_CHEN_CH28_Pos, /**< Channel 28. */
NRF_PPI_CHANNEL29 = PPI_CHEN_CH29_Pos, /**< Channel 29. */
NRF_PPI_CHANNEL30 = PPI_CHEN_CH30_Pos, /**< Channel 30. */
NRF_PPI_CHANNEL31 = PPI_CHEN_CH31_Pos /**< Channel 31. */
} nrf_ppi_channel_t;
/** @brief PPI channel groups. */
typedef enum
{
NRF_PPI_CHANNEL_GROUP0 = 0, /**< Channel group 0. */
NRF_PPI_CHANNEL_GROUP1 = 1, /**< Channel group 1. */
NRF_PPI_CHANNEL_GROUP2 = 2, /**< Channel group 2. */
NRF_PPI_CHANNEL_GROUP3 = 3, /**< Channel group 3. */
#if (PPI_GROUP_NUM > 4) || defined(__NRFX_DOXYGEN__)
NRF_PPI_CHANNEL_GROUP4 = 4, /**< Channel group 4. */
NRF_PPI_CHANNEL_GROUP5 = 5 /**< Channel group 5. */
#endif
} nrf_ppi_channel_group_t;
/** @brief Definition of whether a PPI channel belongs to a group. */
typedef enum
{
NRF_PPI_CHANNEL_EXCLUDE = PPI_CHG_CH0_Excluded, /**< Channel excluded from a group. */
NRF_PPI_CHANNEL_INCLUDE = PPI_CHG_CH0_Included /**< Channel included in a group. */
} nrf_ppi_channel_include_t;
/** @brief Definition of whether a PPI channel is enabled. */
typedef enum
{
NRF_PPI_CHANNEL_DISABLED = PPI_CHEN_CH0_Disabled, /**< Channel disabled. */
NRF_PPI_CHANNEL_ENABLED = PPI_CHEN_CH0_Enabled /**< Channel enabled. */
} nrf_ppi_channel_enable_t;
/** @brief PPI tasks. */
typedef enum
{
NRF_PPI_TASK_CHG0_EN = offsetof(NRF_PPI_Type, TASKS_CHG[0].EN), /**< Task for enabling channel group 0. */
NRF_PPI_TASK_CHG0_DIS = offsetof(NRF_PPI_Type, TASKS_CHG[0].DIS), /**< Task for disabling channel group 0. */
NRF_PPI_TASK_CHG1_EN = offsetof(NRF_PPI_Type, TASKS_CHG[1].EN), /**< Task for enabling channel group 1. */
NRF_PPI_TASK_CHG1_DIS = offsetof(NRF_PPI_Type, TASKS_CHG[1].DIS), /**< Task for disabling channel group 1. */
NRF_PPI_TASK_CHG2_EN = offsetof(NRF_PPI_Type, TASKS_CHG[2].EN), /**< Task for enabling channel group 2. */
NRF_PPI_TASK_CHG2_DIS = offsetof(NRF_PPI_Type, TASKS_CHG[2].DIS), /**< Task for disabling channel group 2. */
NRF_PPI_TASK_CHG3_EN = offsetof(NRF_PPI_Type, TASKS_CHG[3].EN), /**< Task for enabling channel group 3. */
NRF_PPI_TASK_CHG3_DIS = offsetof(NRF_PPI_Type, TASKS_CHG[3].DIS), /**< Task for disabling channel group 3. */
#if (PPI_GROUP_NUM > 4) || defined(__NRFX_DOXYGEN__)
NRF_PPI_TASK_CHG4_EN = offsetof(NRF_PPI_Type, TASKS_CHG[4].EN), /**< Task for enabling channel group 4. */
NRF_PPI_TASK_CHG4_DIS = offsetof(NRF_PPI_Type, TASKS_CHG[4].DIS), /**< Task for disabling channel group 4. */
NRF_PPI_TASK_CHG5_EN = offsetof(NRF_PPI_Type, TASKS_CHG[5].EN), /**< Task for enabling channel group 5. */
NRF_PPI_TASK_CHG5_DIS = offsetof(NRF_PPI_Type, TASKS_CHG[5].DIS) /**< Task for disabling channel group 5. */
#endif
} nrf_ppi_task_t;
/**
* @brief Function for enabling a given PPI channel.
*
* @details This function enables only one channel.
*
* @param[in] channel Channel to be enabled.
*/
__STATIC_INLINE void nrf_ppi_channel_enable(nrf_ppi_channel_t channel);
/**
* @brief Function for disabling a given PPI channel.
*
* @details This function disables only one channel.
*
* @param[in] channel Channel to be disabled.
*/
__STATIC_INLINE void nrf_ppi_channel_disable(nrf_ppi_channel_t channel);
/**
* @brief Function for checking if a given PPI channel is enabled.
*
* @details This function checks only one channel.
*
* @param[in] channel Channel to be checked.
*
* @retval NRF_PPI_CHANNEL_ENABLED The channel is enabled.
* @retval NRF_PPI_CHANNEL_DISABLED The channel is not enabled.
*
*/
__STATIC_INLINE nrf_ppi_channel_enable_t nrf_ppi_channel_enable_get(nrf_ppi_channel_t channel);
/** @brief Function for disabling all PPI channels. */
__STATIC_INLINE void nrf_ppi_channel_disable_all(void);
/**
* @brief Function for enabling multiple PPI channels.
*
* @param[in] mask Channel mask.
*/
__STATIC_INLINE void nrf_ppi_channels_enable(uint32_t mask);
/**
* @brief Function for disabling multiple PPI channels.
*
* @param[in] mask Channel mask.
*/
__STATIC_INLINE void nrf_ppi_channels_disable(uint32_t mask);
/**
* @brief Function for setting up event and task endpoints for a given PPI channel.
*
* @param[in] eep Event register address.
* @param[in] tep Task register address.
* @param[in] channel Channel to which the given endpoints are assigned.
*/
__STATIC_INLINE void nrf_ppi_channel_endpoint_setup(nrf_ppi_channel_t channel,
uint32_t eep,
uint32_t tep);
/**
* @brief Function for setting up the event endpoint for a given PPI channel.
*
* @param[in] eep Event register address.
* @param[in] channel Channel to which the given endpoint is assigned.
*/
__STATIC_INLINE void nrf_ppi_event_endpoint_setup(nrf_ppi_channel_t channel,
uint32_t eep);
/**
* @brief Function for setting up the task endpoint for a given PPI channel.
*
* @param[in] tep Task register address.
* @param[in] channel Channel to which the given endpoint is assigned.
*/
__STATIC_INLINE void nrf_ppi_task_endpoint_setup(nrf_ppi_channel_t channel,
uint32_t tep);
#if defined(PPI_FEATURE_FORKS_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting up task endpoint for a given PPI fork.
*
* @param[in] fork_tep Task register address.
* @param[in] channel Channel to which the given fork endpoint is assigned.
*/
__STATIC_INLINE void nrf_ppi_fork_endpoint_setup(nrf_ppi_channel_t channel,
uint32_t fork_tep);
/**
* @brief Function for setting up event and task endpoints for a given PPI channel and fork.
*
* @param[in] eep Event register address.
* @param[in] tep Task register address.
* @param[in] fork_tep Fork task register address (register value).
* @param[in] channel Channel to which the given endpoints are assigned.
*/
__STATIC_INLINE void nrf_ppi_channel_and_fork_endpoint_setup(nrf_ppi_channel_t channel,
uint32_t eep,
uint32_t tep,
uint32_t fork_tep);
#endif
/**
* @brief Function for including a PPI channel in a channel group.
*
* @details This function adds only one channel to the group.
*
* @param[in] channel Channel to be included in the group.
* @param[in] channel_group Channel group.
*/
__STATIC_INLINE void nrf_ppi_channel_include_in_group(nrf_ppi_channel_t channel,
nrf_ppi_channel_group_t channel_group);
/**
* @brief Function for including multiple PPI channels in a channel group.
*
* @details This function adds all specified channels to the group.
*
* @param[in] channel_mask Channels to be included in the group.
* @param[in] channel_group Channel group.
*/
__STATIC_INLINE void nrf_ppi_channels_include_in_group(uint32_t channel_mask,
nrf_ppi_channel_group_t channel_group);
/**
* @brief Function for removing a PPI channel from a channel group.
*
* @details This function removes only one channel from the group.
*
* @param[in] channel Channel to be removed from the group.
* @param[in] channel_group Channel group.
*/
__STATIC_INLINE void nrf_ppi_channel_remove_from_group(nrf_ppi_channel_t channel,
nrf_ppi_channel_group_t channel_group);
/**
* @brief Function for removing multiple PPI channels from a channel group.
*
* @details This function removes all specified channels from the group.
*
* @param[in] channel_mask Channels to be removed from the group.
* @param[in] channel_group Channel group.
*/
__STATIC_INLINE void nrf_ppi_channels_remove_from_group(uint32_t channel_mask,
nrf_ppi_channel_group_t channel_group);
/**
* @brief Function for removing all PPI channels from a channel group.
*
* @param[in] group Channel group.
*/
__STATIC_INLINE void nrf_ppi_channel_group_clear(nrf_ppi_channel_group_t group);
/**
* @brief Function for enabling a channel group.
*
* @param[in] group Channel group.
*/
__STATIC_INLINE void nrf_ppi_group_enable(nrf_ppi_channel_group_t group);
/**
* @brief Function for disabling a channel group.
*
* @param[in] group Channel group.
*/
__STATIC_INLINE void nrf_ppi_group_disable(nrf_ppi_channel_group_t group);
/**
* @brief Function for setting a PPI task.
*
* @param[in] ppi_task PPI task to be set.
*/
__STATIC_INLINE void nrf_ppi_task_trigger(nrf_ppi_task_t ppi_task);
/**
* @brief Function for getting the address of the specified PPI task register.
*
* @param[in] ppi_task PPI task.
*
* @return Address of the requested PPI task register.
*/
__STATIC_INLINE uint32_t * nrf_ppi_task_address_get(nrf_ppi_task_t ppi_task);
/**
* @brief Function for getting the PPI enable task address of the specified group.
*
* @param[in] group PPI group.
*
* @return PPI enable task address of the specified group.
*/
__STATIC_INLINE uint32_t * nrf_ppi_task_group_enable_address_get(nrf_ppi_channel_group_t group);
/**
* @brief Function for getting the PPI disable task address of the specified group.
*
* @param[in] group PPI group.
*
* @return PPI disable task address of the specified group.
*/
__STATIC_INLINE uint32_t * nrf_ppi_task_group_disable_address_get(nrf_ppi_channel_group_t group);
/**
* @brief Function for getting the ENABLE task associated with the specified channel group.
*
* @param[in] index Channel group index.
*
* @return Requested ENABLE task.
*/
__STATIC_INLINE nrf_ppi_task_t nrf_ppi_group_enable_task_get(uint8_t index);
/**
* @brief Function for getting the DISABLE task associated with the specified channel group.
*
* @param[in] index Channel group index.
*
* @return Requested DISABLE task.
*/
__STATIC_INLINE nrf_ppi_task_t nrf_ppi_group_disable_task_get(uint8_t index);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_ppi_channel_enable(nrf_ppi_channel_t channel)
{
NRF_PPI->CHENSET = PPI_CHENSET_CH0_Set << ((uint32_t) channel);
}
__STATIC_INLINE void nrf_ppi_channel_disable(nrf_ppi_channel_t channel)
{
NRF_PPI->CHENCLR = PPI_CHENCLR_CH0_Clear << ((uint32_t) channel);
}
__STATIC_INLINE nrf_ppi_channel_enable_t nrf_ppi_channel_enable_get(nrf_ppi_channel_t channel)
{
if (NRF_PPI->CHEN & (PPI_CHEN_CH0_Msk << ((uint32_t) channel)))
{
return NRF_PPI_CHANNEL_ENABLED;
}
else
{
return NRF_PPI_CHANNEL_DISABLED;
}
}
__STATIC_INLINE void nrf_ppi_channel_disable_all(void)
{
NRF_PPI->CHENCLR = ((uint32_t)0xFFFFFFFFuL);
}
__STATIC_INLINE void nrf_ppi_channels_enable(uint32_t mask)
{
NRF_PPI->CHENSET = mask;
}
__STATIC_INLINE void nrf_ppi_channels_disable(uint32_t mask)
{
NRF_PPI->CHENCLR = mask;
}
__STATIC_INLINE void nrf_ppi_channel_endpoint_setup(nrf_ppi_channel_t channel,
uint32_t eep,
uint32_t tep)
{
NRF_PPI->CH[(uint32_t) channel].EEP = eep;
NRF_PPI->CH[(uint32_t) channel].TEP = tep;
}
__STATIC_INLINE void nrf_ppi_event_endpoint_setup(nrf_ppi_channel_t channel,
uint32_t eep)
{
NRF_PPI->CH[(uint32_t) channel].EEP = eep;
}
__STATIC_INLINE void nrf_ppi_task_endpoint_setup(nrf_ppi_channel_t channel,
uint32_t tep)
{
NRF_PPI->CH[(uint32_t) channel].TEP = tep;
}
#if defined(PPI_FEATURE_FORKS_PRESENT)
__STATIC_INLINE void nrf_ppi_fork_endpoint_setup(nrf_ppi_channel_t channel,
uint32_t fork_tep)
{
NRF_PPI->FORK[(uint32_t) channel].TEP = fork_tep;
}
__STATIC_INLINE void nrf_ppi_channel_and_fork_endpoint_setup(nrf_ppi_channel_t channel,
uint32_t eep,
uint32_t tep,
uint32_t fork_tep)
{
nrf_ppi_channel_endpoint_setup(channel, eep, tep);
nrf_ppi_fork_endpoint_setup(channel, fork_tep);
}
#endif
__STATIC_INLINE void nrf_ppi_channel_include_in_group(nrf_ppi_channel_t channel,
nrf_ppi_channel_group_t channel_group)
{
NRF_PPI->CHG[(uint32_t) channel_group] =
NRF_PPI->CHG[(uint32_t) channel_group] | (PPI_CHG_CH0_Included << ((uint32_t) channel));
}
__STATIC_INLINE void nrf_ppi_channels_include_in_group(uint32_t channel_mask,
nrf_ppi_channel_group_t channel_group)
{
NRF_PPI->CHG[(uint32_t) channel_group] =
NRF_PPI->CHG[(uint32_t) channel_group] | (channel_mask);
}
__STATIC_INLINE void nrf_ppi_channel_remove_from_group(nrf_ppi_channel_t channel,
nrf_ppi_channel_group_t channel_group)
{
NRF_PPI->CHG[(uint32_t) channel_group] =
NRF_PPI->CHG[(uint32_t) channel_group] & ~(PPI_CHG_CH0_Included << ((uint32_t) channel));
}
__STATIC_INLINE void nrf_ppi_channels_remove_from_group(uint32_t channel_mask,
nrf_ppi_channel_group_t channel_group)
{
NRF_PPI->CHG[(uint32_t) channel_group] =
NRF_PPI->CHG[(uint32_t) channel_group] & ~(channel_mask);
}
__STATIC_INLINE void nrf_ppi_channel_group_clear(nrf_ppi_channel_group_t group)
{
NRF_PPI->CHG[(uint32_t) group] = 0;
}
__STATIC_INLINE void nrf_ppi_group_enable(nrf_ppi_channel_group_t group)
{
NRF_PPI->TASKS_CHG[(uint32_t) group].EN = 1UL;
}
__STATIC_INLINE void nrf_ppi_group_disable(nrf_ppi_channel_group_t group)
{
NRF_PPI->TASKS_CHG[(uint32_t) group].DIS = 1UL;
}
__STATIC_INLINE void nrf_ppi_task_trigger(nrf_ppi_task_t ppi_task)
{
*((volatile uint32_t *) ((uint8_t *) NRF_PPI_BASE + (uint32_t) ppi_task)) = 1UL;
}
__STATIC_INLINE uint32_t * nrf_ppi_task_address_get(nrf_ppi_task_t ppi_task)
{
return (uint32_t *) ((uint8_t *) NRF_PPI_BASE + (uint32_t) ppi_task);
}
__STATIC_INLINE uint32_t * nrf_ppi_task_group_enable_address_get(nrf_ppi_channel_group_t group)
{
return (uint32_t *) &NRF_PPI->TASKS_CHG[(uint32_t) group].EN;
}
__STATIC_INLINE uint32_t * nrf_ppi_task_group_disable_address_get(nrf_ppi_channel_group_t group)
{
return (uint32_t *) &NRF_PPI->TASKS_CHG[(uint32_t) group].DIS;
}
__STATIC_INLINE nrf_ppi_task_t nrf_ppi_group_enable_task_get(uint8_t index)
{
NRFX_ASSERT(index < NRFX_ARRAY_SIZE(NRF_PPI->TASKS_CHG));
return (nrf_ppi_task_t)NRFX_OFFSETOF(NRF_PPI_Type, TASKS_CHG[index].EN);
}
__STATIC_INLINE nrf_ppi_task_t nrf_ppi_group_disable_task_get(uint8_t index)
{
NRFX_ASSERT(index < NRFX_ARRAY_SIZE(NRF_PPI->TASKS_CHG));
return (nrf_ppi_task_t)NRFX_OFFSETOF(NRF_PPI_Type, TASKS_CHG[index].DIS);
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_PPI_H__
+751
View File
@@ -0,0 +1,751 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_PWM_H__
#define NRF_PWM_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_pwm_hal PWM HAL
* @{
* @ingroup nrf_pwm
* @brief Hardware access layer for managing the Pulse Width Modulation (PWM) peripheral.
*/
/**
* @brief This value can be provided as a parameter for the @ref nrf_pwm_pins_set
* function call to specify that a given output channel shall not be
* connected to a physical pin.
*/
#define NRF_PWM_PIN_NOT_CONNECTED 0xFFFFFFFF
/** @brief Number of channels in each PWM instance. */
#define NRF_PWM_CHANNEL_COUNT 4
/**
* @brief Helper macro for calculating the number of 16-bit values in the specified
* array of duty cycle values.
*/
#define NRF_PWM_VALUES_LENGTH(array) (sizeof(array) / sizeof(uint16_t))
/** @brief PWM tasks. */
typedef enum
{
NRF_PWM_TASK_STOP = offsetof(NRF_PWM_Type, TASKS_STOP), ///< Stops PWM pulse generation on all channels at the end of the current PWM period, and stops the sequence playback.
NRF_PWM_TASK_SEQSTART0 = offsetof(NRF_PWM_Type, TASKS_SEQSTART[0]), ///< Starts playback of sequence 0.
NRF_PWM_TASK_SEQSTART1 = offsetof(NRF_PWM_Type, TASKS_SEQSTART[1]), ///< Starts playback of sequence 1.
NRF_PWM_TASK_NEXTSTEP = offsetof(NRF_PWM_Type, TASKS_NEXTSTEP) ///< Steps by one value in the current sequence if the decoder is set to @ref NRF_PWM_STEP_TRIGGERED mode.
} nrf_pwm_task_t;
/** @brief PWM events. */
typedef enum
{
NRF_PWM_EVENT_STOPPED = offsetof(NRF_PWM_Type, EVENTS_STOPPED), ///< Response to STOP task, emitted when PWM pulses are no longer generated.
NRF_PWM_EVENT_SEQSTARTED0 = offsetof(NRF_PWM_Type, EVENTS_SEQSTARTED[0]), ///< First PWM period started on sequence 0.
NRF_PWM_EVENT_SEQSTARTED1 = offsetof(NRF_PWM_Type, EVENTS_SEQSTARTED[1]), ///< First PWM period started on sequence 1.
NRF_PWM_EVENT_SEQEND0 = offsetof(NRF_PWM_Type, EVENTS_SEQEND[0]), ///< Emitted at the end of every sequence 0 when its last value has been read from RAM.
NRF_PWM_EVENT_SEQEND1 = offsetof(NRF_PWM_Type, EVENTS_SEQEND[1]), ///< Emitted at the end of every sequence 1 when its last value has been read from RAM.
NRF_PWM_EVENT_PWMPERIODEND = offsetof(NRF_PWM_Type, EVENTS_PWMPERIODEND), ///< Emitted at the end of each PWM period.
NRF_PWM_EVENT_LOOPSDONE = offsetof(NRF_PWM_Type, EVENTS_LOOPSDONE) ///< Concatenated sequences have been played the specified number of times.
} nrf_pwm_event_t;
/** @brief PWM interrupts. */
typedef enum
{
NRF_PWM_INT_STOPPED_MASK = PWM_INTENSET_STOPPED_Msk, ///< Interrupt on STOPPED event.
NRF_PWM_INT_SEQSTARTED0_MASK = PWM_INTENSET_SEQSTARTED0_Msk, ///< Interrupt on SEQSTARTED[0] event.
NRF_PWM_INT_SEQSTARTED1_MASK = PWM_INTENSET_SEQSTARTED1_Msk, ///< Interrupt on SEQSTARTED[1] event.
NRF_PWM_INT_SEQEND0_MASK = PWM_INTENSET_SEQEND0_Msk, ///< Interrupt on SEQEND[0] event.
NRF_PWM_INT_SEQEND1_MASK = PWM_INTENSET_SEQEND1_Msk, ///< Interrupt on SEQEND[1] event.
NRF_PWM_INT_PWMPERIODEND_MASK = PWM_INTENSET_PWMPERIODEND_Msk, ///< Interrupt on PWMPERIODEND event.
NRF_PWM_INT_LOOPSDONE_MASK = PWM_INTENSET_LOOPSDONE_Msk ///< Interrupt on LOOPSDONE event.
} nrf_pwm_int_mask_t;
/** @brief PWM shortcuts. */
typedef enum
{
NRF_PWM_SHORT_SEQEND0_STOP_MASK = PWM_SHORTS_SEQEND0_STOP_Msk, ///< Shortcut between SEQEND[0] event and STOP task.
NRF_PWM_SHORT_SEQEND1_STOP_MASK = PWM_SHORTS_SEQEND1_STOP_Msk, ///< Shortcut between SEQEND[1] event and STOP task.
NRF_PWM_SHORT_LOOPSDONE_SEQSTART0_MASK = PWM_SHORTS_LOOPSDONE_SEQSTART0_Msk, ///< Shortcut between LOOPSDONE event and SEQSTART[0] task.
NRF_PWM_SHORT_LOOPSDONE_SEQSTART1_MASK = PWM_SHORTS_LOOPSDONE_SEQSTART1_Msk, ///< Shortcut between LOOPSDONE event and SEQSTART[1] task.
NRF_PWM_SHORT_LOOPSDONE_STOP_MASK = PWM_SHORTS_LOOPSDONE_STOP_Msk ///< Shortcut between LOOPSDONE event and STOP task.
} nrf_pwm_short_mask_t;
/** @brief PWM modes of operation. */
typedef enum
{
NRF_PWM_MODE_UP = PWM_MODE_UPDOWN_Up, ///< Up counter (edge-aligned PWM duty cycle).
NRF_PWM_MODE_UP_AND_DOWN = PWM_MODE_UPDOWN_UpAndDown, ///< Up and down counter (center-aligned PWM duty cycle).
} nrf_pwm_mode_t;
/** @brief PWM base clock frequencies. */
typedef enum
{
NRF_PWM_CLK_16MHz = PWM_PRESCALER_PRESCALER_DIV_1, ///< 16 MHz / 1 = 16 MHz.
NRF_PWM_CLK_8MHz = PWM_PRESCALER_PRESCALER_DIV_2, ///< 16 MHz / 2 = 8 MHz.
NRF_PWM_CLK_4MHz = PWM_PRESCALER_PRESCALER_DIV_4, ///< 16 MHz / 4 = 4 MHz.
NRF_PWM_CLK_2MHz = PWM_PRESCALER_PRESCALER_DIV_8, ///< 16 MHz / 8 = 2 MHz.
NRF_PWM_CLK_1MHz = PWM_PRESCALER_PRESCALER_DIV_16, ///< 16 MHz / 16 = 1 MHz.
NRF_PWM_CLK_500kHz = PWM_PRESCALER_PRESCALER_DIV_32, ///< 16 MHz / 32 = 500 kHz.
NRF_PWM_CLK_250kHz = PWM_PRESCALER_PRESCALER_DIV_64, ///< 16 MHz / 64 = 250 kHz.
NRF_PWM_CLK_125kHz = PWM_PRESCALER_PRESCALER_DIV_128 ///< 16 MHz / 128 = 125 kHz.
} nrf_pwm_clk_t;
/**
* @brief PWM decoder load modes.
*
* The selected mode determines how the sequence data is read from RAM and
* spread to the compare registers.
*/
typedef enum
{
NRF_PWM_LOAD_COMMON = PWM_DECODER_LOAD_Common, ///< 1st half word (16-bit) used in all PWM channels (0-3).
NRF_PWM_LOAD_GROUPED = PWM_DECODER_LOAD_Grouped, ///< 1st half word (16-bit) used in channels 0 and 1; 2nd word in channels 2 and 3.
NRF_PWM_LOAD_INDIVIDUAL = PWM_DECODER_LOAD_Individual, ///< 1st half word (16-bit) used in channel 0; 2nd in channel 1; 3rd in channel 2; 4th in channel 3.
NRF_PWM_LOAD_WAVE_FORM = PWM_DECODER_LOAD_WaveForm ///< 1st half word (16-bit) used in channel 0; 2nd in channel 1; ... ; 4th as the top value for the pulse generator counter.
} nrf_pwm_dec_load_t;
/**
* @brief PWM decoder next step modes.
*
* The selected mode determines when the next value from the active sequence
* is loaded.
*/
typedef enum
{
NRF_PWM_STEP_AUTO = PWM_DECODER_MODE_RefreshCount, ///< Automatically after the current value is played and repeated the requested number of times.
NRF_PWM_STEP_TRIGGERED = PWM_DECODER_MODE_NextStep ///< When the @ref NRF_PWM_TASK_NEXTSTEP task is triggered.
} nrf_pwm_dec_step_t;
/**
* @brief Type used for defining duty cycle values for a sequence
* loaded in @ref NRF_PWM_LOAD_COMMON mode.
*/
typedef uint16_t nrf_pwm_values_common_t;
/**
* @brief Structure for defining duty cycle values for a sequence
* loaded in @ref NRF_PWM_LOAD_GROUPED mode.
*/
typedef struct {
uint16_t group_0; ///< Duty cycle value for group 0 (channels 0 and 1).
uint16_t group_1; ///< Duty cycle value for group 1 (channels 2 and 3).
} nrf_pwm_values_grouped_t;
/**
* @brief Structure for defining duty cycle values for a sequence
* loaded in @ref NRF_PWM_LOAD_INDIVIDUAL mode.
*/
typedef struct
{
uint16_t channel_0; ///< Duty cycle value for channel 0.
uint16_t channel_1; ///< Duty cycle value for channel 1.
uint16_t channel_2; ///< Duty cycle value for channel 2.
uint16_t channel_3; ///< Duty cycle value for channel 3.
} nrf_pwm_values_individual_t;
/**
* @brief Structure for defining duty cycle values for a sequence
* loaded in @ref NRF_PWM_LOAD_WAVE_FORM mode.
*/
typedef struct {
uint16_t channel_0; ///< Duty cycle value for channel 0.
uint16_t channel_1; ///< Duty cycle value for channel 1.
uint16_t channel_2; ///< Duty cycle value for channel 2.
uint16_t counter_top; ///< Top value for the pulse generator counter.
} nrf_pwm_values_wave_form_t;
/**
* @brief Union grouping pointers to arrays of duty cycle values applicable to
* various loading modes.
*/
typedef union {
nrf_pwm_values_common_t const * p_common; ///< Pointer to be used in @ref NRF_PWM_LOAD_COMMON mode.
nrf_pwm_values_grouped_t const * p_grouped; ///< Pointer to be used in @ref NRF_PWM_LOAD_GROUPED mode.
nrf_pwm_values_individual_t const * p_individual; ///< Pointer to be used in @ref NRF_PWM_LOAD_INDIVIDUAL mode.
nrf_pwm_values_wave_form_t const * p_wave_form; ///< Pointer to be used in @ref NRF_PWM_LOAD_WAVE_FORM mode.
uint16_t const * p_raw; ///< Pointer providing raw access to the values.
} nrf_pwm_values_t;
/**
* @brief Structure for defining a sequence of PWM duty cycles.
*
* When the sequence is set (by a call to @ref nrf_pwm_sequence_set), the
* provided duty cycle values are not copied. The @p values pointer is stored
* in the internal register of the peripheral, and the values are loaded from RAM
* during the sequence playback. Therefore, you must ensure that the values
* do not change before and during the sequence playback (for example,
* the values cannot be placed in a local variable that is allocated on stack).
* If the sequence is played in a loop and the values are to be updated
* before the next iteration, it is safe to modify them when the corresponding
* event signaling the end of sequence occurs (@ref NRF_PWM_EVENT_SEQEND0
* or @ref NRF_PWM_EVENT_SEQEND1, respectively).
*
* @note The @p repeats and @p end_delay values (which are written to the
* SEQ[n].REFRESH and SEQ[n].ENDDELAY registers in the peripheral,
* respectively) are ignored at the end of a complex sequence
* playback, indicated by the LOOPSDONE event.
* See the @linkProductSpecification52 for more information.
*/
typedef struct
{
nrf_pwm_values_t values; ///< Pointer to an array with duty cycle values. This array must be in Data RAM.
/**< This field is defined as an union of pointers
* to provide a convenient way to define duty
* cycle values in various loading modes
* (see @ref nrf_pwm_dec_load_t).
* In each value, the most significant bit (15)
* determines the polarity of the output and the
* others (14-0) compose the 15-bit value to be
* compared with the pulse generator counter. */
uint16_t length; ///< Number of 16-bit values in the array pointed by @p values.
uint32_t repeats; ///< Number of times that each duty cycle is to be repeated (after being played once). Ignored in @ref NRF_PWM_STEP_TRIGGERED mode.
uint32_t end_delay; ///< Additional time (in PWM periods) that the last duty cycle is to be kept after the sequence is played. Ignored in @ref NRF_PWM_STEP_TRIGGERED mode.
} nrf_pwm_sequence_t;
/**
* @brief Function for activating the specified PWM task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task to be activated.
*/
__STATIC_INLINE void nrf_pwm_task_trigger(NRF_PWM_Type * p_reg,
nrf_pwm_task_t task);
/**
* @brief Function for getting the address of the specified PWM task register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task PWM task.
*
* @return Address of the specified task register.
*/
__STATIC_INLINE uint32_t nrf_pwm_task_address_get(NRF_PWM_Type const * p_reg,
nrf_pwm_task_t task);
/**
* @brief Function for clearing the specified PWM event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to clear.
*/
__STATIC_INLINE void nrf_pwm_event_clear(NRF_PWM_Type * p_reg,
nrf_pwm_event_t event);
/**
* @brief Function for retrieving the state of the PWM event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be checked.
*
* @retval true The event has been generated.
* @retval false The event has not been generated.
*/
__STATIC_INLINE bool nrf_pwm_event_check(NRF_PWM_Type const * p_reg,
nrf_pwm_event_t event);
/**
* @brief Function for getting the address of the specified PWM event register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event PWM event.
*
* @return Address of the specified event register.
*/
__STATIC_INLINE uint32_t nrf_pwm_event_address_get(NRF_PWM_Type const * p_reg,
nrf_pwm_event_t event);
/**
* @brief Function for enabling the specified shortcuts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of shortcuts to be enabled.
*/
__STATIC_INLINE void nrf_pwm_shorts_enable(NRF_PWM_Type * p_reg,
uint32_t mask);
/**
* @brief Function for disabling the specified shortcuts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of shortcuts to be disabled.
*/
__STATIC_INLINE void nrf_pwm_shorts_disable(NRF_PWM_Type * p_reg,
uint32_t mask);
/**
* @brief Function for setting the configuration of PWM shortcuts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Shortcuts configuration to be set.
*/
__STATIC_INLINE void nrf_pwm_shorts_set(NRF_PWM_Type * p_reg,
uint32_t mask);
/**
* @brief Function for enabling specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of interrupts to be enabled.
*/
__STATIC_INLINE void nrf_pwm_int_enable(NRF_PWM_Type * p_reg,
uint32_t mask);
/**
* @brief Function for disabling specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of interrupts to be disabled.
*/
__STATIC_INLINE void nrf_pwm_int_disable(NRF_PWM_Type * p_reg,
uint32_t mask);
/**
* @brief Function for setting the configuration of PWM interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of interrupts to be set.
*/
__STATIC_INLINE void nrf_pwm_int_set(NRF_PWM_Type * p_reg,
uint32_t mask);
/**
* @brief Function for retrieving the state of a given interrupt.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] pwm_int Interrupt to be checked.
*
* @retval true The interrupt is enabled.
* @retval false The interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_pwm_int_enable_check(NRF_PWM_Type const * p_reg,
nrf_pwm_int_mask_t pwm_int);
#if defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting the subscribe configuration for a given
* PWM task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task for which to set the configuration.
* @param[in] channel Channel through which to subscribe events.
*/
__STATIC_INLINE void nrf_pwm_subscribe_set(NRF_PWM_Type * p_reg,
nrf_pwm_task_t task,
uint8_t channel);
/**
* @brief Function for clearing the subscribe configuration for a given
* PWM task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task for which to clear the configuration.
*/
__STATIC_INLINE void nrf_pwm_subscribe_clear(NRF_PWM_Type * p_reg,
nrf_pwm_task_t task);
/**
* @brief Function for setting the publish configuration for a given
* PWM event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event for which to set the configuration.
* @param[in] channel Channel through which to publish the event.
*/
__STATIC_INLINE void nrf_pwm_publish_set(NRF_PWM_Type * p_reg,
nrf_pwm_event_t event,
uint8_t channel);
/**
* @brief Function for clearing the publish configuration for a given
* PWM event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event for which to clear the configuration.
*/
__STATIC_INLINE void nrf_pwm_publish_clear(NRF_PWM_Type * p_reg,
nrf_pwm_event_t event);
#endif // defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for enabling the PWM peripheral.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_pwm_enable(NRF_PWM_Type * p_reg);
/**
* @brief Function for disabling the PWM peripheral.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_pwm_disable(NRF_PWM_Type * p_reg);
/**
* @brief Function for assigning pins to PWM output channels.
*
* Usage of all PWM output channels is optional. If a given channel is not
* needed, pass the @ref NRF_PWM_PIN_NOT_CONNECTED value instead of its pin
* number.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] out_pins Array with pin numbers for individual PWM output channels.
*/
__STATIC_INLINE void nrf_pwm_pins_set(NRF_PWM_Type * p_reg,
uint32_t out_pins[NRF_PWM_CHANNEL_COUNT]);
/**
* @brief Function for configuring the PWM peripheral.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] base_clock Base clock frequency.
* @param[in] mode Operating mode of the pulse generator counter.
* @param[in] top_value Value up to which the pulse generator counter counts.
*/
__STATIC_INLINE void nrf_pwm_configure(NRF_PWM_Type * p_reg,
nrf_pwm_clk_t base_clock,
nrf_pwm_mode_t mode,
uint16_t top_value);
/**
* @brief Function for defining a sequence of PWM duty cycles.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] seq_id Identifier of the sequence (0 or 1).
* @param[in] p_seq Pointer to the sequence definition.
*/
__STATIC_INLINE void nrf_pwm_sequence_set(NRF_PWM_Type * p_reg,
uint8_t seq_id,
nrf_pwm_sequence_t const * p_seq);
/**
* @brief Function for modifying the pointer to the duty cycle values
* in the specified sequence.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] seq_id Identifier of the sequence (0 or 1).
* @param[in] p_values Pointer to an array with duty cycle values.
*/
__STATIC_INLINE void nrf_pwm_seq_ptr_set(NRF_PWM_Type * p_reg,
uint8_t seq_id,
uint16_t const * p_values);
/**
* @brief Function for modifying the total number of duty cycle values
* in the specified sequence.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] seq_id Identifier of the sequence (0 or 1).
* @param[in] length Number of duty cycle values.
*/
__STATIC_INLINE void nrf_pwm_seq_cnt_set(NRF_PWM_Type * p_reg,
uint8_t seq_id,
uint16_t length);
/**
* @brief Function for modifying the additional number of PWM periods spent
* on each duty cycle value in the specified sequence.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] seq_id Identifier of the sequence (0 or 1).
* @param[in] refresh Number of additional PWM periods for each duty cycle value.
*/
__STATIC_INLINE void nrf_pwm_seq_refresh_set(NRF_PWM_Type * p_reg,
uint8_t seq_id,
uint32_t refresh);
/**
* @brief Function for modifying the additional time added after the sequence
* is played.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] seq_id Identifier of the sequence (0 or 1).
* @param[in] end_delay Number of PWM periods added at the end of the sequence.
*/
__STATIC_INLINE void nrf_pwm_seq_end_delay_set(NRF_PWM_Type * p_reg,
uint8_t seq_id,
uint32_t end_delay);
/**
* @brief Function for setting the mode of loading sequence data from RAM
* and advancing the sequence.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] dec_load Mode of loading sequence data from RAM.
* @param[in] dec_step Mode of advancing the active sequence.
*/
__STATIC_INLINE void nrf_pwm_decoder_set(NRF_PWM_Type * p_reg,
nrf_pwm_dec_load_t dec_load,
nrf_pwm_dec_step_t dec_step);
/**
* @brief Function for setting the number of times the sequence playback
* should be performed.
*
* This function applies to two-sequence playback (concatenated sequence 0 and 1).
* A single sequence can be played back only once.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] loop_count Number of times to perform the sequence playback.
*/
__STATIC_INLINE void nrf_pwm_loop_set(NRF_PWM_Type * p_reg,
uint16_t loop_count);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_pwm_task_trigger(NRF_PWM_Type * p_reg,
nrf_pwm_task_t task)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)task)) = 0x1UL;
}
__STATIC_INLINE uint32_t nrf_pwm_task_address_get(NRF_PWM_Type const * p_reg,
nrf_pwm_task_t task)
{
return ((uint32_t)p_reg + (uint32_t)task);
}
__STATIC_INLINE void nrf_pwm_event_clear(NRF_PWM_Type * p_reg,
nrf_pwm_event_t event)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0x0UL;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event));
(void)dummy;
#endif
}
__STATIC_INLINE bool nrf_pwm_event_check(NRF_PWM_Type const * p_reg,
nrf_pwm_event_t event)
{
return (bool)*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE uint32_t nrf_pwm_event_address_get(NRF_PWM_Type const * p_reg,
nrf_pwm_event_t event)
{
return ((uint32_t)p_reg + (uint32_t)event);
}
__STATIC_INLINE void nrf_pwm_shorts_enable(NRF_PWM_Type * p_reg,
uint32_t mask)
{
p_reg->SHORTS |= mask;
}
__STATIC_INLINE void nrf_pwm_shorts_disable(NRF_PWM_Type * p_reg,
uint32_t mask)
{
p_reg->SHORTS &= ~(mask);
}
__STATIC_INLINE void nrf_pwm_shorts_set(NRF_PWM_Type * p_reg,
uint32_t mask)
{
p_reg->SHORTS = mask;
}
__STATIC_INLINE void nrf_pwm_int_enable(NRF_PWM_Type * p_reg,
uint32_t mask)
{
p_reg->INTENSET = mask;
}
__STATIC_INLINE void nrf_pwm_int_disable(NRF_PWM_Type * p_reg,
uint32_t mask)
{
p_reg->INTENCLR = mask;
}
__STATIC_INLINE void nrf_pwm_int_set(NRF_PWM_Type * p_reg,
uint32_t mask)
{
p_reg->INTEN = mask;
}
__STATIC_INLINE bool nrf_pwm_int_enable_check(NRF_PWM_Type const * p_reg,
nrf_pwm_int_mask_t pwm_int)
{
return (bool)(p_reg->INTENSET & pwm_int);
}
#if defined(DPPI_PRESENT)
__STATIC_INLINE void nrf_pwm_subscribe_set(NRF_PWM_Type * p_reg,
nrf_pwm_task_t task,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) task + 0x80uL)) =
((uint32_t)channel | PWM_SUBSCRIBE_STOP_EN_Msk);
}
__STATIC_INLINE void nrf_pwm_subscribe_clear(NRF_PWM_Type * p_reg,
nrf_pwm_task_t task)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) task + 0x80uL)) = 0;
}
__STATIC_INLINE void nrf_pwm_publish_set(NRF_PWM_Type * p_reg,
nrf_pwm_event_t event,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) event + 0x80uL)) =
((uint32_t)channel | PWM_PUBLISH_STOPPED_EN_Msk);
}
__STATIC_INLINE void nrf_pwm_publish_clear(NRF_PWM_Type * p_reg,
nrf_pwm_event_t event)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) event + 0x80uL)) = 0;
}
#endif // defined(DPPI_PRESENT)
__STATIC_INLINE void nrf_pwm_enable(NRF_PWM_Type * p_reg)
{
p_reg->ENABLE = (PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos);
}
__STATIC_INLINE void nrf_pwm_disable(NRF_PWM_Type * p_reg)
{
p_reg->ENABLE = (PWM_ENABLE_ENABLE_Disabled << PWM_ENABLE_ENABLE_Pos);
}
__STATIC_INLINE void nrf_pwm_pins_set(NRF_PWM_Type * p_reg,
uint32_t out_pins[NRF_PWM_CHANNEL_COUNT])
{
uint8_t i;
for (i = 0; i < NRF_PWM_CHANNEL_COUNT; ++i)
{
p_reg->PSEL.OUT[i] = out_pins[i];
}
}
__STATIC_INLINE void nrf_pwm_configure(NRF_PWM_Type * p_reg,
nrf_pwm_clk_t base_clock,
nrf_pwm_mode_t mode,
uint16_t top_value)
{
NRFX_ASSERT(top_value <= PWM_COUNTERTOP_COUNTERTOP_Msk);
p_reg->PRESCALER = base_clock;
p_reg->MODE = mode;
p_reg->COUNTERTOP = top_value;
}
__STATIC_INLINE void nrf_pwm_sequence_set(NRF_PWM_Type * p_reg,
uint8_t seq_id,
nrf_pwm_sequence_t const * p_seq)
{
NRFX_ASSERT(p_seq != NULL);
nrf_pwm_seq_ptr_set( p_reg, seq_id, p_seq->values.p_raw);
nrf_pwm_seq_cnt_set( p_reg, seq_id, p_seq->length);
nrf_pwm_seq_refresh_set( p_reg, seq_id, p_seq->repeats);
nrf_pwm_seq_end_delay_set(p_reg, seq_id, p_seq->end_delay);
}
__STATIC_INLINE void nrf_pwm_seq_ptr_set(NRF_PWM_Type * p_reg,
uint8_t seq_id,
uint16_t const * p_values)
{
NRFX_ASSERT(seq_id <= 1);
NRFX_ASSERT(p_values != NULL);
p_reg->SEQ[seq_id].PTR = (uint32_t)p_values;
}
__STATIC_INLINE void nrf_pwm_seq_cnt_set(NRF_PWM_Type * p_reg,
uint8_t seq_id,
uint16_t length)
{
NRFX_ASSERT(seq_id <= 1);
NRFX_ASSERT(length != 0);
NRFX_ASSERT(length <= PWM_SEQ_CNT_CNT_Msk);
p_reg->SEQ[seq_id].CNT = length;
}
__STATIC_INLINE void nrf_pwm_seq_refresh_set(NRF_PWM_Type * p_reg,
uint8_t seq_id,
uint32_t refresh)
{
NRFX_ASSERT(seq_id <= 1);
NRFX_ASSERT(refresh <= PWM_SEQ_REFRESH_CNT_Msk);
p_reg->SEQ[seq_id].REFRESH = refresh;
}
__STATIC_INLINE void nrf_pwm_seq_end_delay_set(NRF_PWM_Type * p_reg,
uint8_t seq_id,
uint32_t end_delay)
{
NRFX_ASSERT(seq_id <= 1);
NRFX_ASSERT(end_delay <= PWM_SEQ_ENDDELAY_CNT_Msk);
p_reg->SEQ[seq_id].ENDDELAY = end_delay;
}
__STATIC_INLINE void nrf_pwm_decoder_set(NRF_PWM_Type * p_reg,
nrf_pwm_dec_load_t dec_load,
nrf_pwm_dec_step_t dec_step)
{
p_reg->DECODER = ((uint32_t)dec_load << PWM_DECODER_LOAD_Pos) |
((uint32_t)dec_step << PWM_DECODER_MODE_Pos);
}
__STATIC_INLINE void nrf_pwm_loop_set(NRF_PWM_Type * p_reg,
uint16_t loop_count)
{
p_reg->LOOP = loop_count;
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_PWM_H__
File diff suppressed because it is too large Load Diff
+104
View File
@@ -0,0 +1,104 @@
/**
* Copyright (c) 2018 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_REGULATORS_H__
#define NRF_REGULATORS_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_regulators_hal REGULATORS HAL
* @{
* @ingroup nrf_power
* @brief Hardware access layer for managing the REGULATORS peripheral.
*/
/**
* @brief Function for enabling or disabling DCDC converter.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] enable Set true to enable or false to disable DCDC converter.
*/
__STATIC_INLINE void nrf_regulators_dcdcen_set(NRF_REGULATORS_Type * p_reg, bool enable);
/**
* @brief Function for putting CPU in system OFF mode.
*
* This function puts the CPU into system off mode.
* The only way to wake up the CPU is by reset.
*
* @note This function never returns.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_regulators_system_off(NRF_REGULATORS_Type * p_reg);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_regulators_dcdcen_set(NRF_REGULATORS_Type * p_reg, bool enable)
{
p_reg->DCDCEN = (enable ? REGULATORS_DCDCEN_DCDCEN_Msk : 0);
}
__STATIC_INLINE void nrf_regulators_system_off(NRF_REGULATORS_Type * p_reg)
{
p_reg->SYSTEMOFF = REGULATORS_SYSTEMOFF_SYSTEMOFF_Msk;
__DSB();
/* Solution for simulated System OFF in debug mode */
while (true)
{
__WFE();
}
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_REGULATORS_H__
+260
View File
@@ -0,0 +1,260 @@
/**
* Copyright (c) 2014 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_RNG_H__
#define NRF_RNG_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_rng_hal RNG HAL
* @{
* @ingroup nrf_rng
* @brief Hardware access layer (HAL) for managing the Random Number Generator (RNG) peripheral.
*/
/** @brief RNG tasks. */
typedef enum
{
NRF_RNG_TASK_START = offsetof(NRF_RNG_Type, TASKS_START), /**< Start the random number generator. */
NRF_RNG_TASK_STOP = offsetof(NRF_RNG_Type, TASKS_STOP) /**< Stop the random number generator. */
} nrf_rng_task_t;
/** @brief RNG events. */
typedef enum
{
NRF_RNG_EVENT_VALRDY = offsetof(NRF_RNG_Type, EVENTS_VALRDY) /**< New random number generated event. */
} nrf_rng_event_t;
/** @brief RNG interrupts. */
typedef enum
{
NRF_RNG_INT_VALRDY_MASK = RNG_INTENSET_VALRDY_Msk /**< Mask for enabling or disabling an interrupt on VALRDY event. */
} nrf_rng_int_mask_t;
/** @brief Types of RNG shortcuts. */
typedef enum
{
NRF_RNG_SHORT_VALRDY_STOP_MASK = RNG_SHORTS_VALRDY_STOP_Msk /**< Mask for setting shortcut between EVENT_VALRDY and TASK_STOP. */
} nrf_rng_short_mask_t;
/**
* @brief Function for enabling interrupts.
*
* @param[in] mask Mask of interrupts to be enabled.
*/
__STATIC_INLINE void nrf_rng_int_enable(uint32_t mask);
/**
* @brief Function for disabling interrupts.
*
* @param[in] mask Mask of interrupts to be disabled.
*/
__STATIC_INLINE void nrf_rng_int_disable(uint32_t mask);
/**
* @brief Function for getting the state of the specified interrupt.
*
* @param[in] mask Interrupts to be checked.
*
* @retval true The interrupt is not enabled.
* @retval false The interrupt is enabled.
*/
__STATIC_INLINE bool nrf_rng_int_get(nrf_rng_int_mask_t mask);
/**
* @brief Function for getting the address of the specified task.
*
* This function can be used by the PPI module.
*
* @param[in] rng_task The specified task.
*
* @return Address of the specified task.
*/
__STATIC_INLINE uint32_t * nrf_rng_task_address_get(nrf_rng_task_t rng_task);
/**
* @brief Function for triggering the specified task.
*
* @param[in] rng_task The specified Task.
*/
__STATIC_INLINE void nrf_rng_task_trigger(nrf_rng_task_t rng_task);
/**
* @brief Function for getting address of the specified event.
*
* This function can be used by the PPI module.
*
* @param[in] rng_event The specified event.
*
* @return Address of the specified event.
*/
__STATIC_INLINE uint32_t * nrf_rng_event_address_get(nrf_rng_event_t rng_event);
/**
* @brief Function for clearing the specified event.
*
* @param[in] rng_event The specified event.
*/
__STATIC_INLINE void nrf_rng_event_clear(nrf_rng_event_t rng_event);
/**
* @brief Function for getting the state of the specified event.
*
* @param[in] rng_event The specified event.
*
* @retval true The event is not set.
* @retval false The event is set.
*/
__STATIC_INLINE bool nrf_rng_event_get(nrf_rng_event_t rng_event);
/**
* @brief Function for setting shortcuts.
*
* @param[in] mask Mask of shortcuts.
*/
__STATIC_INLINE void nrf_rng_shorts_enable(uint32_t mask);
/**
* @brief Function for clearing shortcuts.
*
* @param[in] mask Mask of shortcuts.
*/
__STATIC_INLINE void nrf_rng_shorts_disable(uint32_t mask);
/**
* @brief Function for getting the previously generated random value.
*
* @return Previously generated random value.
*/
__STATIC_INLINE uint8_t nrf_rng_random_value_get(void);
/** @brief Function for enabling digital error correction. */
__STATIC_INLINE void nrf_rng_error_correction_enable(void);
/** @brief Function for disabling digital error correction. */
__STATIC_INLINE void nrf_rng_error_correction_disable(void);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_rng_int_enable(uint32_t mask)
{
NRF_RNG->INTENSET = mask;
}
__STATIC_INLINE void nrf_rng_int_disable(uint32_t mask)
{
NRF_RNG->INTENCLR = mask;
}
__STATIC_INLINE bool nrf_rng_int_get(nrf_rng_int_mask_t mask)
{
return (bool)(NRF_RNG->INTENCLR & mask);
}
__STATIC_INLINE uint32_t * nrf_rng_task_address_get(nrf_rng_task_t rng_task)
{
return (uint32_t *)((uint8_t *)NRF_RNG + (uint32_t)rng_task);
}
__STATIC_INLINE void nrf_rng_task_trigger(nrf_rng_task_t rng_task)
{
*((volatile uint32_t *)((uint8_t *)NRF_RNG + (uint32_t)rng_task)) = 0x1UL;
}
__STATIC_INLINE uint32_t * nrf_rng_event_address_get(nrf_rng_event_t rng_event)
{
return (uint32_t *)((uint8_t *)NRF_RNG + (uint32_t)rng_event);
}
__STATIC_INLINE void nrf_rng_event_clear(nrf_rng_event_t rng_event)
{
*((volatile uint32_t *)((uint8_t *)NRF_RNG + (uint32_t)rng_event)) = 0x0UL;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)NRF_RNG + (uint32_t)rng_event));
(void)dummy;
#endif
}
__STATIC_INLINE bool nrf_rng_event_get(nrf_rng_event_t rng_event)
{
return (bool) * ((volatile uint32_t *)((uint8_t *)NRF_RNG + (uint32_t)rng_event));
}
__STATIC_INLINE void nrf_rng_shorts_enable(uint32_t mask)
{
NRF_RNG->SHORTS |= mask;
}
__STATIC_INLINE void nrf_rng_shorts_disable(uint32_t mask)
{
NRF_RNG->SHORTS &= ~mask;
}
__STATIC_INLINE uint8_t nrf_rng_random_value_get(void)
{
return (uint8_t)(NRF_RNG->VALUE & RNG_VALUE_VALUE_Msk);
}
__STATIC_INLINE void nrf_rng_error_correction_enable(void)
{
NRF_RNG->CONFIG |= RNG_CONFIG_DERCEN_Msk;
}
__STATIC_INLINE void nrf_rng_error_correction_disable(void)
{
NRF_RNG->CONFIG &= ~RNG_CONFIG_DERCEN_Msk;
}
#endif
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* NRF_RNG_H__ */
+426
View File
@@ -0,0 +1,426 @@
/**
* Copyright (c) 2014 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_RTC_H
#define NRF_RTC_H
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_rtc_hal RTC HAL
* @{
* @ingroup nrf_rtc
* @brief Hardware access layer for managing the Real Time Counter (RTC) peripheral.
*/
/** @brief Macro for getting the number of compare channels available in a given RTC instance. */
#define NRF_RTC_CC_CHANNEL_COUNT(id) NRFX_CONCAT_3(RTC, id, _CC_NUM)
/** @brief Input frequency of the RTC instance. */
#define RTC_INPUT_FREQ 32768
/** @brief Macro for converting expected frequency to prescaler setting. */
#define RTC_FREQ_TO_PRESCALER(FREQ) (uint16_t)(((RTC_INPUT_FREQ) / (FREQ)) - 1)
/** @brief Macro for trimming values to the RTC bit width. */
#define RTC_WRAP(val) ((val) & RTC_COUNTER_COUNTER_Msk)
/** @brief Macro for creating the interrupt bitmask for the specified compare channel. */
#define RTC_CHANNEL_INT_MASK(ch) ((uint32_t)(NRF_RTC_INT_COMPARE0_MASK) << (ch))
/** @brief Macro for obtaining the compare event for the specified channel. */
#define RTC_CHANNEL_EVENT_ADDR(ch) (nrf_rtc_event_t)((NRF_RTC_EVENT_COMPARE_0) + (ch) * sizeof(uint32_t))
/** @brief RTC tasks. */
typedef enum
{
NRF_RTC_TASK_START = offsetof(NRF_RTC_Type,TASKS_START), /**< Start. */
NRF_RTC_TASK_STOP = offsetof(NRF_RTC_Type,TASKS_STOP), /**< Stop. */
NRF_RTC_TASK_CLEAR = offsetof(NRF_RTC_Type,TASKS_CLEAR), /**< Clear. */
NRF_RTC_TASK_TRIGGER_OVERFLOW = offsetof(NRF_RTC_Type,TASKS_TRIGOVRFLW),/**< Trigger overflow. */
} nrf_rtc_task_t;
/** @brief RTC events. */
typedef enum
{
NRF_RTC_EVENT_TICK = offsetof(NRF_RTC_Type,EVENTS_TICK), /**< Tick event. */
NRF_RTC_EVENT_OVERFLOW = offsetof(NRF_RTC_Type,EVENTS_OVRFLW), /**< Overflow event. */
NRF_RTC_EVENT_COMPARE_0 = offsetof(NRF_RTC_Type,EVENTS_COMPARE[0]), /**< Compare 0 event. */
NRF_RTC_EVENT_COMPARE_1 = offsetof(NRF_RTC_Type,EVENTS_COMPARE[1]), /**< Compare 1 event. */
NRF_RTC_EVENT_COMPARE_2 = offsetof(NRF_RTC_Type,EVENTS_COMPARE[2]), /**< Compare 2 event. */
NRF_RTC_EVENT_COMPARE_3 = offsetof(NRF_RTC_Type,EVENTS_COMPARE[3]) /**< Compare 3 event. */
} nrf_rtc_event_t;
/** @brief RTC interrupts. */
typedef enum
{
NRF_RTC_INT_TICK_MASK = RTC_INTENSET_TICK_Msk, /**< RTC interrupt from tick event. */
NRF_RTC_INT_OVERFLOW_MASK = RTC_INTENSET_OVRFLW_Msk, /**< RTC interrupt from overflow event. */
NRF_RTC_INT_COMPARE0_MASK = RTC_INTENSET_COMPARE0_Msk, /**< RTC interrupt from compare event on channel 0. */
NRF_RTC_INT_COMPARE1_MASK = RTC_INTENSET_COMPARE1_Msk, /**< RTC interrupt from compare event on channel 1. */
NRF_RTC_INT_COMPARE2_MASK = RTC_INTENSET_COMPARE2_Msk, /**< RTC interrupt from compare event on channel 2. */
NRF_RTC_INT_COMPARE3_MASK = RTC_INTENSET_COMPARE3_Msk /**< RTC interrupt from compare event on channel 3. */
} nrf_rtc_int_t;
/**
* @brief Function for setting a compare value for a channel.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] ch Channel.
* @param[in] cc_val Compare value to be set.
*/
__STATIC_INLINE void nrf_rtc_cc_set(NRF_RTC_Type * p_reg, uint32_t ch, uint32_t cc_val);
/**
* @brief Function for returning the compare value for a channel.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] ch Channel.
*
* @return COMPARE[ch] value.
*/
__STATIC_INLINE uint32_t nrf_rtc_cc_get(NRF_RTC_Type * p_reg, uint32_t ch);
/**
* @brief Function for enabling interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Interrupt mask to be enabled.
*/
__STATIC_INLINE void nrf_rtc_int_enable(NRF_RTC_Type * p_reg, uint32_t mask);
/**
* @brief Function for disabling interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Interrupt mask to be disabled.
*/
__STATIC_INLINE void nrf_rtc_int_disable(NRF_RTC_Type * p_reg, uint32_t mask);
/**
* @brief Function for checking if interrupts are enabled.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of interrupt flags to be checked.
*
* @return Mask with enabled interrupts.
*/
__STATIC_INLINE uint32_t nrf_rtc_int_is_enabled(NRF_RTC_Type * p_reg, uint32_t mask);
/**
* @brief Function for returning the status of currently enabled interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Value in INTEN register.
*/
__STATIC_INLINE uint32_t nrf_rtc_int_get(NRF_RTC_Type * p_reg);
#if defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting the subscribe configuration for a given
* RTC task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task for which to set the configuration.
* @param[in] channel Channel through which to subscribe events.
*/
__STATIC_INLINE void nrf_rtc_subscribe_set(NRF_RTC_Type * p_reg,
nrf_rtc_task_t task,
uint8_t channel);
/**
* @brief Function for clearing the subscribe configuration for a given
* RTC task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task for which to clear the configuration.
*/
__STATIC_INLINE void nrf_rtc_subscribe_clear(NRF_RTC_Type * p_reg,
nrf_rtc_task_t task);
/**
* @brief Function for setting the publish configuration for a given
* RTC event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event for which to set the configuration.
* @param[in] channel Channel through which to publish the event.
*/
__STATIC_INLINE void nrf_rtc_publish_set(NRF_RTC_Type * p_reg,
nrf_rtc_event_t event,
uint8_t channel);
/**
* @brief Function for clearing the publish configuration for a given
* RTC event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event for which to clear the configuration.
*/
__STATIC_INLINE void nrf_rtc_publish_clear(NRF_RTC_Type * p_reg,
nrf_rtc_event_t event);
#endif // defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for checking if an event is pending.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Address of the event.
*
* @return Mask of pending events.
*/
__STATIC_INLINE uint32_t nrf_rtc_event_pending(NRF_RTC_Type * p_reg, nrf_rtc_event_t event);
/**
* @brief Function for clearing an event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be cleared.
*/
__STATIC_INLINE void nrf_rtc_event_clear(NRF_RTC_Type * p_reg, nrf_rtc_event_t event);
/**
* @brief Function for returning a counter value.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Counter value.
*/
__STATIC_INLINE uint32_t nrf_rtc_counter_get(NRF_RTC_Type * p_reg);
/**
* @brief Function for setting a prescaler value.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] val Value to set the prescaler to.
*/
__STATIC_INLINE void nrf_rtc_prescaler_set(NRF_RTC_Type * p_reg, uint32_t val);
/**
* @brief Function for returning the address of an event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Requested event.
*
* @return Address of the requested event register.
*/
__STATIC_INLINE uint32_t nrf_rtc_event_address_get(NRF_RTC_Type * p_reg, nrf_rtc_event_t event);
/**
* @brief Function for returning the address of a task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Requested task.
*
* @return Address of the requested task register.
*/
__STATIC_INLINE uint32_t nrf_rtc_task_address_get(NRF_RTC_Type * p_reg, nrf_rtc_task_t task);
/**
* @brief Function for starting a task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Requested task.
*/
__STATIC_INLINE void nrf_rtc_task_trigger(NRF_RTC_Type * p_reg, nrf_rtc_task_t task);
/**
* @brief Function for enabling events.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of event flags to be enabled.
*/
__STATIC_INLINE void nrf_rtc_event_enable(NRF_RTC_Type * p_reg, uint32_t mask);
/**
* @brief Function for disabling an event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Requested event.
*/
__STATIC_INLINE void nrf_rtc_event_disable(NRF_RTC_Type * p_reg, uint32_t event);
/**
* @brief Function for getting the COMPARE event associated with the specified compare channel.
*
* @param[in] index Compare channel index.
*
* @return Requested COMPARE event.
*/
__STATIC_INLINE nrf_rtc_event_t nrf_rtc_compare_event_get(uint8_t index);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_rtc_cc_set(NRF_RTC_Type * p_reg, uint32_t ch, uint32_t cc_val)
{
p_reg->CC[ch] = cc_val;
}
__STATIC_INLINE uint32_t nrf_rtc_cc_get(NRF_RTC_Type * p_reg, uint32_t ch)
{
return p_reg->CC[ch];
}
__STATIC_INLINE void nrf_rtc_int_enable(NRF_RTC_Type * p_reg, uint32_t mask)
{
p_reg->INTENSET = mask;
}
__STATIC_INLINE void nrf_rtc_int_disable(NRF_RTC_Type * p_reg, uint32_t mask)
{
p_reg->INTENCLR = mask;
}
__STATIC_INLINE uint32_t nrf_rtc_int_is_enabled(NRF_RTC_Type * p_reg, uint32_t mask)
{
return (p_reg->INTENSET & mask);
}
__STATIC_INLINE uint32_t nrf_rtc_int_get(NRF_RTC_Type * p_reg)
{
return p_reg->INTENSET;
}
#if defined(DPPI_PRESENT)
__STATIC_INLINE void nrf_rtc_subscribe_set(NRF_RTC_Type * p_reg,
nrf_rtc_task_t task,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) task + 0x80uL)) =
((uint32_t)channel | RTC_SUBSCRIBE_START_EN_Msk);
}
__STATIC_INLINE void nrf_rtc_subscribe_clear(NRF_RTC_Type * p_reg,
nrf_rtc_task_t task)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) task + 0x80uL)) = 0;
}
__STATIC_INLINE void nrf_rtc_publish_set(NRF_RTC_Type * p_reg,
nrf_rtc_event_t event,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) event + 0x80uL)) =
((uint32_t)channel | RTC_PUBLISH_TICK_EN_Msk);
}
__STATIC_INLINE void nrf_rtc_publish_clear(NRF_RTC_Type * p_reg,
nrf_rtc_event_t event)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) event + 0x80uL)) = 0;
}
#endif // defined(DPPI_PRESENT)
__STATIC_INLINE uint32_t nrf_rtc_event_pending(NRF_RTC_Type * p_reg, nrf_rtc_event_t event)
{
return *(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE void nrf_rtc_event_clear(NRF_RTC_Type * p_reg, nrf_rtc_event_t event)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event));
(void)dummy;
#endif
}
__STATIC_INLINE uint32_t nrf_rtc_counter_get(NRF_RTC_Type * p_reg)
{
return p_reg->COUNTER;
}
__STATIC_INLINE void nrf_rtc_prescaler_set(NRF_RTC_Type * p_reg, uint32_t val)
{
NRFX_ASSERT(val <= (RTC_PRESCALER_PRESCALER_Msk >> RTC_PRESCALER_PRESCALER_Pos));
p_reg->PRESCALER = val;
}
__STATIC_INLINE uint32_t rtc_prescaler_get(NRF_RTC_Type * p_reg)
{
return p_reg->PRESCALER;
}
__STATIC_INLINE uint32_t nrf_rtc_event_address_get(NRF_RTC_Type * p_reg, nrf_rtc_event_t event)
{
return (uint32_t)p_reg + event;
}
__STATIC_INLINE uint32_t nrf_rtc_task_address_get(NRF_RTC_Type * p_reg, nrf_rtc_task_t task)
{
return (uint32_t)p_reg + task;
}
__STATIC_INLINE void nrf_rtc_task_trigger(NRF_RTC_Type * p_reg, nrf_rtc_task_t task)
{
*(__IO uint32_t *)((uint32_t)p_reg + task) = 1;
}
__STATIC_INLINE void nrf_rtc_event_enable(NRF_RTC_Type * p_reg, uint32_t mask)
{
p_reg->EVTENSET = mask;
}
__STATIC_INLINE void nrf_rtc_event_disable(NRF_RTC_Type * p_reg, uint32_t mask)
{
p_reg->EVTENCLR = mask;
}
__STATIC_INLINE nrf_rtc_event_t nrf_rtc_compare_event_get(uint8_t index)
{
return (nrf_rtc_event_t)NRFX_OFFSETOF(NRF_RTC_Type, EVENTS_COMPARE[index]);
}
#endif
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* NRF_RTC_H */
+896
View File
@@ -0,0 +1,896 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_SAADC_H_
#define NRF_SAADC_H_
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_saadc_hal SAADC HAL
* @{
* @ingroup nrf_saadc
* @brief Hardware access layer for managing the SAADC peripheral.
*/
/** @brief Number of available SAADC channels. */
#define NRF_SAADC_CHANNEL_COUNT 8
/** @brief Resolution of the analog-to-digital converter. */
typedef enum
{
NRF_SAADC_RESOLUTION_8BIT = SAADC_RESOLUTION_VAL_8bit, ///< 8 bit resolution.
NRF_SAADC_RESOLUTION_10BIT = SAADC_RESOLUTION_VAL_10bit, ///< 10 bit resolution.
NRF_SAADC_RESOLUTION_12BIT = SAADC_RESOLUTION_VAL_12bit, ///< 12 bit resolution.
NRF_SAADC_RESOLUTION_14BIT = SAADC_RESOLUTION_VAL_14bit ///< 14 bit resolution.
} nrf_saadc_resolution_t;
/** @brief Input selection for the analog-to-digital converter. */
typedef enum
{
NRF_SAADC_INPUT_DISABLED = SAADC_CH_PSELP_PSELP_NC, ///< Not connected.
NRF_SAADC_INPUT_AIN0 = SAADC_CH_PSELP_PSELP_AnalogInput0, ///< Analog input 0 (AIN0).
NRF_SAADC_INPUT_AIN1 = SAADC_CH_PSELP_PSELP_AnalogInput1, ///< Analog input 1 (AIN1).
NRF_SAADC_INPUT_AIN2 = SAADC_CH_PSELP_PSELP_AnalogInput2, ///< Analog input 2 (AIN2).
NRF_SAADC_INPUT_AIN3 = SAADC_CH_PSELP_PSELP_AnalogInput3, ///< Analog input 3 (AIN3).
NRF_SAADC_INPUT_AIN4 = SAADC_CH_PSELP_PSELP_AnalogInput4, ///< Analog input 4 (AIN4).
NRF_SAADC_INPUT_AIN5 = SAADC_CH_PSELP_PSELP_AnalogInput5, ///< Analog input 5 (AIN5).
NRF_SAADC_INPUT_AIN6 = SAADC_CH_PSELP_PSELP_AnalogInput6, ///< Analog input 6 (AIN6).
NRF_SAADC_INPUT_AIN7 = SAADC_CH_PSELP_PSELP_AnalogInput7, ///< Analog input 7 (AIN7).
NRF_SAADC_INPUT_VDD = SAADC_CH_PSELP_PSELP_VDD, ///< VDD as input.
#if defined(SAADC_CH_PSELP_PSELP_VDDHDIV5) || defined(__NRFX_DOXYGEN__)
NRF_SAADC_INPUT_VDDHDIV5 = SAADC_CH_PSELP_PSELP_VDDHDIV5 ///< VDDH/5 as input.
#endif
} nrf_saadc_input_t;
/** @brief Analog-to-digital converter oversampling mode. */
typedef enum
{
NRF_SAADC_OVERSAMPLE_DISABLED = SAADC_OVERSAMPLE_OVERSAMPLE_Bypass, ///< No oversampling.
NRF_SAADC_OVERSAMPLE_2X = SAADC_OVERSAMPLE_OVERSAMPLE_Over2x, ///< Oversample 2x.
NRF_SAADC_OVERSAMPLE_4X = SAADC_OVERSAMPLE_OVERSAMPLE_Over4x, ///< Oversample 4x.
NRF_SAADC_OVERSAMPLE_8X = SAADC_OVERSAMPLE_OVERSAMPLE_Over8x, ///< Oversample 8x.
NRF_SAADC_OVERSAMPLE_16X = SAADC_OVERSAMPLE_OVERSAMPLE_Over16x, ///< Oversample 16x.
NRF_SAADC_OVERSAMPLE_32X = SAADC_OVERSAMPLE_OVERSAMPLE_Over32x, ///< Oversample 32x.
NRF_SAADC_OVERSAMPLE_64X = SAADC_OVERSAMPLE_OVERSAMPLE_Over64x, ///< Oversample 64x.
NRF_SAADC_OVERSAMPLE_128X = SAADC_OVERSAMPLE_OVERSAMPLE_Over128x, ///< Oversample 128x.
NRF_SAADC_OVERSAMPLE_256X = SAADC_OVERSAMPLE_OVERSAMPLE_Over256x ///< Oversample 256x.
} nrf_saadc_oversample_t;
/** @brief Analog-to-digital converter channel resistor control. */
typedef enum
{
NRF_SAADC_RESISTOR_DISABLED = SAADC_CH_CONFIG_RESP_Bypass, ///< Bypass resistor ladder.
NRF_SAADC_RESISTOR_PULLDOWN = SAADC_CH_CONFIG_RESP_Pulldown, ///< Pull-down to GND.
NRF_SAADC_RESISTOR_PULLUP = SAADC_CH_CONFIG_RESP_Pullup, ///< Pull-up to VDD.
NRF_SAADC_RESISTOR_VDD1_2 = SAADC_CH_CONFIG_RESP_VDD1_2 ///< Set input at VDD/2.
} nrf_saadc_resistor_t;
/** @brief Gain factor of the analog-to-digital converter input. */
typedef enum
{
NRF_SAADC_GAIN1_6 = SAADC_CH_CONFIG_GAIN_Gain1_6, ///< Gain factor 1/6.
NRF_SAADC_GAIN1_5 = SAADC_CH_CONFIG_GAIN_Gain1_5, ///< Gain factor 1/5.
NRF_SAADC_GAIN1_4 = SAADC_CH_CONFIG_GAIN_Gain1_4, ///< Gain factor 1/4.
NRF_SAADC_GAIN1_3 = SAADC_CH_CONFIG_GAIN_Gain1_3, ///< Gain factor 1/3.
NRF_SAADC_GAIN1_2 = SAADC_CH_CONFIG_GAIN_Gain1_2, ///< Gain factor 1/2.
NRF_SAADC_GAIN1 = SAADC_CH_CONFIG_GAIN_Gain1, ///< Gain factor 1.
NRF_SAADC_GAIN2 = SAADC_CH_CONFIG_GAIN_Gain2, ///< Gain factor 2.
NRF_SAADC_GAIN4 = SAADC_CH_CONFIG_GAIN_Gain4, ///< Gain factor 4.
} nrf_saadc_gain_t;
/** @brief Reference selection for the analog-to-digital converter. */
typedef enum
{
NRF_SAADC_REFERENCE_INTERNAL = SAADC_CH_CONFIG_REFSEL_Internal, ///< Internal reference (0.6 V).
NRF_SAADC_REFERENCE_VDD4 = SAADC_CH_CONFIG_REFSEL_VDD1_4 ///< VDD/4 as reference.
} nrf_saadc_reference_t;
/** @brief Analog-to-digital converter acquisition time. */
typedef enum
{
NRF_SAADC_ACQTIME_3US = SAADC_CH_CONFIG_TACQ_3us, ///< 3 us.
NRF_SAADC_ACQTIME_5US = SAADC_CH_CONFIG_TACQ_5us, ///< 5 us.
NRF_SAADC_ACQTIME_10US = SAADC_CH_CONFIG_TACQ_10us, ///< 10 us.
NRF_SAADC_ACQTIME_15US = SAADC_CH_CONFIG_TACQ_15us, ///< 15 us.
NRF_SAADC_ACQTIME_20US = SAADC_CH_CONFIG_TACQ_20us, ///< 20 us.
NRF_SAADC_ACQTIME_40US = SAADC_CH_CONFIG_TACQ_40us ///< 40 us.
} nrf_saadc_acqtime_t;
/** @brief Analog-to-digital converter channel mode. */
typedef enum
{
NRF_SAADC_MODE_SINGLE_ENDED = SAADC_CH_CONFIG_MODE_SE, ///< Single-ended mode. PSELN will be ignored, negative input to ADC shorted to GND.
NRF_SAADC_MODE_DIFFERENTIAL = SAADC_CH_CONFIG_MODE_Diff ///< Differential mode.
} nrf_saadc_mode_t;
/** @brief Analog-to-digital converter channel burst mode. */
typedef enum
{
NRF_SAADC_BURST_DISABLED = SAADC_CH_CONFIG_BURST_Disabled, ///< Burst mode is disabled (normal operation).
NRF_SAADC_BURST_ENABLED = SAADC_CH_CONFIG_BURST_Enabled ///< Burst mode is enabled. SAADC takes 2^OVERSAMPLE number of samples as fast as it can, and sends the average to Data RAM.
} nrf_saadc_burst_t;
/** @brief Analog-to-digital converter tasks. */
typedef enum
{
NRF_SAADC_TASK_START = offsetof(NRF_SAADC_Type, TASKS_START), ///< Start the ADC and prepare the result buffer in RAM.
NRF_SAADC_TASK_SAMPLE = offsetof(NRF_SAADC_Type, TASKS_SAMPLE), ///< Take one ADC sample. If scan is enabled, all channels are sampled.
NRF_SAADC_TASK_STOP = offsetof(NRF_SAADC_Type, TASKS_STOP), ///< Stop the ADC and terminate any ongoing conversion.
NRF_SAADC_TASK_CALIBRATEOFFSET = offsetof(NRF_SAADC_Type, TASKS_CALIBRATEOFFSET), ///< Starts offset auto-calibration.
} nrf_saadc_task_t;
/** @brief Analog-to-digital converter events. */
typedef enum
{
NRF_SAADC_EVENT_STARTED = offsetof(NRF_SAADC_Type, EVENTS_STARTED), ///< The ADC has started.
NRF_SAADC_EVENT_END = offsetof(NRF_SAADC_Type, EVENTS_END), ///< The ADC has filled up the result buffer.
NRF_SAADC_EVENT_DONE = offsetof(NRF_SAADC_Type, EVENTS_DONE), ///< A conversion task has been completed.
NRF_SAADC_EVENT_RESULTDONE = offsetof(NRF_SAADC_Type, EVENTS_RESULTDONE), ///< A result is ready to get transferred to RAM.
NRF_SAADC_EVENT_CALIBRATEDONE = offsetof(NRF_SAADC_Type, EVENTS_CALIBRATEDONE), ///< Calibration is complete.
NRF_SAADC_EVENT_STOPPED = offsetof(NRF_SAADC_Type, EVENTS_STOPPED), ///< The ADC has stopped.
NRF_SAADC_EVENT_CH0_LIMITH = offsetof(NRF_SAADC_Type, EVENTS_CH[0].LIMITH), ///< Last result is equal or above CH[0].LIMIT.HIGH.
NRF_SAADC_EVENT_CH0_LIMITL = offsetof(NRF_SAADC_Type, EVENTS_CH[0].LIMITL), ///< Last result is equal or below CH[0].LIMIT.LOW.
NRF_SAADC_EVENT_CH1_LIMITH = offsetof(NRF_SAADC_Type, EVENTS_CH[1].LIMITH), ///< Last result is equal or above CH[1].LIMIT.HIGH.
NRF_SAADC_EVENT_CH1_LIMITL = offsetof(NRF_SAADC_Type, EVENTS_CH[1].LIMITL), ///< Last result is equal or below CH[1].LIMIT.LOW.
NRF_SAADC_EVENT_CH2_LIMITH = offsetof(NRF_SAADC_Type, EVENTS_CH[2].LIMITH), ///< Last result is equal or above CH[2].LIMIT.HIGH.
NRF_SAADC_EVENT_CH2_LIMITL = offsetof(NRF_SAADC_Type, EVENTS_CH[2].LIMITL), ///< Last result is equal or below CH[2].LIMIT.LOW.
NRF_SAADC_EVENT_CH3_LIMITH = offsetof(NRF_SAADC_Type, EVENTS_CH[3].LIMITH), ///< Last result is equal or above CH[3].LIMIT.HIGH.
NRF_SAADC_EVENT_CH3_LIMITL = offsetof(NRF_SAADC_Type, EVENTS_CH[3].LIMITL), ///< Last result is equal or below CH[3].LIMIT.LOW.
NRF_SAADC_EVENT_CH4_LIMITH = offsetof(NRF_SAADC_Type, EVENTS_CH[4].LIMITH), ///< Last result is equal or above CH[4].LIMIT.HIGH.
NRF_SAADC_EVENT_CH4_LIMITL = offsetof(NRF_SAADC_Type, EVENTS_CH[4].LIMITL), ///< Last result is equal or below CH[4].LIMIT.LOW.
NRF_SAADC_EVENT_CH5_LIMITH = offsetof(NRF_SAADC_Type, EVENTS_CH[5].LIMITH), ///< Last result is equal or above CH[5].LIMIT.HIGH.
NRF_SAADC_EVENT_CH5_LIMITL = offsetof(NRF_SAADC_Type, EVENTS_CH[5].LIMITL), ///< Last result is equal or below CH[5].LIMIT.LOW.
NRF_SAADC_EVENT_CH6_LIMITH = offsetof(NRF_SAADC_Type, EVENTS_CH[6].LIMITH), ///< Last result is equal or above CH[6].LIMIT.HIGH.
NRF_SAADC_EVENT_CH6_LIMITL = offsetof(NRF_SAADC_Type, EVENTS_CH[6].LIMITL), ///< Last result is equal or below CH[6].LIMIT.LOW.
NRF_SAADC_EVENT_CH7_LIMITH = offsetof(NRF_SAADC_Type, EVENTS_CH[7].LIMITH), ///< Last result is equal or above CH[7].LIMIT.HIGH.
NRF_SAADC_EVENT_CH7_LIMITL = offsetof(NRF_SAADC_Type, EVENTS_CH[7].LIMITL) ///< Last result is equal or below CH[7].LIMIT.LOW.
} nrf_saadc_event_t;
/** @brief Analog-to-digital converter interrupt masks. */
typedef enum
{
NRF_SAADC_INT_STARTED = SAADC_INTENSET_STARTED_Msk, ///< Interrupt on EVENTS_STARTED event.
NRF_SAADC_INT_END = SAADC_INTENSET_END_Msk, ///< Interrupt on EVENTS_END event.
NRF_SAADC_INT_DONE = SAADC_INTENSET_DONE_Msk, ///< Interrupt on EVENTS_DONE event.
NRF_SAADC_INT_RESULTDONE = SAADC_INTENSET_RESULTDONE_Msk, ///< Interrupt on EVENTS_RESULTDONE event.
NRF_SAADC_INT_CALIBRATEDONE = SAADC_INTENSET_CALIBRATEDONE_Msk, ///< Interrupt on EVENTS_CALIBRATEDONE event.
NRF_SAADC_INT_STOPPED = SAADC_INTENSET_STOPPED_Msk, ///< Interrupt on EVENTS_STOPPED event.
NRF_SAADC_INT_CH0LIMITH = SAADC_INTENSET_CH0LIMITH_Msk, ///< Interrupt on EVENTS_CH[0].LIMITH event.
NRF_SAADC_INT_CH0LIMITL = SAADC_INTENSET_CH0LIMITL_Msk, ///< Interrupt on EVENTS_CH[0].LIMITL event.
NRF_SAADC_INT_CH1LIMITH = SAADC_INTENSET_CH1LIMITH_Msk, ///< Interrupt on EVENTS_CH[1].LIMITH event.
NRF_SAADC_INT_CH1LIMITL = SAADC_INTENSET_CH1LIMITL_Msk, ///< Interrupt on EVENTS_CH[1].LIMITL event.
NRF_SAADC_INT_CH2LIMITH = SAADC_INTENSET_CH2LIMITH_Msk, ///< Interrupt on EVENTS_CH[2].LIMITH event.
NRF_SAADC_INT_CH2LIMITL = SAADC_INTENSET_CH2LIMITL_Msk, ///< Interrupt on EVENTS_CH[2].LIMITL event.
NRF_SAADC_INT_CH3LIMITH = SAADC_INTENSET_CH3LIMITH_Msk, ///< Interrupt on EVENTS_CH[3].LIMITH event.
NRF_SAADC_INT_CH3LIMITL = SAADC_INTENSET_CH3LIMITL_Msk, ///< Interrupt on EVENTS_CH[3].LIMITL event.
NRF_SAADC_INT_CH4LIMITH = SAADC_INTENSET_CH4LIMITH_Msk, ///< Interrupt on EVENTS_CH[4].LIMITH event.
NRF_SAADC_INT_CH4LIMITL = SAADC_INTENSET_CH4LIMITL_Msk, ///< Interrupt on EVENTS_CH[4].LIMITL event.
NRF_SAADC_INT_CH5LIMITH = SAADC_INTENSET_CH5LIMITH_Msk, ///< Interrupt on EVENTS_CH[5].LIMITH event.
NRF_SAADC_INT_CH5LIMITL = SAADC_INTENSET_CH5LIMITL_Msk, ///< Interrupt on EVENTS_CH[5].LIMITL event.
NRF_SAADC_INT_CH6LIMITH = SAADC_INTENSET_CH6LIMITH_Msk, ///< Interrupt on EVENTS_CH[6].LIMITH event.
NRF_SAADC_INT_CH6LIMITL = SAADC_INTENSET_CH6LIMITL_Msk, ///< Interrupt on EVENTS_CH[6].LIMITL event.
NRF_SAADC_INT_CH7LIMITH = SAADC_INTENSET_CH7LIMITH_Msk, ///< Interrupt on EVENTS_CH[7].LIMITH event.
NRF_SAADC_INT_CH7LIMITL = SAADC_INTENSET_CH7LIMITL_Msk, ///< Interrupt on EVENTS_CH[7].LIMITL event.
NRF_SAADC_INT_ALL = 0x7FFFFFFFUL ///< Mask of all interrupts.
} nrf_saadc_int_mask_t;
/** @brief Analog-to-digital converter value limit type. */
typedef enum
{
NRF_SAADC_LIMIT_LOW = 0, ///< Low limit type.
NRF_SAADC_LIMIT_HIGH = 1 ///< High limit type.
} nrf_saadc_limit_t;
/** @brief Type of a single ADC conversion result. */
typedef int16_t nrf_saadc_value_t;
/** @brief Analog-to-digital converter configuration structure. */
typedef struct
{
nrf_saadc_resolution_t resolution; ///< Resolution of samples.
nrf_saadc_oversample_t oversample; ///< Oversampling configuration.
nrf_saadc_value_t * buffer; ///< Pointer to sample buffer.
uint32_t buffer_size; ///< Size of the sample buffer.
} nrf_saadc_config_t;
/** @brief Analog-to-digital converter channel configuration structure. */
typedef struct
{
nrf_saadc_resistor_t resistor_p; ///< Resistor value on positive input.
nrf_saadc_resistor_t resistor_n; ///< Resistor value on negative input.
nrf_saadc_gain_t gain; ///< Gain control value.
nrf_saadc_reference_t reference; ///< Reference control value.
nrf_saadc_acqtime_t acq_time; ///< Acquisition time.
nrf_saadc_mode_t mode; ///< SAADC mode. Single-ended or differential.
nrf_saadc_burst_t burst; ///< Burst mode configuration.
nrf_saadc_input_t pin_p; ///< Input positive pin selection.
nrf_saadc_input_t pin_n; ///< Input negative pin selection.
} nrf_saadc_channel_config_t;
/**
* @brief Function for triggering the specified SAADC task.
*
* @param[in] task SAADC task.
*/
__STATIC_INLINE void nrf_saadc_task_trigger(nrf_saadc_task_t task);
/**
* @brief Function for getting the address of the specified SAADC task register.
*
* @param[in] task SAADC task.
*
* @return Address of the specified SAADC task.
*/
__STATIC_INLINE uint32_t nrf_saadc_task_address_get(nrf_saadc_task_t task);
/**
* @brief Function for retrieving the state of the UARTE event.
*
* @param[in] event Event to be checked.
*
* @retval true The event has been generated.
* @retval false The event has not been generated.
*/
__STATIC_INLINE bool nrf_saadc_event_check(nrf_saadc_event_t event);
/**
* @brief Function for clearing the specific SAADC event.
*
* @param[in] event SAADC event.
*/
__STATIC_INLINE void nrf_saadc_event_clear(nrf_saadc_event_t event);
/**
* @brief Function for getting the address of the specified SAADC event register.
*
* @param[in] event SAADC event.
*
* @return Address of the specified SAADC event.
*/
__STATIC_INLINE uint32_t nrf_saadc_event_address_get(nrf_saadc_event_t event);
#if defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting the subscribe configuration for a given
* SAADC task.
*
* @param[in] task Task for which to set the configuration.
* @param[in] channel Channel through which to subscribe events.
*/
__STATIC_INLINE void nrf_saadc_subscribe_set(nrf_saadc_task_t task,
uint8_t channel);
/**
* @brief Function for clearing the subscribe configuration for a given
* SAADC task.
*
* @param[in] task Task for which to clear the configuration.
*/
__STATIC_INLINE void nrf_saadc_subscribe_clear(nrf_saadc_task_t task);
/**
* @brief Function for setting the publish configuration for a given
* SAADC event.
*
* @param[in] event Event for which to set the configuration.
* @param[in] channel Channel through which to publish the event.
*/
__STATIC_INLINE void nrf_saadc_publish_set(nrf_saadc_event_t event,
uint8_t channel);
/**
* @brief Function for clearing the publish configuration for a given
* SAADC event.
*
* @param[in] event Event for which to clear the configuration.
*/
__STATIC_INLINE void nrf_saadc_publish_clear(nrf_saadc_event_t event);
#endif // defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for getting the address of the SAADC limit event register,
* as specified by the channel and the limit type.
*
* @param[in] channel Channel number.
* @param[in] limit_type Low limit or high limit.
*
* @return Address of the specified SAADC limit event.
*/
__STATIC_INLINE volatile uint32_t * nrf_saadc_event_limit_address_get(uint8_t channel,
nrf_saadc_limit_t limit_type);
/**
* @brief Function for getting the SAADC channel monitoring limit events.
*
* @param[in] channel Channel number.
* @param[in] limit_type Low limit or high limit.
*
* @return The SAADC channel monitoring limit event.
*/
__STATIC_INLINE nrf_saadc_event_t nrf_saadc_limit_event_get(uint8_t channel,
nrf_saadc_limit_t limit_type);
/**
* @brief Function for configuring the input pins for the specified SAADC channel.
*
* @param[in] channel Channel number.
* @param[in] pselp Positive input.
* @param[in] pseln Negative input. Set to NRF_SAADC_INPUT_DISABLED in single ended mode.
*/
__STATIC_INLINE void nrf_saadc_channel_input_set(uint8_t channel,
nrf_saadc_input_t pselp,
nrf_saadc_input_t pseln);
/**
* @brief Function for configuring the positive input pin for the specified SAADC channel.
*
* @param[in] channel Channel number.
* @param[in] pselp Positive input.
*/
__STATIC_INLINE void nrf_saadc_channel_pos_input_set(uint8_t channel,
nrf_saadc_input_t pselp);
/**
* @brief Function for setting the SAADC channel monitoring limits.
*
* @param[in] channel Channel number.
* @param[in] low Low limit.
* @param[in] high High limit.
*/
__STATIC_INLINE void nrf_saadc_channel_limits_set(uint8_t channel, int16_t low, int16_t high);
/**
* @brief Function for setting the configuration of SAADC interrupts.
*
* @param[in] mask Interrupts configuration to be set.
*/
__STATIC_INLINE void nrf_saadc_int_set(uint32_t mask);
/**
* @brief Function for enabling specified SAADC interrupts.
*
* @param[in] saadc_int_mask Interrupt(s) to be enabled.
*/
__STATIC_INLINE void nrf_saadc_int_enable(uint32_t saadc_int_mask);
/**
* @brief Function for retrieving the state of specified SAADC interrupts.
*
* @param[in] saadc_int_mask Interrupt(s) to be checked.
*
* @retval true All specified interrupts are enabled.
* @retval false At least one of the given interrupts is not enabled.
*/
__STATIC_INLINE bool nrf_saadc_int_enable_check(uint32_t saadc_int_mask);
/**
* @brief Function for disabling specified interrupts.
*
* @param saadc_int_mask Interrupt(s) to be disabled.
*/
__STATIC_INLINE void nrf_saadc_int_disable(uint32_t saadc_int_mask);
/**
* @brief Function for generating masks for SAADC channel limit interrupts.
*
* @param[in] channel SAADC channel number.
* @param[in] limit_type Limit type.
*
* @return Interrupt mask.
*/
__STATIC_INLINE uint32_t nrf_saadc_limit_int_get(uint8_t channel, nrf_saadc_limit_t limit_type);
/**
* @brief Function for checking whether the SAADC is busy.
*
* This function checks whether the analog-to-digital converter is busy with a conversion.
*
* @retval true The SAADC is busy.
* @retval false The SAADC is not busy.
*/
__STATIC_INLINE bool nrf_saadc_busy_check(void);
/**
* @brief Function for enabling the SAADC.
*
* The analog-to-digital converter must be enabled before use.
*/
__STATIC_INLINE void nrf_saadc_enable(void);
/**
* @brief Function for disabling the SAADC.
*/
__STATIC_INLINE void nrf_saadc_disable(void);
/**
* @brief Function for checking if the SAADC is enabled.
*
* @retval true The SAADC is enabled.
* @retval false The SAADC is not enabled.
*/
__STATIC_INLINE bool nrf_saadc_enable_check(void);
/**
* @brief Function for initializing the SAADC result buffer.
*
* @param[in] p_buffer Pointer to the result buffer.
* @param[in] size Size of the buffer (in 16-bit samples).
*/
__STATIC_INLINE void nrf_saadc_buffer_init(nrf_saadc_value_t * p_buffer,
uint32_t size);
/**
* @brief Function for setting the SAADC result buffer pointer.
*
* @param[in] p_buffer Pointer to the result buffer.
*/
__STATIC_INLINE void nrf_saadc_buffer_pointer_set(nrf_saadc_value_t * p_buffer);
/**
* @brief Function for getting the SAADC result buffer pointer.
*
* @return Pointer to the result buffer.
*/
__STATIC_INLINE nrf_saadc_value_t * nrf_saadc_buffer_pointer_get(void);
/**
* @brief Function for getting the number of samples written to the result
* buffer since the previous START task.
*
* @returns Number of 16-bit samples written to the buffer.
*/
__STATIC_INLINE uint16_t nrf_saadc_amount_get(void);
/**
* @brief Function for setting the SAADC sample resolution.
*
* @param[in] resolution Bit resolution.
*/
__STATIC_INLINE void nrf_saadc_resolution_set(nrf_saadc_resolution_t resolution);
/**
* @brief Function for getting the SAADC sample resolution.
*
* @return Sample resolution.
*/
__STATIC_INLINE nrf_saadc_resolution_t nrf_saadc_resolution_get(void);
/**
* @brief Function for configuring the oversampling feature.
*
* @param[in] oversample Oversampling mode.
*/
__STATIC_INLINE void nrf_saadc_oversample_set(nrf_saadc_oversample_t oversample);
/**
* @brief Function for getting the oversampling feature configuration.
*
* @return Oversampling configuration.
*/
__STATIC_INLINE nrf_saadc_oversample_t nrf_saadc_oversample_get(void);
/**
* @brief Function for getting the sample count needed for one averaged result for a given
* oversampling configuration.
*
* @param[in] oversample Oversampling configuration.
*
* @return Sample count.
*/
__STATIC_INLINE uint32_t nrf_saadc_oversample_sample_count_get(nrf_saadc_oversample_t oversample);
/**
* @brief Function for enabling the continuous sampling.
*
* This function configures the SAADC internal timer to automatically take new samples at a fixed
* sample rate. Trigger the START task to begin continuous sampling. To stop the sampling, trigger
* the STOP task.
*
* @note The internal timer can only be used when a single input channel is enabled.
*
* @param[in] cc Capture and compare value. Sample rate is 16 MHz/cc. Valid CC range is
* from 80 to 2047.
*/
__STATIC_INLINE void nrf_saadc_continuous_mode_enable(uint16_t cc);
/**
* @brief Function for checking if the continuous sampling is enabled.
*
* @retval true The continuous sampling is enabled.
* @retval false The continuous sampling is disabled.
*/
__STATIC_INLINE bool nrf_saadc_continuous_mode_enable_check(void);
/**
* @brief Function for disabling the continuous sampling.
*
* New samples can still be acquired by manually triggering the SAMPLE task or by PPI.
*/
__STATIC_INLINE void nrf_saadc_continuous_mode_disable(void);
/**
* @brief Function for initializing the SAADC channel.
*
* @param[in] channel Channel number.
* @param[in] config Pointer to the channel configuration structure.
*/
__STATIC_INLINE void nrf_saadc_channel_init(uint8_t channel,
nrf_saadc_channel_config_t const * const config);
/**
* @brief Function for configuring the burst mode for the specified channel.
*
* @param[in] channel Channel number.
* @param[in] burst Burst mode setting.
*/
__STATIC_INLINE void nrf_saadc_burst_set(uint8_t channel,
nrf_saadc_burst_t burst);
/**
* @brief Function for getting the minimum value of the conversion result.
*
* The minimum value of the conversion result depends on the configured resolution.
*
* @param[in] resolution Bit resolution.
*
* @return Minimum value of the conversion result.
*/
__STATIC_INLINE nrf_saadc_value_t nrf_saadc_value_min_get(nrf_saadc_resolution_t resolution);
/**
* @brief Function for getting the maximum value of the conversion result.
*
* The maximum value of the conversion result depends on the configured resolution.
*
* @param[in] resolution Bit resolution.
*
* @return Maximum value of the conversion result.
*/
__STATIC_INLINE nrf_saadc_value_t nrf_saadc_value_max_get(nrf_saadc_resolution_t resolution);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_saadc_task_trigger(nrf_saadc_task_t task)
{
*((volatile uint32_t *)((uint8_t *)NRF_SAADC + (uint32_t)task)) = 0x1UL;
}
__STATIC_INLINE uint32_t nrf_saadc_task_address_get(nrf_saadc_task_t task)
{
return (uint32_t)((uint8_t *)NRF_SAADC + (uint32_t)task);
}
__STATIC_INLINE bool nrf_saadc_event_check(nrf_saadc_event_t event)
{
return (bool)*(volatile uint32_t *)((uint8_t *)NRF_SAADC + (uint32_t)event);
}
__STATIC_INLINE void nrf_saadc_event_clear(nrf_saadc_event_t event)
{
*((volatile uint32_t *)((uint8_t *)NRF_SAADC + (uint32_t)event)) = 0x0UL;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)NRF_SAADC + (uint32_t)event));
(void)dummy;
#endif
}
__STATIC_INLINE uint32_t nrf_saadc_event_address_get(nrf_saadc_event_t event)
{
return (uint32_t )((uint8_t *)NRF_SAADC + (uint32_t)event);
}
#if defined(DPPI_PRESENT)
__STATIC_INLINE void nrf_saadc_subscribe_set(nrf_saadc_task_t task,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) NRF_SAADC + (uint32_t) task + 0x80uL)) =
((uint32_t)channel | SAADC_SUBSCRIBE_START_EN_Msk);
}
__STATIC_INLINE void nrf_saadc_subscribe_clear(nrf_saadc_task_t task)
{
*((volatile uint32_t *) ((uint8_t *) NRF_SAADC + (uint32_t) task + 0x80uL)) = 0;
}
__STATIC_INLINE void nrf_saadc_publish_set(nrf_saadc_event_t event,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) NRF_SAADC + (uint32_t) event + 0x80uL)) =
((uint32_t)channel | SAADC_PUBLISH_STARTED_EN_Msk);
}
__STATIC_INLINE void nrf_saadc_publish_clear(nrf_saadc_event_t event)
{
*((volatile uint32_t *) ((uint8_t *) NRF_SAADC + (uint32_t) event + 0x80uL)) = 0;
}
#endif // defined(DPPI_PRESENT)
__STATIC_INLINE volatile uint32_t * nrf_saadc_event_limit_address_get(uint8_t channel,
nrf_saadc_limit_t limit_type)
{
NRFX_ASSERT(channel < NRF_SAADC_CHANNEL_COUNT);
if (limit_type == NRF_SAADC_LIMIT_HIGH)
{
return &NRF_SAADC->EVENTS_CH[channel].LIMITH;
}
else
{
return &NRF_SAADC->EVENTS_CH[channel].LIMITL;
}
}
__STATIC_INLINE nrf_saadc_event_t nrf_saadc_limit_event_get(uint8_t channel,
nrf_saadc_limit_t limit_type)
{
if (limit_type == NRF_SAADC_LIMIT_HIGH)
{
return (nrf_saadc_event_t)( (uint32_t) NRF_SAADC_EVENT_CH0_LIMITH +
(uint32_t) (NRF_SAADC_EVENT_CH1_LIMITH - NRF_SAADC_EVENT_CH0_LIMITH)
* (uint32_t) channel );
}
else
{
return (nrf_saadc_event_t)( (uint32_t) NRF_SAADC_EVENT_CH0_LIMITL +
(uint32_t) (NRF_SAADC_EVENT_CH1_LIMITL - NRF_SAADC_EVENT_CH0_LIMITL)
* (uint32_t) channel );
}
}
__STATIC_INLINE void nrf_saadc_channel_input_set(uint8_t channel,
nrf_saadc_input_t pselp,
nrf_saadc_input_t pseln)
{
NRF_SAADC->CH[channel].PSELN = pseln;
NRF_SAADC->CH[channel].PSELP = pselp;
}
__STATIC_INLINE void nrf_saadc_channel_pos_input_set(uint8_t channel,
nrf_saadc_input_t pselp)
{
NRF_SAADC->CH[channel].PSELP = pselp;
}
__STATIC_INLINE void nrf_saadc_channel_limits_set(uint8_t channel, int16_t low, int16_t high)
{
NRF_SAADC->CH[channel].LIMIT = (
(((uint32_t) low << SAADC_CH_LIMIT_LOW_Pos) & SAADC_CH_LIMIT_LOW_Msk)
| (((uint32_t) high << SAADC_CH_LIMIT_HIGH_Pos) & SAADC_CH_LIMIT_HIGH_Msk));
}
__STATIC_INLINE void nrf_saadc_int_set(uint32_t mask)
{
NRF_SAADC->INTEN = mask;
}
__STATIC_INLINE void nrf_saadc_int_enable(uint32_t saadc_int_mask)
{
NRF_SAADC->INTENSET = saadc_int_mask;
}
__STATIC_INLINE bool nrf_saadc_int_enable_check(uint32_t saadc_int_mask)
{
return (bool)(NRF_SAADC->INTENSET & saadc_int_mask);
}
__STATIC_INLINE void nrf_saadc_int_disable(uint32_t saadc_int_mask)
{
NRF_SAADC->INTENCLR = saadc_int_mask;
}
__STATIC_INLINE uint32_t nrf_saadc_limit_int_get(uint8_t channel, nrf_saadc_limit_t limit_type)
{
NRFX_ASSERT(channel < NRF_SAADC_CHANNEL_COUNT);
uint32_t mask = (limit_type == NRF_SAADC_LIMIT_LOW) ?
NRF_SAADC_INT_CH0LIMITL : NRF_SAADC_INT_CH0LIMITH;
return mask << (channel * 2);
}
__STATIC_INLINE bool nrf_saadc_busy_check(void)
{
//return ((NRF_SAADC->STATUS & SAADC_STATUS_STATUS_Msk) == SAADC_STATUS_STATUS_Msk);
//simplified for performance
return NRF_SAADC->STATUS;
}
__STATIC_INLINE void nrf_saadc_enable(void)
{
NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos);
}
__STATIC_INLINE void nrf_saadc_disable(void)
{
NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Disabled << SAADC_ENABLE_ENABLE_Pos);
}
__STATIC_INLINE bool nrf_saadc_enable_check(void)
{
//simplified for performance
return NRF_SAADC->ENABLE;
}
__STATIC_INLINE void nrf_saadc_buffer_init(nrf_saadc_value_t * p_buffer,
uint32_t size)
{
NRF_SAADC->RESULT.PTR = (uint32_t)p_buffer;
NRF_SAADC->RESULT.MAXCNT = size;
}
__STATIC_INLINE void nrf_saadc_buffer_pointer_set(nrf_saadc_value_t * p_buffer)
{
NRF_SAADC->RESULT.PTR = (uint32_t)p_buffer;
}
__STATIC_INLINE nrf_saadc_value_t * nrf_saadc_buffer_pointer_get(void)
{
return (nrf_saadc_value_t *)NRF_SAADC->RESULT.PTR;
}
__STATIC_INLINE uint16_t nrf_saadc_amount_get(void)
{
return NRF_SAADC->RESULT.AMOUNT;
}
__STATIC_INLINE void nrf_saadc_resolution_set(nrf_saadc_resolution_t resolution)
{
NRF_SAADC->RESOLUTION = resolution;
}
__STATIC_INLINE nrf_saadc_resolution_t nrf_saadc_resolution_get(void)
{
return (nrf_saadc_resolution_t)NRF_SAADC->RESOLUTION;
}
__STATIC_INLINE uint32_t nrf_saadc_oversample_sample_count_get(nrf_saadc_oversample_t oversample)
{
return (1 << (uint32_t)oversample);
}
__STATIC_INLINE void nrf_saadc_oversample_set(nrf_saadc_oversample_t oversample)
{
NRF_SAADC->OVERSAMPLE = oversample;
}
__STATIC_INLINE nrf_saadc_oversample_t nrf_saadc_oversample_get(void)
{
return (nrf_saadc_oversample_t)NRF_SAADC->OVERSAMPLE;
}
__STATIC_INLINE void nrf_saadc_continuous_mode_enable(uint16_t cc)
{
NRFX_ASSERT((cc >= 80) && (cc <= 2047));
NRF_SAADC->SAMPLERATE = (SAADC_SAMPLERATE_MODE_Timers << SAADC_SAMPLERATE_MODE_Pos)
| ((uint32_t)cc << SAADC_SAMPLERATE_CC_Pos);
}
__STATIC_INLINE bool nrf_saadc_continuous_mode_enable_check(void)
{
return (bool)((NRF_SAADC->SAMPLERATE & SAADC_SAMPLERATE_MODE_Msk)
== (SAADC_SAMPLERATE_MODE_Timers << SAADC_SAMPLERATE_MODE_Pos));
}
__STATIC_INLINE void nrf_saadc_continuous_mode_disable(void)
{
NRF_SAADC->SAMPLERATE = SAADC_SAMPLERATE_MODE_Task << SAADC_SAMPLERATE_MODE_Pos;
}
__STATIC_INLINE void nrf_saadc_channel_init(uint8_t channel,
nrf_saadc_channel_config_t const * const config)
{
NRF_SAADC->CH[channel].CONFIG =
((config->resistor_p << SAADC_CH_CONFIG_RESP_Pos) & SAADC_CH_CONFIG_RESP_Msk)
| ((config->resistor_n << SAADC_CH_CONFIG_RESN_Pos) & SAADC_CH_CONFIG_RESN_Msk)
| ((config->gain << SAADC_CH_CONFIG_GAIN_Pos) & SAADC_CH_CONFIG_GAIN_Msk)
| ((config->reference << SAADC_CH_CONFIG_REFSEL_Pos) & SAADC_CH_CONFIG_REFSEL_Msk)
| ((config->acq_time << SAADC_CH_CONFIG_TACQ_Pos) & SAADC_CH_CONFIG_TACQ_Msk)
| ((config->mode << SAADC_CH_CONFIG_MODE_Pos) & SAADC_CH_CONFIG_MODE_Msk)
| ((config->burst << SAADC_CH_CONFIG_BURST_Pos) & SAADC_CH_CONFIG_BURST_Msk);
nrf_saadc_channel_input_set(channel, config->pin_p, config->pin_n);
}
__STATIC_INLINE void nrf_saadc_burst_set(uint8_t channel,
nrf_saadc_burst_t burst)
{
NRF_SAADC->CH[channel].CONFIG =
(NRF_SAADC->CH[channel].CONFIG & ~SAADC_CH_CONFIG_BURST_Msk) |
(burst << SAADC_CH_CONFIG_BURST_Pos);
}
__STATIC_INLINE nrf_saadc_value_t nrf_saadc_value_min_get(nrf_saadc_resolution_t resolution)
{
uint8_t res_bits = 0;
switch (resolution)
{
case NRF_SAADC_RESOLUTION_8BIT:
res_bits = 8;
break;
case NRF_SAADC_RESOLUTION_10BIT:
res_bits = 10;
break;
case NRF_SAADC_RESOLUTION_12BIT:
res_bits = 12;
break;
case NRF_SAADC_RESOLUTION_14BIT:
res_bits = 14;
break;
default:
NRFX_ASSERT(false);
}
return (nrf_saadc_value_t)(-(1 << res_bits));
}
__STATIC_INLINE nrf_saadc_value_t nrf_saadc_value_max_get(nrf_saadc_resolution_t resolution)
{
uint8_t res_bits = 0;
switch (resolution)
{
case NRF_SAADC_RESOLUTION_8BIT:
res_bits = 8;
break;
case NRF_SAADC_RESOLUTION_10BIT:
res_bits = 10;
break;
case NRF_SAADC_RESOLUTION_12BIT:
res_bits = 12;
break;
case NRF_SAADC_RESOLUTION_14BIT:
res_bits = 14;
break;
default:
NRFX_ASSERT(false);
}
return (nrf_saadc_value_t)((1 << res_bits) - 1);
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_SAADC_H_
+371
View File
@@ -0,0 +1,371 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_SPI_H__
#define NRF_SPI_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_spi_hal SPI HAL
* @{
* @ingroup nrf_spi
* @brief Hardware access layer for managing the SPI peripheral.
*/
/**
* @brief This value can be used as a parameter for the @ref nrf_spi_pins_set
* function to specify that a given SPI signal (SCK, MOSI, or MISO)
* shall not be connected to a physical pin.
*/
#define NRF_SPI_PIN_NOT_CONNECTED 0xFFFFFFFF
/** @brief SPI events. */
typedef enum
{
NRF_SPI_EVENT_READY = offsetof(NRF_SPI_Type, EVENTS_READY) ///< TXD byte sent and RXD byte received.
} nrf_spi_event_t;
/** @brief SPI interrupts. */
typedef enum
{
NRF_SPI_INT_READY_MASK = SPI_INTENSET_READY_Msk, ///< Interrupt on READY event.
NRF_SPI_ALL_INTS_MASK = SPI_INTENSET_READY_Msk ///< All SPI interrupts.
} nrf_spi_int_mask_t;
/** @brief SPI data rates. */
typedef enum
{
NRF_SPI_FREQ_125K = SPI_FREQUENCY_FREQUENCY_K125, ///< 125 kbps.
NRF_SPI_FREQ_250K = SPI_FREQUENCY_FREQUENCY_K250, ///< 250 kbps.
NRF_SPI_FREQ_500K = SPI_FREQUENCY_FREQUENCY_K500, ///< 500 kbps.
NRF_SPI_FREQ_1M = SPI_FREQUENCY_FREQUENCY_M1, ///< 1 Mbps.
NRF_SPI_FREQ_2M = SPI_FREQUENCY_FREQUENCY_M2, ///< 2 Mbps.
NRF_SPI_FREQ_4M = SPI_FREQUENCY_FREQUENCY_M4, ///< 4 Mbps.
// [conversion to 'int' needed to prevent compilers from complaining
// that the provided value (0x80000000UL) is out of range of "int"]
NRF_SPI_FREQ_8M = (int)SPI_FREQUENCY_FREQUENCY_M8 ///< 8 Mbps.
} nrf_spi_frequency_t;
/** @brief SPI modes. */
typedef enum
{
NRF_SPI_MODE_0, ///< SCK active high, sample on leading edge of clock.
NRF_SPI_MODE_1, ///< SCK active high, sample on trailing edge of clock.
NRF_SPI_MODE_2, ///< SCK active low, sample on leading edge of clock.
NRF_SPI_MODE_3 ///< SCK active low, sample on trailing edge of clock.
} nrf_spi_mode_t;
/** @brief SPI bit orders. */
typedef enum
{
NRF_SPI_BIT_ORDER_MSB_FIRST = SPI_CONFIG_ORDER_MsbFirst, ///< Most significant bit shifted out first.
NRF_SPI_BIT_ORDER_LSB_FIRST = SPI_CONFIG_ORDER_LsbFirst ///< Least significant bit shifted out first.
} nrf_spi_bit_order_t;
/**
* @brief Function for clearing the specified SPI event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be cleared.
*/
__STATIC_INLINE void nrf_spi_event_clear(NRF_SPI_Type * p_reg,
nrf_spi_event_t event);
/**
* @brief Function for retrieving the state of the SPI event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be checked.
*
* @retval true The event has been generated.
* @retval false The event has not been generated.
*/
__STATIC_INLINE bool nrf_spi_event_check(NRF_SPI_Type * p_reg,
nrf_spi_event_t event);
/**
* @brief Function for getting the address of the specified SPI event register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event The specified event.
*
* @return Address of the specified event register.
*/
__STATIC_INLINE uint32_t * nrf_spi_event_address_get(NRF_SPI_Type * p_reg,
nrf_spi_event_t event);
/**
* @brief Function for enabling the specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of interrupts to be enabled.
*/
__STATIC_INLINE void nrf_spi_int_enable(NRF_SPI_Type * p_reg,
uint32_t mask);
/**
* @brief Function for disabling the specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of interrupts to be disabled.
*/
__STATIC_INLINE void nrf_spi_int_disable(NRF_SPI_Type * p_reg,
uint32_t mask);
/**
* @brief Function for retrieving the state of a given interrupt.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] spi_int Interrupt to be checked.
*
* @retval true The interrupt is enabled.
* @retval false The interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_spi_int_enable_check(NRF_SPI_Type * p_reg,
nrf_spi_int_mask_t spi_int);
/**
* @brief Function for enabling the SPI peripheral.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_spi_enable(NRF_SPI_Type * p_reg);
/**
* @brief Function for disabling the SPI peripheral.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_spi_disable(NRF_SPI_Type * p_reg);
/**
* @brief Function for configuring SPI pins.
*
* If a given signal is not needed, pass the @ref NRF_SPI_PIN_NOT_CONNECTED
* value instead of its pin number.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] sck_pin SCK pin number.
* @param[in] mosi_pin MOSI pin number.
* @param[in] miso_pin MISO pin number.
*/
__STATIC_INLINE void nrf_spi_pins_set(NRF_SPI_Type * p_reg,
uint32_t sck_pin,
uint32_t mosi_pin,
uint32_t miso_pin);
/**
* @brief Function for writing data to the SPI transmitter register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] data TX data to send.
*/
__STATIC_INLINE void nrf_spi_txd_set(NRF_SPI_Type * p_reg, uint8_t data);
/**
* @brief Function for reading data from the SPI receiver register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return RX data received.
*/
__STATIC_INLINE uint8_t nrf_spi_rxd_get(NRF_SPI_Type * p_reg);
/**
* @brief Function for setting the SPI master data rate.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] frequency SPI frequency.
*/
__STATIC_INLINE void nrf_spi_frequency_set(NRF_SPI_Type * p_reg,
nrf_spi_frequency_t frequency);
/**
* @brief Function for setting the SPI configuration.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] spi_mode SPI mode.
* @param[in] spi_bit_order SPI bit order.
*/
__STATIC_INLINE void nrf_spi_configure(NRF_SPI_Type * p_reg,
nrf_spi_mode_t spi_mode,
nrf_spi_bit_order_t spi_bit_order);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_spi_event_clear(NRF_SPI_Type * p_reg,
nrf_spi_event_t event)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0x0UL;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event));
(void)dummy;
#endif
}
__STATIC_INLINE bool nrf_spi_event_check(NRF_SPI_Type * p_reg,
nrf_spi_event_t event)
{
return (bool)*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE uint32_t * nrf_spi_event_address_get(NRF_SPI_Type * p_reg,
nrf_spi_event_t event)
{
return (uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE void nrf_spi_int_enable(NRF_SPI_Type * p_reg,
uint32_t mask)
{
p_reg->INTENSET = mask;
}
__STATIC_INLINE void nrf_spi_int_disable(NRF_SPI_Type * p_reg,
uint32_t mask)
{
p_reg->INTENCLR = mask;
}
__STATIC_INLINE bool nrf_spi_int_enable_check(NRF_SPI_Type * p_reg,
nrf_spi_int_mask_t spi_int)
{
return (bool)(p_reg->INTENSET & spi_int);
}
__STATIC_INLINE void nrf_spi_enable(NRF_SPI_Type * p_reg)
{
p_reg->ENABLE = (SPI_ENABLE_ENABLE_Enabled << SPI_ENABLE_ENABLE_Pos);
}
__STATIC_INLINE void nrf_spi_disable(NRF_SPI_Type * p_reg)
{
p_reg->ENABLE = (SPI_ENABLE_ENABLE_Disabled << SPI_ENABLE_ENABLE_Pos);
}
__STATIC_INLINE void nrf_spi_pins_set(NRF_SPI_Type * p_reg,
uint32_t sck_pin,
uint32_t mosi_pin,
uint32_t miso_pin)
{
#if defined(SPI_PSEL_SCK_CONNECT_Pos)
p_reg->PSEL.SCK = sck_pin;
#else
p_reg->PSELSCK = sck_pin;
#endif
#if defined(SPI_PSEL_MOSI_CONNECT_Pos)
p_reg->PSEL.MOSI = mosi_pin;
#else
p_reg->PSELMOSI = mosi_pin;
#endif
#if defined(SPI_PSEL_MISO_CONNECT_Pos)
p_reg->PSEL.MISO = miso_pin;
#else
p_reg->PSELMISO = miso_pin;
#endif
}
__STATIC_INLINE void nrf_spi_txd_set(NRF_SPI_Type * p_reg, uint8_t data)
{
p_reg->TXD = data;
}
__STATIC_INLINE uint8_t nrf_spi_rxd_get(NRF_SPI_Type * p_reg)
{
return p_reg->RXD;
}
__STATIC_INLINE void nrf_spi_frequency_set(NRF_SPI_Type * p_reg,
nrf_spi_frequency_t frequency)
{
p_reg->FREQUENCY = frequency;
}
__STATIC_INLINE void nrf_spi_configure(NRF_SPI_Type * p_reg,
nrf_spi_mode_t spi_mode,
nrf_spi_bit_order_t spi_bit_order)
{
uint32_t config = (spi_bit_order == NRF_SPI_BIT_ORDER_MSB_FIRST ?
SPI_CONFIG_ORDER_MsbFirst : SPI_CONFIG_ORDER_LsbFirst);
switch (spi_mode)
{
default:
case NRF_SPI_MODE_0:
config |= (SPI_CONFIG_CPOL_ActiveHigh << SPI_CONFIG_CPOL_Pos) |
(SPI_CONFIG_CPHA_Leading << SPI_CONFIG_CPHA_Pos);
break;
case NRF_SPI_MODE_1:
config |= (SPI_CONFIG_CPOL_ActiveHigh << SPI_CONFIG_CPOL_Pos) |
(SPI_CONFIG_CPHA_Trailing << SPI_CONFIG_CPHA_Pos);
break;
case NRF_SPI_MODE_2:
config |= (SPI_CONFIG_CPOL_ActiveLow << SPI_CONFIG_CPOL_Pos) |
(SPI_CONFIG_CPHA_Leading << SPI_CONFIG_CPHA_Pos);
break;
case NRF_SPI_MODE_3:
config |= (SPI_CONFIG_CPOL_ActiveLow << SPI_CONFIG_CPOL_Pos) |
(SPI_CONFIG_CPHA_Trailing << SPI_CONFIG_CPHA_Pos);
break;
}
p_reg->CONFIG = config;
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_SPI_H__
+801
View File
@@ -0,0 +1,801 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_SPIM_H__
#define NRF_SPIM_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_spim_hal SPIM HAL
* @{
* @ingroup nrf_spim
* @brief Hardware access layer for managing the SPIM peripheral.
*/
/**
* @brief This value can be used as a parameter for the @ref nrf_spim_pins_set
* function to specify that a given SPI signal (SCK, MOSI, or MISO)
* shall not be connected to a physical pin.
*/
#define NRF_SPIM_PIN_NOT_CONNECTED 0xFFFFFFFF
#if defined(SPIM_DCXCNT_DCXCNT_Msk) || defined(__NRFX_DOXYGEN__)
/**
* @brief This value specified in the DCX line configuration causes this line
* to be set low during whole transmission (all transmitted bytes are
* marked as command bytes). Any lower value causes the DCX line to be
* switched from low to high after this number of bytes is transmitted
* (all remaining bytes are marked as data bytes).
*/
#define NRF_SPIM_DCX_CNT_ALL_CMD 0xF
#endif
/** @brief Macro for checking if the hardware chip select function is available. */
#define NRF_SPIM_HW_CSN_PRESENT \
(NRFX_CHECK(SPIM0_FEATURE_HARDWARE_CSN_PRESENT) || \
NRFX_CHECK(SPIM1_FEATURE_HARDWARE_CSN_PRESENT) || \
NRFX_CHECK(SPIM2_FEATURE_HARDWARE_CSN_PRESENT) || \
NRFX_CHECK(SPIM3_FEATURE_HARDWARE_CSN_PRESENT))
/** @brief SPIM tasks. */
typedef enum
{
NRF_SPIM_TASK_START = offsetof(NRF_SPIM_Type, TASKS_START), ///< Start SPI transaction.
NRF_SPIM_TASK_STOP = offsetof(NRF_SPIM_Type, TASKS_STOP), ///< Stop SPI transaction.
NRF_SPIM_TASK_SUSPEND = offsetof(NRF_SPIM_Type, TASKS_SUSPEND), ///< Suspend SPI transaction.
NRF_SPIM_TASK_RESUME = offsetof(NRF_SPIM_Type, TASKS_RESUME) ///< Resume SPI transaction.
} nrf_spim_task_t;
/** @brief SPIM events. */
typedef enum
{
NRF_SPIM_EVENT_STOPPED = offsetof(NRF_SPIM_Type, EVENTS_STOPPED), ///< SPI transaction has stopped.
NRF_SPIM_EVENT_ENDRX = offsetof(NRF_SPIM_Type, EVENTS_ENDRX), ///< End of RXD buffer reached.
NRF_SPIM_EVENT_END = offsetof(NRF_SPIM_Type, EVENTS_END), ///< End of RXD buffer and TXD buffer reached.
NRF_SPIM_EVENT_ENDTX = offsetof(NRF_SPIM_Type, EVENTS_ENDTX), ///< End of TXD buffer reached.
NRF_SPIM_EVENT_STARTED = offsetof(NRF_SPIM_Type, EVENTS_STARTED) ///< Transaction started.
} nrf_spim_event_t;
/**
* @brief SPIM shortcuts.
*/
typedef enum
{
NRF_SPIM_SHORT_END_START_MASK = SPIM_SHORTS_END_START_Msk, ///< Shortcut between END event and START task.
NRF_SPIM_ALL_SHORTS_MASK = SPIM_SHORTS_END_START_Msk ///< All SPIM shortcuts.
} nrf_spim_short_mask_t;
/** @brief SPIM interrupts. */
typedef enum
{
NRF_SPIM_INT_STOPPED_MASK = SPIM_INTENSET_STOPPED_Msk, ///< Interrupt on STOPPED event.
NRF_SPIM_INT_ENDRX_MASK = SPIM_INTENSET_ENDRX_Msk, ///< Interrupt on ENDRX event.
NRF_SPIM_INT_END_MASK = SPIM_INTENSET_END_Msk, ///< Interrupt on END event.
NRF_SPIM_INT_ENDTX_MASK = SPIM_INTENSET_ENDTX_Msk, ///< Interrupt on ENDTX event.
NRF_SPIM_INT_STARTED_MASK = SPIM_INTENSET_STARTED_Msk, ///< Interrupt on STARTED event.
NRF_SPIM_ALL_INTS_MASK = SPIM_INTENSET_STOPPED_Msk |
SPIM_INTENSET_ENDRX_Msk |
SPIM_INTENSET_END_Msk |
SPIM_INTENSET_ENDTX_Msk |
SPIM_INTENSET_STARTED_Msk ///< All SPIM interrupts.
} nrf_spim_int_mask_t;
/** @brief SPI master data rates. */
typedef enum
{
NRF_SPIM_FREQ_125K = SPIM_FREQUENCY_FREQUENCY_K125, ///< 125 kbps.
NRF_SPIM_FREQ_250K = SPIM_FREQUENCY_FREQUENCY_K250, ///< 250 kbps.
NRF_SPIM_FREQ_500K = SPIM_FREQUENCY_FREQUENCY_K500, ///< 500 kbps.
NRF_SPIM_FREQ_1M = SPIM_FREQUENCY_FREQUENCY_M1, ///< 1 Mbps.
NRF_SPIM_FREQ_2M = SPIM_FREQUENCY_FREQUENCY_M2, ///< 2 Mbps.
NRF_SPIM_FREQ_4M = SPIM_FREQUENCY_FREQUENCY_M4, ///< 4 Mbps.
// [conversion to 'int' needed to prevent compilers from complaining
// that the provided value (0x80000000UL) is out of range of "int"]
NRF_SPIM_FREQ_8M = (int)SPIM_FREQUENCY_FREQUENCY_M8, ///< 8 Mbps.
#if defined(SPIM_FREQUENCY_FREQUENCY_M16) || defined(__NRFX_DOXYGEN__)
NRF_SPIM_FREQ_16M = SPIM_FREQUENCY_FREQUENCY_M16, ///< 16 Mbps.
#endif
#if defined(SPIM_FREQUENCY_FREQUENCY_M32) || defined(__NRFX_DOXYGEN__)
NRF_SPIM_FREQ_32M = SPIM_FREQUENCY_FREQUENCY_M32 ///< 32 Mbps.
#endif
} nrf_spim_frequency_t;
/** @brief SPI modes. */
typedef enum
{
NRF_SPIM_MODE_0, ///< SCK active high, sample on leading edge of clock.
NRF_SPIM_MODE_1, ///< SCK active high, sample on trailing edge of clock.
NRF_SPIM_MODE_2, ///< SCK active low, sample on leading edge of clock.
NRF_SPIM_MODE_3 ///< SCK active low, sample on trailing edge of clock.
} nrf_spim_mode_t;
/** @brief SPI bit orders. */
typedef enum
{
NRF_SPIM_BIT_ORDER_MSB_FIRST = SPIM_CONFIG_ORDER_MsbFirst, ///< Most significant bit shifted out first.
NRF_SPIM_BIT_ORDER_LSB_FIRST = SPIM_CONFIG_ORDER_LsbFirst ///< Least significant bit shifted out first.
} nrf_spim_bit_order_t;
#if (NRF_SPIM_HW_CSN_PRESENT) || defined(__NRFX_DOXYGEN__)
/** @brief SPI CSN pin polarity. */
typedef enum
{
NRF_SPIM_CSN_POL_LOW = SPIM_CSNPOL_CSNPOL_LOW, ///< Active low (idle state high).
NRF_SPIM_CSN_POL_HIGH = SPIM_CSNPOL_CSNPOL_HIGH ///< Active high (idle state low).
} nrf_spim_csn_pol_t;
#endif // (NRF_SPIM_HW_CSN_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for activating the specified SPIM task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task to be activated.
*/
__STATIC_INLINE void nrf_spim_task_trigger(NRF_SPIM_Type * p_reg,
nrf_spim_task_t task);
/**
* @brief Function for getting the address of the specified SPIM task register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task The specified task.
*
* @return Address of the specified task register.
*/
__STATIC_INLINE uint32_t nrf_spim_task_address_get(NRF_SPIM_Type * p_reg,
nrf_spim_task_t task);
/**
* @brief Function for clearing the specified SPIM event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be cleared.
*/
__STATIC_INLINE void nrf_spim_event_clear(NRF_SPIM_Type * p_reg,
nrf_spim_event_t event);
/**
* @brief Function for retrieving the state of the SPIM event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be checked.
*
* @retval true The event has been generated.
* @retval false The event has not been generated.
*/
__STATIC_INLINE bool nrf_spim_event_check(NRF_SPIM_Type * p_reg,
nrf_spim_event_t event);
/**
* @brief Function for getting the address of the specified SPIM event register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event The specified event.
*
* @return Address of the specified event register.
*/
__STATIC_INLINE uint32_t nrf_spim_event_address_get(NRF_SPIM_Type * p_reg,
nrf_spim_event_t event);
/**
* @brief Function for enabling the specified shortcuts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Shortcuts to be enabled.
*/
__STATIC_INLINE void nrf_spim_shorts_enable(NRF_SPIM_Type * p_reg,
uint32_t mask);
/**
* @brief Function for disabling the specified shortcuts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Shortcuts to be disabled.
*/
__STATIC_INLINE void nrf_spim_shorts_disable(NRF_SPIM_Type * p_reg,
uint32_t mask);
/**
* @brief Function for getting the shortcut setting.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Current shortcut configuration.
*/
__STATIC_INLINE uint32_t nrf_spim_shorts_get(NRF_SPIM_Type * p_reg);
/**
* @brief Function for enabling the specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of interrupts to be enabled.
*/
__STATIC_INLINE void nrf_spim_int_enable(NRF_SPIM_Type * p_reg,
uint32_t mask);
/**
* @brief Function for disabling the specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of interrupts to be disabled.
*/
__STATIC_INLINE void nrf_spim_int_disable(NRF_SPIM_Type * p_reg,
uint32_t mask);
/**
* @brief Function for retrieving the state of a given interrupt.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] spim_int Interrupt to be checked.
*
* @retval true The interrupt is enabled.
* @retval false The interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_spim_int_enable_check(NRF_SPIM_Type * p_reg,
nrf_spim_int_mask_t spim_int);
#if defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting the subscribe configuration for a given
* SPIM task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task for which to set the configuration.
* @param[in] channel Channel through which to subscribe events.
*/
__STATIC_INLINE void nrf_spim_subscribe_set(NRF_SPIM_Type * p_reg,
nrf_spim_task_t task,
uint8_t channel);
/**
* @brief Function for clearing the subscribe configuration for a given
* SPIM task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task for which to clear the configuration.
*/
__STATIC_INLINE void nrf_spim_subscribe_clear(NRF_SPIM_Type * p_reg,
nrf_spim_task_t task);
/**
* @brief Function for setting the publish configuration for a given
* SPIM event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event for which to set the configuration.
* @param[in] channel Channel through which to publish the event.
*/
__STATIC_INLINE void nrf_spim_publish_set(NRF_SPIM_Type * p_reg,
nrf_spim_event_t event,
uint8_t channel);
/**
* @brief Function for clearing the publish configuration for a given
* SPIM event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event for which to clear the configuration.
*/
__STATIC_INLINE void nrf_spim_publish_clear(NRF_SPIM_Type * p_reg,
nrf_spim_event_t event);
#endif // defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for enabling the SPIM peripheral.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_spim_enable(NRF_SPIM_Type * p_reg);
/**
* @brief Function for disabling the SPIM peripheral.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_spim_disable(NRF_SPIM_Type * p_reg);
/**
* @brief Function for configuring SPIM pins.
*
* If a given signal is not needed, pass the @ref NRF_SPIM_PIN_NOT_CONNECTED
* value instead of its pin number.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] sck_pin SCK pin number.
* @param[in] mosi_pin MOSI pin number.
* @param[in] miso_pin MISO pin number.
*/
__STATIC_INLINE void nrf_spim_pins_set(NRF_SPIM_Type * p_reg,
uint32_t sck_pin,
uint32_t mosi_pin,
uint32_t miso_pin);
#if (NRF_SPIM_HW_CSN_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for configuring the SPIM hardware CSN pin.
*
* If this signal is not needed, pass the @ref NRF_SPIM_PIN_NOT_CONNECTED
* value instead of its pin number.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] pin CSN pin number.
* @param[in] polarity CSN pin polarity.
* @param[in] duration Minimum duration between the edge of CSN and the edge of SCK
* and minimum duration of CSN must stay unselected between transactions.
* The value is specified in number of 64 MHz clock cycles (15.625 ns).
*/
__STATIC_INLINE void nrf_spim_csn_configure(NRF_SPIM_Type * p_reg,
uint32_t pin,
nrf_spim_csn_pol_t polarity,
uint32_t duration);
#endif // (NRF_SPIM_HW_CSN_PRESENT) || defined(__NRFX_DOXYGEN__)
#if defined(SPIM_PSELDCX_CONNECT_Msk) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for configuring the SPIM DCX pin.
*
* If this signal is not needed, pass the @ref NRF_SPIM_PIN_NOT_CONNECTED
* value instead of its pin number.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] dcx_pin DCX pin number.
*/
__STATIC_INLINE void nrf_spim_dcx_pin_set(NRF_SPIM_Type * p_reg,
uint32_t dcx_pin);
/**
* @brief Function for configuring the number of command bytes.
*
* Maximum value available for dividing the transmitted bytes into command
* bytes and data bytes is @ref NRF_SPIM_DCX_CNT_ALL_CMD - 1.
* The @ref NRF_SPIM_DCX_CNT_ALL_CMD value passed as the @c count parameter
* causes all transmitted bytes to be marked as command bytes.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] count Number of command bytes preceding the data bytes.
*/
__STATIC_INLINE void nrf_spim_dcx_cnt_set(NRF_SPIM_Type * p_reg,
uint32_t count);
#endif // defined(SPIM_PSELDCX_CONNECT_Msk) || defined(__NRFX_DOXYGEN__)
#if defined(SPIM_IFTIMING_RXDELAY_RXDELAY_Msk) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for configuring the extended SPIM interface.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param rxdelay Sample delay for input serial data on MISO,
* specified in 64 MHz clock cycles (15.625 ns) from the sampling edge of SCK.
*/
__STATIC_INLINE void nrf_spim_iftiming_set(NRF_SPIM_Type * p_reg,
uint32_t rxdelay);
#endif // defined(SPIM_IFTIMING_RXDELAY_RXDELAY_Msk) || defined(__NRFX_DOXYGEN__)
#if defined(SPIM_STALLSTAT_RX_Msk) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for clearing stall status for RX EasyDMA RAM accesses.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_spim_stallstat_rx_clear(NRF_SPIM_Type * p_reg);
/**
* @brief Function for getting stall status for RX EasyDMA RAM accesses.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return Stall status of RX EasyDMA RAM accesses.
*/
__STATIC_INLINE bool nrf_spim_stallstat_rx_get(NRF_SPIM_Type * p_reg);
#endif // defined(SPIM_STALLSTAT_RX_Msk) || defined(__NRFX_DOXYGEN__)
#if defined(SPIM_STALLSTAT_TX_Msk) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for clearing stall status for TX EasyDMA RAM accesses.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_spim_stallstat_tx_clear(NRF_SPIM_Type * p_reg);
/**
* @brief Function for getting stall status for TX EasyDMA RAM accesses.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return Stall status of TX EasyDMA RAM accesses.
*/
__STATIC_INLINE bool nrf_spim_stallstat_tx_get(NRF_SPIM_Type * p_reg);
#endif // defined(SPIM_STALLSTAT_TX_Msk) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting the SPI master data rate.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] frequency SPI frequency.
*/
__STATIC_INLINE void nrf_spim_frequency_set(NRF_SPIM_Type * p_reg,
nrf_spim_frequency_t frequency);
/**
* @brief Function for setting the transmit buffer.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] p_buffer Pointer to the buffer with data to send.
* @param[in] length Maximum number of data bytes to transmit.
*/
__STATIC_INLINE void nrf_spim_tx_buffer_set(NRF_SPIM_Type * p_reg,
uint8_t const * p_buffer,
size_t length);
/**
* @brief Function for setting the receive buffer.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] p_buffer Pointer to the buffer for received data.
* @param[in] length Maximum number of data bytes to receive.
*/
__STATIC_INLINE void nrf_spim_rx_buffer_set(NRF_SPIM_Type * p_reg,
uint8_t * p_buffer,
size_t length);
/**
* @brief Function for setting the SPI configuration.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] spi_mode SPI mode.
* @param[in] spi_bit_order SPI bit order.
*/
__STATIC_INLINE void nrf_spim_configure(NRF_SPIM_Type * p_reg,
nrf_spim_mode_t spi_mode,
nrf_spim_bit_order_t spi_bit_order);
/**
* @brief Function for setting the over-read character.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] orc Over-read character that is clocked out in case of
* an over-read of the TXD buffer.
*/
__STATIC_INLINE void nrf_spim_orc_set(NRF_SPIM_Type * p_reg,
uint8_t orc);
/**
* @brief Function for enabling the TX list feature.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_spim_tx_list_enable(NRF_SPIM_Type * p_reg);
/**
* @brief Function for disabling the TX list feature.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_spim_tx_list_disable(NRF_SPIM_Type * p_reg);
/**
* @brief Function for enabling the RX list feature.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_spim_rx_list_enable(NRF_SPIM_Type * p_reg);
/**
* @brief Function for disabling the RX list feature.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_spim_rx_list_disable(NRF_SPIM_Type * p_reg);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_spim_task_trigger(NRF_SPIM_Type * p_reg,
nrf_spim_task_t task)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)task)) = 0x1UL;
}
__STATIC_INLINE uint32_t nrf_spim_task_address_get(NRF_SPIM_Type * p_reg,
nrf_spim_task_t task)
{
return (uint32_t)((uint8_t *)p_reg + (uint32_t)task);
}
__STATIC_INLINE void nrf_spim_event_clear(NRF_SPIM_Type * p_reg,
nrf_spim_event_t event)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0x0UL;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event));
(void)dummy;
#endif
}
__STATIC_INLINE bool nrf_spim_event_check(NRF_SPIM_Type * p_reg,
nrf_spim_event_t event)
{
return (bool)*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE uint32_t nrf_spim_event_address_get(NRF_SPIM_Type * p_reg,
nrf_spim_event_t event)
{
return (uint32_t)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE void nrf_spim_shorts_enable(NRF_SPIM_Type * p_reg,
uint32_t mask)
{
p_reg->SHORTS |= mask;
}
__STATIC_INLINE void nrf_spim_shorts_disable(NRF_SPIM_Type * p_reg,
uint32_t mask)
{
p_reg->SHORTS &= ~(mask);
}
__STATIC_INLINE uint32_t nrf_spim_shorts_get(NRF_SPIM_Type * p_reg)
{
return p_reg->SHORTS;
}
__STATIC_INLINE void nrf_spim_int_enable(NRF_SPIM_Type * p_reg,
uint32_t mask)
{
p_reg->INTENSET = mask;
}
__STATIC_INLINE void nrf_spim_int_disable(NRF_SPIM_Type * p_reg,
uint32_t mask)
{
p_reg->INTENCLR = mask;
}
__STATIC_INLINE bool nrf_spim_int_enable_check(NRF_SPIM_Type * p_reg,
nrf_spim_int_mask_t spim_int)
{
return (bool)(p_reg->INTENSET & spim_int);
}
#if defined(DPPI_PRESENT)
__STATIC_INLINE void nrf_spim_subscribe_set(NRF_SPIM_Type * p_reg,
nrf_spim_task_t task,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) task + 0x80uL)) =
((uint32_t)channel | SPIM_SUBSCRIBE_START_EN_Msk);
}
__STATIC_INLINE void nrf_spim_subscribe_clear(NRF_SPIM_Type * p_reg,
nrf_spim_task_t task)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) task + 0x80uL)) = 0;
}
__STATIC_INLINE void nrf_spim_publish_set(NRF_SPIM_Type * p_reg,
nrf_spim_event_t event,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) event + 0x80uL)) =
((uint32_t)channel | SPIM_PUBLISH_STARTED_EN_Msk);
}
__STATIC_INLINE void nrf_spim_publish_clear(NRF_SPIM_Type * p_reg,
nrf_spim_event_t event)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) event + 0x80uL)) = 0;
}
#endif // defined(DPPI_PRESENT)
__STATIC_INLINE void nrf_spim_enable(NRF_SPIM_Type * p_reg)
{
p_reg->ENABLE = (SPIM_ENABLE_ENABLE_Enabled << SPIM_ENABLE_ENABLE_Pos);
}
__STATIC_INLINE void nrf_spim_disable(NRF_SPIM_Type * p_reg)
{
p_reg->ENABLE = (SPIM_ENABLE_ENABLE_Disabled << SPIM_ENABLE_ENABLE_Pos);
}
__STATIC_INLINE void nrf_spim_pins_set(NRF_SPIM_Type * p_reg,
uint32_t sck_pin,
uint32_t mosi_pin,
uint32_t miso_pin)
{
p_reg->PSEL.SCK = sck_pin;
p_reg->PSEL.MOSI = mosi_pin;
p_reg->PSEL.MISO = miso_pin;
}
#if (NRF_SPIM_HW_CSN_PRESENT)
__STATIC_INLINE void nrf_spim_csn_configure(NRF_SPIM_Type * p_reg,
uint32_t pin,
nrf_spim_csn_pol_t polarity,
uint32_t duration)
{
p_reg->PSEL.CSN = pin;
p_reg->CSNPOL = polarity;
p_reg->IFTIMING.CSNDUR = duration;
}
#endif // defined(NRF_SPIM_HW_CSN_PRESENT)
#if defined(SPIM_PSELDCX_CONNECT_Msk)
__STATIC_INLINE void nrf_spim_dcx_pin_set(NRF_SPIM_Type * p_reg,
uint32_t dcx_pin)
{
p_reg->PSELDCX = dcx_pin;
}
__STATIC_INLINE void nrf_spim_dcx_cnt_set(NRF_SPIM_Type * p_reg,
uint32_t dcx_cnt)
{
p_reg->DCXCNT = dcx_cnt;
}
#endif // defined(SPIM_PSELDCX_CONNECT_Msk)
#if defined(SPIM_IFTIMING_RXDELAY_RXDELAY_Msk)
__STATIC_INLINE void nrf_spim_iftiming_set(NRF_SPIM_Type * p_reg,
uint32_t rxdelay)
{
p_reg->IFTIMING.RXDELAY = rxdelay;
}
#endif // defined(SPIM_IFTIMING_RXDELAY_RXDELAY_Msk)
#if defined(SPIM_STALLSTAT_RX_Msk)
__STATIC_INLINE void nrf_spim_stallstat_rx_clear(NRF_SPIM_Type * p_reg)
{
p_reg->STALLSTAT &= ~(SPIM_STALLSTAT_RX_Msk);
}
__STATIC_INLINE bool nrf_spim_stallstat_rx_get(NRF_SPIM_Type * p_reg)
{
return (p_reg->STALLSTAT & SPIM_STALLSTAT_RX_Msk) != 0;
}
#endif // defined(SPIM_STALLSTAT_RX_Msk)
#if defined(SPIM_STALLSTAT_TX_Msk)
__STATIC_INLINE void nrf_spim_stallstat_tx_clear(NRF_SPIM_Type * p_reg)
{
p_reg->STALLSTAT &= ~(SPIM_STALLSTAT_TX_Msk);
}
__STATIC_INLINE bool nrf_spim_stallstat_tx_get(NRF_SPIM_Type * p_reg)
{
return (p_reg->STALLSTAT & SPIM_STALLSTAT_TX_Msk) != 0;
}
#endif // defined(SPIM_STALLSTAT_TX_Msk)
__STATIC_INLINE void nrf_spim_frequency_set(NRF_SPIM_Type * p_reg,
nrf_spim_frequency_t frequency)
{
p_reg->FREQUENCY = (uint32_t)frequency;
}
__STATIC_INLINE void nrf_spim_tx_buffer_set(NRF_SPIM_Type * p_reg,
uint8_t const * p_buffer,
size_t length)
{
p_reg->TXD.PTR = (uint32_t)p_buffer;
p_reg->TXD.MAXCNT = length;
}
__STATIC_INLINE void nrf_spim_rx_buffer_set(NRF_SPIM_Type * p_reg,
uint8_t * p_buffer,
size_t length)
{
p_reg->RXD.PTR = (uint32_t)p_buffer;
p_reg->RXD.MAXCNT = length;
}
__STATIC_INLINE void nrf_spim_configure(NRF_SPIM_Type * p_reg,
nrf_spim_mode_t spi_mode,
nrf_spim_bit_order_t spi_bit_order)
{
uint32_t config = (spi_bit_order == NRF_SPIM_BIT_ORDER_MSB_FIRST ?
SPIM_CONFIG_ORDER_MsbFirst : SPIM_CONFIG_ORDER_LsbFirst);
switch (spi_mode)
{
default:
case NRF_SPIM_MODE_0:
config |= (SPIM_CONFIG_CPOL_ActiveHigh << SPIM_CONFIG_CPOL_Pos) |
(SPIM_CONFIG_CPHA_Leading << SPIM_CONFIG_CPHA_Pos);
break;
case NRF_SPIM_MODE_1:
config |= (SPIM_CONFIG_CPOL_ActiveHigh << SPIM_CONFIG_CPOL_Pos) |
(SPIM_CONFIG_CPHA_Trailing << SPIM_CONFIG_CPHA_Pos);
break;
case NRF_SPIM_MODE_2:
config |= (SPIM_CONFIG_CPOL_ActiveLow << SPIM_CONFIG_CPOL_Pos) |
(SPIM_CONFIG_CPHA_Leading << SPIM_CONFIG_CPHA_Pos);
break;
case NRF_SPIM_MODE_3:
config |= (SPIM_CONFIG_CPOL_ActiveLow << SPIM_CONFIG_CPOL_Pos) |
(SPIM_CONFIG_CPHA_Trailing << SPIM_CONFIG_CPHA_Pos);
break;
}
p_reg->CONFIG = config;
}
__STATIC_INLINE void nrf_spim_orc_set(NRF_SPIM_Type * p_reg,
uint8_t orc)
{
p_reg->ORC = orc;
}
__STATIC_INLINE void nrf_spim_tx_list_enable(NRF_SPIM_Type * p_reg)
{
p_reg->TXD.LIST = 1;
}
__STATIC_INLINE void nrf_spim_tx_list_disable(NRF_SPIM_Type * p_reg)
{
p_reg->TXD.LIST = 0;
}
__STATIC_INLINE void nrf_spim_rx_list_enable(NRF_SPIM_Type * p_reg)
{
p_reg->RXD.LIST = 1;
}
__STATIC_INLINE void nrf_spim_rx_list_disable(NRF_SPIM_Type * p_reg)
{
p_reg->RXD.LIST = 0;
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_SPIM_H__
+450
View File
@@ -0,0 +1,450 @@
/**
* Copyright (c) 2018 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_SPU_H__
#define NRF_SPU_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_spu_hal SPU HAL
* @{
* @ingroup nrf_spu
* @brief Hardware access layer for managing the System Protection Unit (SPU) peripheral.
*/
/** @brief SPU events. */
typedef enum
{
NRF_SPU_EVENT_RAMACCERR = offsetof(NRF_SPU_Type, EVENTS_RAMACCERR), ///< A security violation has been detected for the RAM memory space.
NRF_SPU_EVENT_FLASHACCERR = offsetof(NRF_SPU_Type, EVENTS_FLASHACCERR), ///< A security violation has been detected for the Flash memory space.
NRF_SPU_EVENT_PERIPHACCERR = offsetof(NRF_SPU_Type, EVENTS_PERIPHACCERR) ///< A security violation has been detected on one or several peripherals.
} nrf_spu_event_t;
/** @brief SPU interrupts. */
typedef enum
{
NRF_SPU_INT_RAMACCERR_MASK = SPU_INTENSET_RAMACCERR_Msk, ///< Interrupt on RAMACCERR event.
NRF_SPU_INT_FLASHACCERR_MASK = SPU_INTENSET_FLASHACCERR_Msk, ///< Interrupt on FLASHACCERR event.
NRF_SPU_INT_PERIPHACCERR_MASK = SPU_INTENSET_PERIPHACCERR_Msk ///< Interrupt on PERIPHACCERR event.
} nrf_spu_int_mask_t;
/** @brief SPU Non-Secure Callable (NSC) region size. */
typedef enum
{
NRF_SPU_NSC_SIZE_DISABLED = 0, ///< Not defined as a non-secure callable region.
NRF_SPU_NSC_SIZE_32B = 1, ///< Non-Secure Callable region with a 32-byte size
NRF_SPU_NSC_SIZE_64B = 2, ///< Non-Secure Callable region with a 64-byte size
NRF_SPU_NSC_SIZE_128B = 3, ///< Non-Secure Callable region with a 128-byte size
NRF_SPU_NSC_SIZE_256B = 4, ///< Non-Secure Callable region with a 256-byte size
NRF_SPU_NSC_SIZE_512B = 5, ///< Non-Secure Callable region with a 512-byte size
NRF_SPU_NSC_SIZE_1024B = 6, ///< Non-Secure Callable region with a 1024-byte size
NRF_SPU_NSC_SIZE_2048B = 7, ///< Non-Secure Callable region with a 2048-byte size
NRF_SPU_NSC_SIZE_4096B = 8 ///< Non-Secure Callable region with a 4096-byte size
} nrf_spu_nsc_size_t;
/** @brief SPU memory region permissions. */
typedef enum
{
NRF_SPU_MEM_PERM_EXECUTE = SPU_FLASHREGION_PERM_EXECUTE_Msk, ///< Allow code execution from particular memory region.
NRF_SPU_MEM_PERM_WRITE = SPU_FLASHREGION_PERM_WRITE_Msk, ///< Allow write operation on particular memory region.
NRF_SPU_MEM_PERM_READ = SPU_FLASHREGION_PERM_READ_Msk ///< Allow read operation from particular memory region.
} nrf_spu_mem_perm_t;
/**
* @brief Function for clearing a specific SPU event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to clear.
*/
__STATIC_INLINE void nrf_spu_event_clear(NRF_SPU_Type * p_reg,
nrf_spu_event_t event);
/**
* @brief Function for retrieving the state of the SPU event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be checked.
*
* @retval true The event has been generated.
* @retval false The event has not been generated.
*/
__STATIC_INLINE bool nrf_spu_event_check(NRF_SPU_Type const * p_reg,
nrf_spu_event_t event);
/**
* @brief Function for enabling specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Interrupts to be enabled.
*/
__STATIC_INLINE void nrf_spu_int_enable(NRF_SPU_Type * p_reg,
uint32_t mask);
/**
* @brief Function for disabling specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Interrupts to be disabled.
*/
__STATIC_INLINE void nrf_spu_int_disable(NRF_SPU_Type * p_reg,
uint32_t mask);
/**
* @brief Function for retrieving the state of a given interrupt.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] spu_int Interrupt to be checked.
*
* @retval true The interrupt is enabled.
* @retval false The interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_spu_int_enable_check(NRF_SPU_Type const * p_reg,
uint32_t spu_int);
/**
* @brief Function for setting up publication configuration of a given SPU event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to configure.
* @param[in] channel Channel to connect with published event.
*/
__STATIC_INLINE void nrf_spu_publish_set(NRF_SPU_Type * p_reg,
nrf_spu_event_t event,
uint32_t channel);
/**
* @brief Function for clearing publication configuration of a given SPU event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to clear.
*/
__STATIC_INLINE void nrf_spu_publish_clear(NRF_SPU_Type * p_reg,
nrf_spu_event_t event);
/**
* @brief Function for retrieving the capabilities of the current device.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @retval true ARM TrustZone support is available.
* @retval false ARM TrustZone support is not available.
*/
__STATIC_INLINE bool nrf_spu_tz_is_available(NRF_SPU_Type const * p_reg);
/**
* @brief Function for configuring the DPPI channels to be available in particular domains.
*
* Channels are configured as bitmask. Set one in bitmask to make channels available only in secure
* domain. Set zero to make it available in secure and non-secure domains.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] dppi_id DPPI peripheral id.
* @param[in] channels_mask Bitmask with channels configuration.
* @param[in] lock_conf Lock configuration until next SoC reset.
*/
__STATIC_INLINE void nrf_spu_dppi_config_set(NRF_SPU_Type * p_reg,
uint8_t dppi_id,
uint32_t channels_mask,
bool lock_conf);
/**
* @brief Function for configuring the GPIO pins to be available in particular domains.
*
* GPIO pins are configured as bitmask. Set one in bitmask to make particular pin available only
* in secure domain. Set zero to make it available in secure and non-secure domains.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] gpio_port Port number.
* @param[in] gpio_mask Bitmask with gpio configuration.
* @param[in] lock_conf Lock configuration until next SoC reset.
*/
__STATIC_INLINE void nrf_spu_gpio_config_set(NRF_SPU_Type * p_reg,
uint8_t gpio_port,
uint32_t gpio_mask,
bool lock_conf);
/**
* @brief Function for configuring non-secure callable flash region.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] flash_nsc_id Non-secure callable flash region ID.
* @param[in] flash_nsc_size Non-secure callable flash region size.
* @param[in] region_number Flash region number.
* @param[in] lock_conf Lock configuration until next SoC reset.
*/
__STATIC_INLINE void nrf_spu_flashnsc_set(NRF_SPU_Type * p_reg,
uint8_t flash_nsc_id,
nrf_spu_nsc_size_t flash_nsc_size,
uint8_t region_number,
bool lock_conf);
/**
* @brief Function for configuring non-secure callable RAM region.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] ram_nsc_id Non-secure callable RAM region ID.
* @param[in] ram_nsc_size Non-secure callable RAM region size.
* @param[in] region_number RAM region number.
* @param[in] lock_conf Lock configuration until next SoC reset.
*/
__STATIC_INLINE void nrf_spu_ramnsc_set(NRF_SPU_Type * p_reg,
uint8_t ram_nsc_id,
nrf_spu_nsc_size_t ram_nsc_size,
uint8_t region_number,
bool lock_conf);
/**
* @brief Function for configuring security for a particular flash region.
*
* Permissions parameter must be set by using the logical OR on the @ref nrf_spu_mem_perm_t values.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] region_id Flash region index.
* @param[in] secure_attr Set region attribute to secure.
* @param[in] permissions Flash region permissions.
* @param[in] lock_conf Lock configuration until next SoC reset.
*/
__STATIC_INLINE void nrf_spu_flashregion_set(NRF_SPU_Type * p_reg,
uint8_t region_id,
bool secure_attr,
uint32_t permissions,
bool lock_conf);
/**
* @brief Function for configuring security for the RAM region.
*
* Permissions parameter must be set by using the logical OR on the @ref nrf_spu_mem_perm_t values.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] region_id RAM region index.
* @param[in] secure_attr Set region attribute to secure.
* @param[in] permissions RAM region permissions.
* @param[in] lock_conf Lock configuration until next SoC reset.
*/
__STATIC_INLINE void nrf_spu_ramregion_set(NRF_SPU_Type * p_reg,
uint8_t region_id,
bool secure_attr,
uint32_t permissions,
bool lock_conf);
/**
* @brief Function for configuring access permissions of the peripheral.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] peripheral_id ID number of a particular peripheral.
* @param[in] secure_attr Peripheral registers accessible only from secure domain.
* @param[in] secure_dma DMA transfers possible only from RAM memory in secure domain.
* @param[in] lock_conf Lock configuration until next SoC reset.
*/
__STATIC_INLINE void nrf_spu_peripheral_set(NRF_SPU_Type * p_reg,
uint32_t peripheral_id,
bool secure_attr,
bool secure_dma,
bool lock_conf);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_spu_event_clear(NRF_SPU_Type * p_reg,
nrf_spu_event_t event)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0x0UL;
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event));
(void)dummy;
}
__STATIC_INLINE bool nrf_spu_event_check(NRF_SPU_Type const * p_reg,
nrf_spu_event_t event)
{
return (bool)*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE void nrf_spu_int_enable(NRF_SPU_Type * p_reg,
uint32_t mask)
{
p_reg->INTENSET = mask;
}
__STATIC_INLINE void nrf_spu_int_disable(NRF_SPU_Type * p_reg,
uint32_t mask)
{
p_reg->INTENCLR = mask;
}
__STATIC_INLINE bool nrf_spu_int_enable_check(NRF_SPU_Type const * p_reg,
uint32_t spu_int)
{
return (bool)(p_reg->INTENSET & spu_int);
}
__STATIC_INLINE void nrf_spu_publish_set(NRF_SPU_Type * p_reg,
nrf_spu_event_t event,
uint32_t channel)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) event + 0x80uL)) =
(channel | (SPU_PUBLISH_RAMACCERR_EN_Msk));
}
__STATIC_INLINE void nrf_spu_publish_clear(NRF_SPU_Type * p_reg,
nrf_spu_event_t event)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) event + 0x80uL)) = 0;
}
__STATIC_INLINE bool nrf_spu_tz_is_available(NRF_SPU_Type const * p_reg)
{
return (p_reg->CAP & SPU_CAP_TZM_Msk ? true : false);
}
__STATIC_INLINE void nrf_spu_dppi_config_set(NRF_SPU_Type * p_reg,
uint8_t dppi_id,
uint32_t channels_mask,
bool lock_conf)
{
NRFX_ASSERT(!(p_reg->DPPI[dppi_id].LOCK & SPU_DPPI_LOCK_LOCK_Msk));
p_reg->DPPI[dppi_id].PERM = channels_mask;
if (lock_conf)
{
p_reg->DPPI[dppi_id].LOCK = (SPU_DPPI_LOCK_LOCK_Msk);
}
}
__STATIC_INLINE void nrf_spu_gpio_config_set(NRF_SPU_Type * p_reg,
uint8_t gpio_port,
uint32_t gpio_mask,
bool lock_conf)
{
NRFX_ASSERT(!(p_reg->GPIOPORT[gpio_port].LOCK & SPU_GPIOPORT_LOCK_LOCK_Msk));
p_reg->GPIOPORT[gpio_port].PERM = gpio_mask;
if (lock_conf)
{
p_reg->GPIOPORT[gpio_port].LOCK = (SPU_GPIOPORT_LOCK_LOCK_Msk);
}
}
__STATIC_INLINE void nrf_spu_flashnsc_set(NRF_SPU_Type * p_reg,
uint8_t flash_nsc_id,
nrf_spu_nsc_size_t flash_nsc_size,
uint8_t region_number,
bool lock_conf)
{
NRFX_ASSERT(!(p_reg->FLASHNSC[flash_nsc_id].REGION & SPU_FLASHNSC_REGION_LOCK_Msk));
NRFX_ASSERT(!(p_reg->FLASHNSC[flash_nsc_id].SIZE & SPU_FLASHNSC_SIZE_LOCK_Msk));
p_reg->FLASHNSC[flash_nsc_id].REGION = (uint32_t)region_number |
(lock_conf ? SPU_FLASHNSC_REGION_LOCK_Msk : 0);
p_reg->FLASHNSC[flash_nsc_id].SIZE = (uint32_t)flash_nsc_size |
(lock_conf ? SPU_FLASHNSC_SIZE_LOCK_Msk : 0);
}
__STATIC_INLINE void nrf_spu_ramnsc_set(NRF_SPU_Type * p_reg,
uint8_t ram_nsc_id,
nrf_spu_nsc_size_t ram_nsc_size,
uint8_t region_number,
bool lock_conf)
{
NRFX_ASSERT(!(p_reg->RAMNSC[ram_nsc_id].REGION & SPU_RAMNSC_REGION_LOCK_Msk));
NRFX_ASSERT(!(p_reg->RAMNSC[ram_nsc_id].SIZE & SPU_RAMNSC_SIZE_LOCK_Msk));
p_reg->RAMNSC[ram_nsc_id].REGION = (uint32_t)region_number |
(lock_conf ? SPU_RAMNSC_REGION_LOCK_Msk : 0);
p_reg->RAMNSC[ram_nsc_id].SIZE = (uint32_t)ram_nsc_size |
(lock_conf ? SPU_RAMNSC_SIZE_LOCK_Msk : 0);
}
__STATIC_INLINE void nrf_spu_flashregion_set(NRF_SPU_Type * p_reg,
uint8_t region_id,
bool secure_attr,
uint32_t permissions,
bool lock_conf)
{
NRFX_ASSERT(!(p_reg->FLASHREGION[region_id].PERM & SPU_FLASHREGION_PERM_LOCK_Msk));
p_reg->FLASHREGION[region_id].PERM = permissions |
(secure_attr ? SPU_FLASHREGION_PERM_SECATTR_Msk : 0) |
(lock_conf ? SPU_FLASHREGION_PERM_LOCK_Msk : 0);
}
__STATIC_INLINE void nrf_spu_ramregion_set(NRF_SPU_Type * p_reg,
uint8_t region_id,
bool secure_attr,
uint32_t permissions,
bool lock_conf)
{
NRFX_ASSERT(!(p_reg->RAMREGION[region_id].PERM & SPU_RAMREGION_PERM_LOCK_Msk));
p_reg->RAMREGION[region_id].PERM = permissions |
(secure_attr ? SPU_RAMREGION_PERM_SECATTR_Msk : 0) |
(lock_conf ? SPU_RAMREGION_PERM_LOCK_Msk : 0);
}
__STATIC_INLINE void nrf_spu_peripheral_set(NRF_SPU_Type * p_reg,
uint32_t peripheral_id,
bool secure_attr,
bool secure_dma,
bool lock_conf)
{
NRFX_ASSERT(p_reg->PERIPHID[peripheral_id].PERM & SPU_PERIPHID_PERM_PRESENT_Msk);
NRFX_ASSERT(!(p_reg->PERIPHID[peripheral_id].PERM & SPU_PERIPHID_PERM_LOCK_Msk));
p_reg->PERIPHID[peripheral_id].PERM =
(secure_attr ? SPU_PERIPHID_PERM_SECATTR_Msk : 0) |
(secure_dma ? SPU_PERIPHID_PERM_DMASEC_Msk : 0) |
(lock_conf ? SPU_PERIPHID_PERM_LOCK_Msk : 0);
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_SPU_H__
+720
View File
@@ -0,0 +1,720 @@
/**
* Copyright (c) 2014 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_TIMER_H__
#define NRF_TIMER_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_timer_hal TIMER HAL
* @{
* @ingroup nrf_timer
* @brief Hardware access layer for managing the TIMER peripheral.
*/
/**
* @brief Macro for getting the maximum bit resolution of the specified timer instance.
*
* @param[in] id Index of the specified timer instance.
*
* @retval Maximum bit resolution of the specified timer instance.
*/
#define TIMER_MAX_SIZE(id) NRFX_CONCAT_3(TIMER, id, _MAX_SIZE)
/**
* @brief Macro for validating the correctness of the bit width resolution setting.
*
* @param[in] id Index of the specified timer instance.
* @param[in] bit_width Bit width resolution value to be checked.
*
* @retval true Timer instance supports the specified bit width resolution value.
* @retval false Timer instance does not support the specified bit width resolution value.
*/
#define TIMER_BIT_WIDTH_MAX(id, bit_width) \
(TIMER_MAX_SIZE(id) == 8 ? (bit_width == NRF_TIMER_BIT_WIDTH_8) : \
(TIMER_MAX_SIZE(id) == 16 ? (bit_width == NRF_TIMER_BIT_WIDTH_8) || \
(bit_width == NRF_TIMER_BIT_WIDTH_16) : \
(TIMER_MAX_SIZE(id) == 24 ? (bit_width == NRF_TIMER_BIT_WIDTH_8) || \
(bit_width == NRF_TIMER_BIT_WIDTH_16) || \
(bit_width == NRF_TIMER_BIT_WIDTH_24) : \
(TIMER_MAX_SIZE(id) == 32 ? (bit_width == NRF_TIMER_BIT_WIDTH_8) || \
(bit_width == NRF_TIMER_BIT_WIDTH_16) || \
(bit_width == NRF_TIMER_BIT_WIDTH_24) || \
(bit_width == NRF_TIMER_BIT_WIDTH_32) : \
false))))
/**
* @brief Macro for checking correctness of bit width configuration for the specified timer.
*
* @param[in] p_reg Timer instance register.
* @param[in] bit_width Bit width resolution value to be checked.
*
* @retval true Timer instance supports the specified bit width resolution value.
* @retval false Timer instance does not support the specified bit width resolution value.
*/
#if (TIMER_COUNT == 3) || defined(__NRFX_DOXYGEN__)
#define NRF_TIMER_IS_BIT_WIDTH_VALID(p_reg, bit_width) ( \
((p_reg == NRF_TIMER0) && TIMER_BIT_WIDTH_MAX(0, bit_width)) \
|| ((p_reg == NRF_TIMER1) && TIMER_BIT_WIDTH_MAX(1, bit_width)) \
|| ((p_reg == NRF_TIMER2) && TIMER_BIT_WIDTH_MAX(2, bit_width)))
#elif (TIMER_COUNT == 4)
#define NRF_TIMER_IS_BIT_WIDTH_VALID(p_reg, bit_width) ( \
((p_reg == NRF_TIMER0) && TIMER_BIT_WIDTH_MAX(0, bit_width)) \
|| ((p_reg == NRF_TIMER1) && TIMER_BIT_WIDTH_MAX(1, bit_width)) \
|| ((p_reg == NRF_TIMER2) && TIMER_BIT_WIDTH_MAX(2, bit_width)) \
|| ((p_reg == NRF_TIMER3) && TIMER_BIT_WIDTH_MAX(3, bit_width)))
#elif (TIMER_COUNT == 5)
#define NRF_TIMER_IS_BIT_WIDTH_VALID(p_reg, bit_width) ( \
((p_reg == NRF_TIMER0) && TIMER_BIT_WIDTH_MAX(0, bit_width)) \
|| ((p_reg == NRF_TIMER1) && TIMER_BIT_WIDTH_MAX(1, bit_width)) \
|| ((p_reg == NRF_TIMER2) && TIMER_BIT_WIDTH_MAX(2, bit_width)) \
|| ((p_reg == NRF_TIMER3) && TIMER_BIT_WIDTH_MAX(3, bit_width)) \
|| ((p_reg == NRF_TIMER4) && TIMER_BIT_WIDTH_MAX(4, bit_width)))
#else
#error "Not supported timer count"
#endif
/**
* @brief Macro for getting the number of capture/compare channels available
* in a given timer instance.
*
* @param[in] id Index of the specified timer instance.
*/
#define NRF_TIMER_CC_CHANNEL_COUNT(id) NRFX_CONCAT_3(TIMER, id, _CC_NUM)
/** @brief Timer tasks. */
typedef enum
{
NRF_TIMER_TASK_START = offsetof(NRF_TIMER_Type, TASKS_START), ///< Task for starting the timer.
NRF_TIMER_TASK_STOP = offsetof(NRF_TIMER_Type, TASKS_STOP), ///< Task for stopping the timer.
NRF_TIMER_TASK_COUNT = offsetof(NRF_TIMER_Type, TASKS_COUNT), ///< Task for incrementing the timer (in counter mode).
NRF_TIMER_TASK_CLEAR = offsetof(NRF_TIMER_Type, TASKS_CLEAR), ///< Task for resetting the timer value.
NRF_TIMER_TASK_SHUTDOWN = offsetof(NRF_TIMER_Type, TASKS_SHUTDOWN), ///< Task for powering off the timer.
NRF_TIMER_TASK_CAPTURE0 = offsetof(NRF_TIMER_Type, TASKS_CAPTURE[0]), ///< Task for capturing the timer value on channel 0.
NRF_TIMER_TASK_CAPTURE1 = offsetof(NRF_TIMER_Type, TASKS_CAPTURE[1]), ///< Task for capturing the timer value on channel 1.
NRF_TIMER_TASK_CAPTURE2 = offsetof(NRF_TIMER_Type, TASKS_CAPTURE[2]), ///< Task for capturing the timer value on channel 2.
NRF_TIMER_TASK_CAPTURE3 = offsetof(NRF_TIMER_Type, TASKS_CAPTURE[3]), ///< Task for capturing the timer value on channel 3.
#if defined(TIMER_INTENSET_COMPARE4_Msk) || defined(__NRFX_DOXYGEN__)
NRF_TIMER_TASK_CAPTURE4 = offsetof(NRF_TIMER_Type, TASKS_CAPTURE[4]), ///< Task for capturing the timer value on channel 4.
#endif
#if defined(TIMER_INTENSET_COMPARE5_Msk) || defined(__NRFX_DOXYGEN__)
NRF_TIMER_TASK_CAPTURE5 = offsetof(NRF_TIMER_Type, TASKS_CAPTURE[5]), ///< Task for capturing the timer value on channel 5.
#endif
} nrf_timer_task_t;
/** @brief Timer events. */
typedef enum
{
NRF_TIMER_EVENT_COMPARE0 = offsetof(NRF_TIMER_Type, EVENTS_COMPARE[0]), ///< Event from compare channel 0.
NRF_TIMER_EVENT_COMPARE1 = offsetof(NRF_TIMER_Type, EVENTS_COMPARE[1]), ///< Event from compare channel 1.
NRF_TIMER_EVENT_COMPARE2 = offsetof(NRF_TIMER_Type, EVENTS_COMPARE[2]), ///< Event from compare channel 2.
NRF_TIMER_EVENT_COMPARE3 = offsetof(NRF_TIMER_Type, EVENTS_COMPARE[3]), ///< Event from compare channel 3.
#if defined(TIMER_INTENSET_COMPARE4_Msk) || defined(__NRFX_DOXYGEN__)
NRF_TIMER_EVENT_COMPARE4 = offsetof(NRF_TIMER_Type, EVENTS_COMPARE[4]), ///< Event from compare channel 4.
#endif
#if defined(TIMER_INTENSET_COMPARE5_Msk) || defined(__NRFX_DOXYGEN__)
NRF_TIMER_EVENT_COMPARE5 = offsetof(NRF_TIMER_Type, EVENTS_COMPARE[5]), ///< Event from compare channel 5.
#endif
} nrf_timer_event_t;
/** @brief Types of timer shortcuts. */
typedef enum
{
NRF_TIMER_SHORT_COMPARE0_STOP_MASK = TIMER_SHORTS_COMPARE0_STOP_Msk, ///< Shortcut for stopping the timer based on compare 0.
NRF_TIMER_SHORT_COMPARE1_STOP_MASK = TIMER_SHORTS_COMPARE1_STOP_Msk, ///< Shortcut for stopping the timer based on compare 1.
NRF_TIMER_SHORT_COMPARE2_STOP_MASK = TIMER_SHORTS_COMPARE2_STOP_Msk, ///< Shortcut for stopping the timer based on compare 2.
NRF_TIMER_SHORT_COMPARE3_STOP_MASK = TIMER_SHORTS_COMPARE3_STOP_Msk, ///< Shortcut for stopping the timer based on compare 3.
#if defined(TIMER_INTENSET_COMPARE4_Msk) || defined(__NRFX_DOXYGEN__)
NRF_TIMER_SHORT_COMPARE4_STOP_MASK = TIMER_SHORTS_COMPARE4_STOP_Msk, ///< Shortcut for stopping the timer based on compare 4.
#endif
#if defined(TIMER_INTENSET_COMPARE5_Msk) || defined(__NRFX_DOXYGEN__)
NRF_TIMER_SHORT_COMPARE5_STOP_MASK = TIMER_SHORTS_COMPARE5_STOP_Msk, ///< Shortcut for stopping the timer based on compare 5.
#endif
NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK = TIMER_SHORTS_COMPARE0_CLEAR_Msk, ///< Shortcut for clearing the timer based on compare 0.
NRF_TIMER_SHORT_COMPARE1_CLEAR_MASK = TIMER_SHORTS_COMPARE1_CLEAR_Msk, ///< Shortcut for clearing the timer based on compare 1.
NRF_TIMER_SHORT_COMPARE2_CLEAR_MASK = TIMER_SHORTS_COMPARE2_CLEAR_Msk, ///< Shortcut for clearing the timer based on compare 2.
NRF_TIMER_SHORT_COMPARE3_CLEAR_MASK = TIMER_SHORTS_COMPARE3_CLEAR_Msk, ///< Shortcut for clearing the timer based on compare 3.
#if defined(TIMER_INTENSET_COMPARE4_Msk) || defined(__NRFX_DOXYGEN__)
NRF_TIMER_SHORT_COMPARE4_CLEAR_MASK = TIMER_SHORTS_COMPARE4_CLEAR_Msk, ///< Shortcut for clearing the timer based on compare 4.
#endif
#if defined(TIMER_INTENSET_COMPARE5_Msk) || defined(__NRFX_DOXYGEN__)
NRF_TIMER_SHORT_COMPARE5_CLEAR_MASK = TIMER_SHORTS_COMPARE5_CLEAR_Msk, ///< Shortcut for clearing the timer based on compare 5.
#endif
} nrf_timer_short_mask_t;
/** @brief Timer modes. */
typedef enum
{
NRF_TIMER_MODE_TIMER = TIMER_MODE_MODE_Timer, ///< Timer mode: timer.
NRF_TIMER_MODE_COUNTER = TIMER_MODE_MODE_Counter, ///< Timer mode: counter.
#if defined(TIMER_MODE_MODE_LowPowerCounter) || defined(__NRFX_DOXYGEN__)
NRF_TIMER_MODE_LOW_POWER_COUNTER = TIMER_MODE_MODE_LowPowerCounter, ///< Timer mode: low-power counter.
#endif
} nrf_timer_mode_t;
/** @brief Timer bit width. */
typedef enum
{
NRF_TIMER_BIT_WIDTH_8 = TIMER_BITMODE_BITMODE_08Bit, ///< Timer bit width 8 bit.
NRF_TIMER_BIT_WIDTH_16 = TIMER_BITMODE_BITMODE_16Bit, ///< Timer bit width 16 bit.
NRF_TIMER_BIT_WIDTH_24 = TIMER_BITMODE_BITMODE_24Bit, ///< Timer bit width 24 bit.
NRF_TIMER_BIT_WIDTH_32 = TIMER_BITMODE_BITMODE_32Bit ///< Timer bit width 32 bit.
} nrf_timer_bit_width_t;
/** @brief Timer prescalers. */
typedef enum
{
NRF_TIMER_FREQ_16MHz = 0, ///< Timer frequency 16 MHz.
NRF_TIMER_FREQ_8MHz, ///< Timer frequency 8 MHz.
NRF_TIMER_FREQ_4MHz, ///< Timer frequency 4 MHz.
NRF_TIMER_FREQ_2MHz, ///< Timer frequency 2 MHz.
NRF_TIMER_FREQ_1MHz, ///< Timer frequency 1 MHz.
NRF_TIMER_FREQ_500kHz, ///< Timer frequency 500 kHz.
NRF_TIMER_FREQ_250kHz, ///< Timer frequency 250 kHz.
NRF_TIMER_FREQ_125kHz, ///< Timer frequency 125 kHz.
NRF_TIMER_FREQ_62500Hz, ///< Timer frequency 62500 Hz.
NRF_TIMER_FREQ_31250Hz ///< Timer frequency 31250 Hz.
} nrf_timer_frequency_t;
/** @brief Timer capture/compare channels. */
typedef enum
{
NRF_TIMER_CC_CHANNEL0 = 0, ///< Timer capture/compare channel 0.
NRF_TIMER_CC_CHANNEL1, ///< Timer capture/compare channel 1.
NRF_TIMER_CC_CHANNEL2, ///< Timer capture/compare channel 2.
NRF_TIMER_CC_CHANNEL3, ///< Timer capture/compare channel 3.
#if defined(TIMER_INTENSET_COMPARE4_Msk) || defined(__NRFX_DOXYGEN__)
NRF_TIMER_CC_CHANNEL4, ///< Timer capture/compare channel 4.
#endif
#if defined(TIMER_INTENSET_COMPARE5_Msk) || defined(__NRFX_DOXYGEN__)
NRF_TIMER_CC_CHANNEL5, ///< Timer capture/compare channel 5.
#endif
} nrf_timer_cc_channel_t;
/** @brief Timer interrupts. */
typedef enum
{
NRF_TIMER_INT_COMPARE0_MASK = TIMER_INTENSET_COMPARE0_Msk, ///< Timer interrupt from compare event on channel 0.
NRF_TIMER_INT_COMPARE1_MASK = TIMER_INTENSET_COMPARE1_Msk, ///< Timer interrupt from compare event on channel 1.
NRF_TIMER_INT_COMPARE2_MASK = TIMER_INTENSET_COMPARE2_Msk, ///< Timer interrupt from compare event on channel 2.
NRF_TIMER_INT_COMPARE3_MASK = TIMER_INTENSET_COMPARE3_Msk, ///< Timer interrupt from compare event on channel 3.
#if defined(TIMER_INTENSET_COMPARE4_Msk) || defined(__NRFX_DOXYGEN__)
NRF_TIMER_INT_COMPARE4_MASK = TIMER_INTENSET_COMPARE4_Msk, ///< Timer interrupt from compare event on channel 4.
#endif
#if defined(TIMER_INTENSET_COMPARE5_Msk) || defined(__NRFX_DOXYGEN__)
NRF_TIMER_INT_COMPARE5_MASK = TIMER_INTENSET_COMPARE5_Msk, ///< Timer interrupt from compare event on channel 5.
#endif
} nrf_timer_int_mask_t;
/**
* @brief Function for activating the specified timer task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task to be activated.
*/
__STATIC_INLINE void nrf_timer_task_trigger(NRF_TIMER_Type * p_reg,
nrf_timer_task_t task);
/**
* @brief Function for getting the address of the specified timer task register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task The specified task.
*
* @return Address of the specified task register.
*/
__STATIC_INLINE uint32_t * nrf_timer_task_address_get(NRF_TIMER_Type * p_reg,
nrf_timer_task_t task);
/**
* @brief Function for clearing the specified timer event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to clear.
*/
__STATIC_INLINE void nrf_timer_event_clear(NRF_TIMER_Type * p_reg,
nrf_timer_event_t event);
/**
* @brief Function for retrieving the state of the TIMER event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be checked.
*
* @retval true The event has been generated.
* @retval false The event has not been generated.
*/
__STATIC_INLINE bool nrf_timer_event_check(NRF_TIMER_Type * p_reg,
nrf_timer_event_t event);
/**
* @brief Function for getting the address of the specified timer event register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event The specified event.
*
* @return Address of the specified event register.
*/
__STATIC_INLINE uint32_t * nrf_timer_event_address_get(NRF_TIMER_Type * p_reg,
nrf_timer_event_t event);
/**
* @brief Function for enabling the specified shortcuts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Shortcuts to be enabled.
*/
__STATIC_INLINE void nrf_timer_shorts_enable(NRF_TIMER_Type * p_reg,
uint32_t mask);
/**
* @brief Function for disabling the specified shortcuts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Shortcuts to be disabled.
*/
__STATIC_INLINE void nrf_timer_shorts_disable(NRF_TIMER_Type * p_reg,
uint32_t mask);
/**
* @brief Function for enabling the specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of interrupts to be enabled.
*/
__STATIC_INLINE void nrf_timer_int_enable(NRF_TIMER_Type * p_reg,
uint32_t mask);
/**
* @brief Function for disabling the specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of interrupts to be disabled.
*/
__STATIC_INLINE void nrf_timer_int_disable(NRF_TIMER_Type * p_reg,
uint32_t mask);
/**
* @brief Function for retrieving the state of a given interrupt.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] timer_int Interrupt to be checked.
*
* @retval true The interrupt is enabled.
* @retval false The interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_timer_int_enable_check(NRF_TIMER_Type * p_reg,
uint32_t timer_int);
#if defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting the subscribe configuration for a given
* TIMER task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task for which to set the configuration.
* @param[in] channel Channel through which to subscribe events.
*/
__STATIC_INLINE void nrf_timer_subscribe_set(NRF_TIMER_Type * p_reg,
nrf_timer_task_t task,
uint8_t channel);
/**
* @brief Function for clearing the subscribe configuration for a given
* TIMER task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task for which to clear the configuration.
*/
__STATIC_INLINE void nrf_timer_subscribe_clear(NRF_TIMER_Type * p_reg,
nrf_timer_task_t task);
/**
* @brief Function for setting the publish configuration for a given
* TIMER event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event for which to set the configuration.
* @param[in] channel Channel through which to publish the event.
*/
__STATIC_INLINE void nrf_timer_publish_set(NRF_TIMER_Type * p_reg,
nrf_timer_event_t event,
uint8_t channel);
/**
* @brief Function for clearing the publish configuration for a given
* TIMER event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event for which to clear the configuration.
*/
__STATIC_INLINE void nrf_timer_publish_clear(NRF_TIMER_Type * p_reg,
nrf_timer_event_t event);
#endif // defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting the timer mode.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mode Timer mode.
*/
__STATIC_INLINE void nrf_timer_mode_set(NRF_TIMER_Type * p_reg,
nrf_timer_mode_t mode);
/**
* @brief Function for retrieving the timer mode.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Timer mode.
*/
__STATIC_INLINE nrf_timer_mode_t nrf_timer_mode_get(NRF_TIMER_Type * p_reg);
/**
* @brief Function for setting the timer bit width.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] bit_width Timer bit width.
*/
__STATIC_INLINE void nrf_timer_bit_width_set(NRF_TIMER_Type * p_reg,
nrf_timer_bit_width_t bit_width);
/**
* @brief Function for retrieving the timer bit width.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Timer bit width.
*/
__STATIC_INLINE nrf_timer_bit_width_t nrf_timer_bit_width_get(NRF_TIMER_Type * p_reg);
/**
* @brief Function for setting the timer frequency.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] frequency Timer frequency.
*/
__STATIC_INLINE void nrf_timer_frequency_set(NRF_TIMER_Type * p_reg,
nrf_timer_frequency_t frequency);
/**
* @brief Function for retrieving the timer frequency.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Timer frequency.
*/
__STATIC_INLINE nrf_timer_frequency_t nrf_timer_frequency_get(NRF_TIMER_Type * p_reg);
/**
* @brief Function for writing the capture/compare register for the specified channel.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] cc_channel The specified capture/compare channel.
* @param[in] cc_value Value to write to the capture/compare register.
*/
__STATIC_INLINE void nrf_timer_cc_write(NRF_TIMER_Type * p_reg,
nrf_timer_cc_channel_t cc_channel,
uint32_t cc_value);
/**
* @brief Function for retrieving the capture/compare value for a specified channel.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] cc_channel The specified capture/compare channel.
*
* @return Value from the specified capture/compare register.
*/
__STATIC_INLINE uint32_t nrf_timer_cc_read(NRF_TIMER_Type * p_reg,
nrf_timer_cc_channel_t cc_channel);
/**
* @brief Function for getting the specified timer capture task.
*
* @param[in] channel Capture channel.
*
* @return Capture task.
*/
__STATIC_INLINE nrf_timer_task_t nrf_timer_capture_task_get(uint32_t channel);
/**
* @brief Function for getting the specified timer compare event.
*
* @param[in] channel Compare channel.
*
* @return Compare event.
*/
__STATIC_INLINE nrf_timer_event_t nrf_timer_compare_event_get(uint32_t channel);
/**
* @brief Function for getting the specified timer compare interrupt.
*
* @param[in] channel Compare channel.
*
* @return Compare interrupt.
*/
__STATIC_INLINE nrf_timer_int_mask_t nrf_timer_compare_int_get(uint32_t channel);
/**
* @brief Function for calculating the number of timer ticks for a given time
* (in microseconds) and timer frequency.
*
* @param[in] time_us Time in microseconds.
* @param[in] frequency Timer frequency.
*
* @return Number of timer ticks.
*/
__STATIC_INLINE uint32_t nrf_timer_us_to_ticks(uint32_t time_us,
nrf_timer_frequency_t frequency);
/**
* @brief Function for calculating the number of timer ticks for a given time
* (in milliseconds) and timer frequency.
*
* @param[in] time_ms Time in milliseconds.
* @param[in] frequency Timer frequency.
*
* @return Number of timer ticks.
*/
__STATIC_INLINE uint32_t nrf_timer_ms_to_ticks(uint32_t time_ms,
nrf_timer_frequency_t frequency);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_timer_task_trigger(NRF_TIMER_Type * p_reg,
nrf_timer_task_t task)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)task)) = 0x1UL;
}
__STATIC_INLINE uint32_t * nrf_timer_task_address_get(NRF_TIMER_Type * p_reg,
nrf_timer_task_t task)
{
return (uint32_t *)((uint8_t *)p_reg + (uint32_t)task);
}
__STATIC_INLINE void nrf_timer_event_clear(NRF_TIMER_Type * p_reg,
nrf_timer_event_t event)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0x0UL;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event));
(void)dummy;
#endif
}
__STATIC_INLINE bool nrf_timer_event_check(NRF_TIMER_Type * p_reg,
nrf_timer_event_t event)
{
return (bool)*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE uint32_t * nrf_timer_event_address_get(NRF_TIMER_Type * p_reg,
nrf_timer_event_t event)
{
return (uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE void nrf_timer_shorts_enable(NRF_TIMER_Type * p_reg,
uint32_t mask)
{
p_reg->SHORTS |= mask;
}
__STATIC_INLINE void nrf_timer_shorts_disable(NRF_TIMER_Type * p_reg,
uint32_t mask)
{
p_reg->SHORTS &= ~(mask);
}
__STATIC_INLINE void nrf_timer_int_enable(NRF_TIMER_Type * p_reg,
uint32_t mask)
{
p_reg->INTENSET = mask;
}
__STATIC_INLINE void nrf_timer_int_disable(NRF_TIMER_Type * p_reg,
uint32_t mask)
{
p_reg->INTENCLR = mask;
}
__STATIC_INLINE bool nrf_timer_int_enable_check(NRF_TIMER_Type * p_reg,
uint32_t timer_int)
{
return (bool)(p_reg->INTENSET & timer_int);
}
#if defined(DPPI_PRESENT)
__STATIC_INLINE void nrf_timer_subscribe_set(NRF_TIMER_Type * p_reg,
nrf_timer_task_t task,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) task + 0x80uL)) =
((uint32_t)channel | TIMER_SUBSCRIBE_START_EN_Msk);
}
__STATIC_INLINE void nrf_timer_subscribe_clear(NRF_TIMER_Type * p_reg,
nrf_timer_task_t task)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) task + 0x80uL)) = 0;
}
__STATIC_INLINE void nrf_timer_publish_set(NRF_TIMER_Type * p_reg,
nrf_timer_event_t event,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) event + 0x80uL)) =
((uint32_t)channel | TIMER_PUBLISH_COMPARE_EN_Msk);
}
__STATIC_INLINE void nrf_timer_publish_clear(NRF_TIMER_Type * p_reg,
nrf_timer_event_t event)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) event + 0x80uL)) = 0;
}
#endif // defined(DPPI_PRESENT)
__STATIC_INLINE void nrf_timer_mode_set(NRF_TIMER_Type * p_reg,
nrf_timer_mode_t mode)
{
p_reg->MODE = (p_reg->MODE & ~TIMER_MODE_MODE_Msk) |
((mode << TIMER_MODE_MODE_Pos) & TIMER_MODE_MODE_Msk);
}
__STATIC_INLINE nrf_timer_mode_t nrf_timer_mode_get(NRF_TIMER_Type * p_reg)
{
return (nrf_timer_mode_t)(p_reg->MODE);
}
__STATIC_INLINE void nrf_timer_bit_width_set(NRF_TIMER_Type * p_reg,
nrf_timer_bit_width_t bit_width)
{
p_reg->BITMODE = (p_reg->BITMODE & ~TIMER_BITMODE_BITMODE_Msk) |
((bit_width << TIMER_BITMODE_BITMODE_Pos) &
TIMER_BITMODE_BITMODE_Msk);
}
__STATIC_INLINE nrf_timer_bit_width_t nrf_timer_bit_width_get(NRF_TIMER_Type * p_reg)
{
return (nrf_timer_bit_width_t)(p_reg->BITMODE);
}
__STATIC_INLINE void nrf_timer_frequency_set(NRF_TIMER_Type * p_reg,
nrf_timer_frequency_t frequency)
{
p_reg->PRESCALER = (p_reg->PRESCALER & ~TIMER_PRESCALER_PRESCALER_Msk) |
((frequency << TIMER_PRESCALER_PRESCALER_Pos) &
TIMER_PRESCALER_PRESCALER_Msk);
}
__STATIC_INLINE nrf_timer_frequency_t nrf_timer_frequency_get(NRF_TIMER_Type * p_reg)
{
return (nrf_timer_frequency_t)(p_reg->PRESCALER);
}
__STATIC_INLINE void nrf_timer_cc_write(NRF_TIMER_Type * p_reg,
nrf_timer_cc_channel_t cc_channel,
uint32_t cc_value)
{
p_reg->CC[cc_channel] = cc_value;
}
__STATIC_INLINE uint32_t nrf_timer_cc_read(NRF_TIMER_Type * p_reg,
nrf_timer_cc_channel_t cc_channel)
{
return (uint32_t)p_reg->CC[cc_channel];
}
__STATIC_INLINE nrf_timer_task_t nrf_timer_capture_task_get(uint32_t channel)
{
return (nrf_timer_task_t)NRFX_OFFSETOF(NRF_TIMER_Type, TASKS_CAPTURE[channel]);
}
__STATIC_INLINE nrf_timer_event_t nrf_timer_compare_event_get(uint32_t channel)
{
return (nrf_timer_event_t)NRFX_OFFSETOF(NRF_TIMER_Type, EVENTS_COMPARE[channel]);
}
__STATIC_INLINE nrf_timer_int_mask_t nrf_timer_compare_int_get(uint32_t channel)
{
return (nrf_timer_int_mask_t)
((uint32_t)NRF_TIMER_INT_COMPARE0_MASK << channel);
}
__STATIC_INLINE uint32_t nrf_timer_us_to_ticks(uint32_t time_us,
nrf_timer_frequency_t frequency)
{
// The "frequency" parameter here is actually the prescaler value, and the
// timer runs at the following frequency: f = 16 MHz / 2^prescaler.
uint32_t prescaler = (uint32_t)frequency;
uint64_t ticks = ((time_us * 16ULL) >> prescaler);
NRFX_ASSERT(ticks <= UINT32_MAX);
return (uint32_t)ticks;
}
__STATIC_INLINE uint32_t nrf_timer_ms_to_ticks(uint32_t time_ms,
nrf_timer_frequency_t frequency)
{
// The "frequency" parameter here is actually the prescaler value, and the
// timer runs at the following frequency: f = 16000 kHz / 2^prescaler.
uint32_t prescaler = (uint32_t)frequency;
uint64_t ticks = ((time_ms * 16000ULL) >> prescaler);
NRFX_ASSERT(ticks <= UINT32_MAX);
return (uint32_t)ticks;
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_TIMER_H__
+476
View File
@@ -0,0 +1,476 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_TWI_H__
#define NRF_TWI_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_twi_hal TWI HAL
* @{
* @ingroup nrf_twi
* @brief Hardware access layer for managing the TWI peripheral.
*/
/** @brief TWI tasks. */
typedef enum
{
NRF_TWI_TASK_STARTRX = offsetof(NRF_TWI_Type, TASKS_STARTRX), ///< Start TWI receive sequence.
NRF_TWI_TASK_STARTTX = offsetof(NRF_TWI_Type, TASKS_STARTTX), ///< Start TWI transmit sequence.
NRF_TWI_TASK_STOP = offsetof(NRF_TWI_Type, TASKS_STOP), ///< Stop TWI transaction.
NRF_TWI_TASK_SUSPEND = offsetof(NRF_TWI_Type, TASKS_SUSPEND), ///< Suspend TWI transaction.
NRF_TWI_TASK_RESUME = offsetof(NRF_TWI_Type, TASKS_RESUME) ///< Resume TWI transaction.
} nrf_twi_task_t;
/** @brief TWI events. */
typedef enum
{
NRF_TWI_EVENT_STOPPED = offsetof(NRF_TWI_Type, EVENTS_STOPPED), ///< TWI stopped.
NRF_TWI_EVENT_RXDREADY = offsetof(NRF_TWI_Type, EVENTS_RXDREADY), ///< TWI RXD byte received.
NRF_TWI_EVENT_TXDSENT = offsetof(NRF_TWI_Type, EVENTS_TXDSENT), ///< TWI TXD byte sent.
NRF_TWI_EVENT_ERROR = offsetof(NRF_TWI_Type, EVENTS_ERROR), ///< TWI error.
NRF_TWI_EVENT_BB = offsetof(NRF_TWI_Type, EVENTS_BB), ///< TWI byte boundary, generated before each byte that is sent or received.
NRF_TWI_EVENT_SUSPENDED = offsetof(NRF_TWI_Type, EVENTS_SUSPENDED) ///< TWI entered the suspended state.
} nrf_twi_event_t;
/** @brief TWI shortcuts. */
typedef enum
{
NRF_TWI_SHORT_BB_SUSPEND_MASK = TWI_SHORTS_BB_SUSPEND_Msk, ///< Shortcut between BB event and SUSPEND task.
NRF_TWI_SHORT_BB_STOP_MASK = TWI_SHORTS_BB_STOP_Msk, ///< Shortcut between BB event and STOP task.
NRF_TWI_ALL_SHORTS_MASK = TWI_SHORTS_BB_SUSPEND_Msk |
TWI_SHORTS_BB_STOP_Msk ///< All TWI shortcuts.
} nrf_twi_short_mask_t;
/** @brief TWI interrupts. */
typedef enum
{
NRF_TWI_INT_STOPPED_MASK = TWI_INTENSET_STOPPED_Msk, ///< Interrupt on STOPPED event.
NRF_TWI_INT_RXDREADY_MASK = TWI_INTENSET_RXDREADY_Msk, ///< Interrupt on RXDREADY event.
NRF_TWI_INT_TXDSENT_MASK = TWI_INTENSET_TXDSENT_Msk, ///< Interrupt on TXDSENT event.
NRF_TWI_INT_ERROR_MASK = TWI_INTENSET_ERROR_Msk, ///< Interrupt on ERROR event.
NRF_TWI_INT_BB_MASK = TWI_INTENSET_BB_Msk, ///< Interrupt on BB event.
NRF_TWI_INT_SUSPENDED_MASK = TWI_INTENSET_SUSPENDED_Msk, ///< Interrupt on SUSPENDED event.
NRF_TWI_ALL_INTS_MASK = TWI_INTENSET_STOPPED_Msk |
TWI_INTENSET_RXDREADY_Msk |
TWI_INTENSET_TXDSENT_Msk |
TWI_INTENSET_ERROR_Msk |
TWI_INTENSET_BB_Msk |
TWI_INTENSET_SUSPENDED_Msk ///< All TWI interrupts.
} nrf_twi_int_mask_t;
/** @brief TWI error source. */
typedef enum
{
NRF_TWI_ERROR_ADDRESS_NACK = TWI_ERRORSRC_ANACK_Msk, ///< NACK received after sending the address.
NRF_TWI_ERROR_DATA_NACK = TWI_ERRORSRC_DNACK_Msk, ///< NACK received after sending a data byte.
NRF_TWI_ERROR_OVERRUN = TWI_ERRORSRC_OVERRUN_Msk ///< Overrun error.
/**< A new byte was received before the previous byte was read
* from the RXD register (previous data is lost). */
} nrf_twi_error_t;
/** @brief TWI master clock frequency. */
typedef enum
{
NRF_TWI_FREQ_100K = TWI_FREQUENCY_FREQUENCY_K100, ///< 100 kbps.
NRF_TWI_FREQ_250K = TWI_FREQUENCY_FREQUENCY_K250, ///< 250 kbps.
NRF_TWI_FREQ_400K = TWI_FREQUENCY_FREQUENCY_K400 ///< 400 kbps.
} nrf_twi_frequency_t;
/**
* @brief Function for activating the specified TWI task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task to be activated.
*/
__STATIC_INLINE void nrf_twi_task_trigger(NRF_TWI_Type * p_reg,
nrf_twi_task_t task);
/**
* @brief Function for getting the address of the specified TWI task register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task The specified task.
*
* @return Address of the specified task register.
*/
__STATIC_INLINE uint32_t * nrf_twi_task_address_get(NRF_TWI_Type * p_reg,
nrf_twi_task_t task);
/**
* @brief Function for clearing the specified TWI event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to clear.
*/
__STATIC_INLINE void nrf_twi_event_clear(NRF_TWI_Type * p_reg,
nrf_twi_event_t event);
/**
* @brief Function for retrieving the state of the TWI event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be checked.
*
* @retval true The event has been generated.
* @retval false The event has not been generated.
*/
__STATIC_INLINE bool nrf_twi_event_check(NRF_TWI_Type * p_reg,
nrf_twi_event_t event);
/**
* @brief Function for getting the address of the specified TWI event register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event The specified event.
*
* @return Address of the specified event register.
*/
__STATIC_INLINE uint32_t * nrf_twi_event_address_get(NRF_TWI_Type * p_reg,
nrf_twi_event_t event);
/**
* @brief Function for enabling the specified shortcuts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Shortcuts to be enabled.
*/
__STATIC_INLINE void nrf_twi_shorts_enable(NRF_TWI_Type * p_reg,
uint32_t mask);
/**
* @brief Function for disabling the specified shortcuts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Shortcuts to be disabled.
*/
__STATIC_INLINE void nrf_twi_shorts_disable(NRF_TWI_Type * p_reg,
uint32_t mask);
/**
* @brief Function for enabling the specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of interrupts to be enabled.
*/
__STATIC_INLINE void nrf_twi_int_enable(NRF_TWI_Type * p_reg,
uint32_t mask);
/**
* @brief Function for disabling the specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of interrupts to be disabled.
*/
__STATIC_INLINE void nrf_twi_int_disable(NRF_TWI_Type * p_reg,
uint32_t mask);
/**
* @brief Function for retrieving the state of a given interrupt.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] twi_int Interrupt to be checked.
*
* @retval true The interrupt is enabled.
* @retval false The interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_twi_int_enable_check(NRF_TWI_Type * p_reg,
nrf_twi_int_mask_t twi_int);
/**
* @brief Function for enabling the TWI peripheral.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_twi_enable(NRF_TWI_Type * p_reg);
/**
* @brief Function for disabling the TWI peripheral.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_twi_disable(NRF_TWI_Type * p_reg);
/**
* @brief Function for configuring TWI pins.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] scl_pin SCL pin number.
* @param[in] sda_pin SDA pin number.
*/
__STATIC_INLINE void nrf_twi_pins_set(NRF_TWI_Type * p_reg,
uint32_t scl_pin,
uint32_t sda_pin);
/**
* @brief Function for retrieving the SCL pin number.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return SCL pin number.
*/
__STATIC_INLINE uint32_t nrf_twi_scl_pin_get(NRF_TWI_Type * p_reg);
/**
* @brief Function for retrieving the SDA pin number.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return SDA pin number.
*/
__STATIC_INLINE uint32_t nrf_twi_sda_pin_get(NRF_TWI_Type * p_reg);
/**
* @brief Function for setting the TWI master clock frequency.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] frequency TWI frequency.
*/
__STATIC_INLINE void nrf_twi_frequency_set(NRF_TWI_Type * p_reg,
nrf_twi_frequency_t frequency);
/**
* @brief Function for checking the TWI error source.
*
* The error flags are cleared after reading.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Mask with error source flags.
*/
__STATIC_INLINE uint32_t nrf_twi_errorsrc_get_and_clear(NRF_TWI_Type * p_reg);
/**
* @brief Function for setting the address to be used in TWI transfers.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] address Address to be used in transfers.
*/
__STATIC_INLINE void nrf_twi_address_set(NRF_TWI_Type * p_reg, uint8_t address);
/**
* @brief Function for reading data received by TWI.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Received data.
*/
__STATIC_INLINE uint8_t nrf_twi_rxd_get(NRF_TWI_Type * p_reg);
/**
* @brief Function for writing data to be transmitted by TWI.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] data Data to be transmitted.
*/
__STATIC_INLINE void nrf_twi_txd_set(NRF_TWI_Type * p_reg, uint8_t data);
/**
* @brief Function for setting the specified shortcuts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Shortcuts to be set.
*/
__STATIC_INLINE void nrf_twi_shorts_set(NRF_TWI_Type * p_reg,
uint32_t mask);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_twi_task_trigger(NRF_TWI_Type * p_reg,
nrf_twi_task_t task)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)task)) = 0x1UL;
}
__STATIC_INLINE uint32_t * nrf_twi_task_address_get(NRF_TWI_Type * p_reg,
nrf_twi_task_t task)
{
return (uint32_t *)((uint8_t *)p_reg + (uint32_t)task);
}
__STATIC_INLINE void nrf_twi_event_clear(NRF_TWI_Type * p_reg,
nrf_twi_event_t event)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0x0UL;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event));
(void)dummy;
#endif
}
__STATIC_INLINE bool nrf_twi_event_check(NRF_TWI_Type * p_reg,
nrf_twi_event_t event)
{
return (bool)*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE uint32_t * nrf_twi_event_address_get(NRF_TWI_Type * p_reg,
nrf_twi_event_t event)
{
return (uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE void nrf_twi_shorts_enable(NRF_TWI_Type * p_reg,
uint32_t mask)
{
p_reg->SHORTS |= mask;
}
__STATIC_INLINE void nrf_twi_shorts_disable(NRF_TWI_Type * p_reg,
uint32_t mask)
{
p_reg->SHORTS &= ~(mask);
}
__STATIC_INLINE void nrf_twi_int_enable(NRF_TWI_Type * p_reg,
uint32_t mask)
{
p_reg->INTENSET = mask;
}
__STATIC_INLINE void nrf_twi_int_disable(NRF_TWI_Type * p_reg,
uint32_t mask)
{
p_reg->INTENCLR = mask;
}
__STATIC_INLINE bool nrf_twi_int_enable_check(NRF_TWI_Type * p_reg,
nrf_twi_int_mask_t twi_int)
{
return (bool)(p_reg->INTENSET & twi_int);
}
__STATIC_INLINE void nrf_twi_enable(NRF_TWI_Type * p_reg)
{
p_reg->ENABLE = (TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos);
}
__STATIC_INLINE void nrf_twi_disable(NRF_TWI_Type * p_reg)
{
p_reg->ENABLE = (TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos);
}
__STATIC_INLINE void nrf_twi_pins_set(NRF_TWI_Type * p_reg,
uint32_t scl_pin,
uint32_t sda_pin)
{
#if defined(TWI_PSEL_SCL_CONNECT_Pos)
p_reg->PSEL.SCL = scl_pin;
#else
p_reg->PSELSCL = scl_pin;
#endif
#if defined(TWI_PSEL_SDA_CONNECT_Pos)
p_reg->PSEL.SDA = sda_pin;
#else
p_reg->PSELSDA = sda_pin;
#endif
}
__STATIC_INLINE uint32_t nrf_twi_scl_pin_get(NRF_TWI_Type * p_reg)
{
#if defined(TWI_PSEL_SCL_CONNECT_Pos)
return p_reg->PSEL.SCL;
#else
return p_reg->PSELSCL;
#endif
}
__STATIC_INLINE uint32_t nrf_twi_sda_pin_get(NRF_TWI_Type * p_reg)
{
#if defined(TWI_PSEL_SDA_CONNECT_Pos)
return p_reg->PSEL.SDA;
#else
return p_reg->PSELSDA;
#endif
}
__STATIC_INLINE void nrf_twi_frequency_set(NRF_TWI_Type * p_reg,
nrf_twi_frequency_t frequency)
{
p_reg->FREQUENCY = frequency;
}
__STATIC_INLINE uint32_t nrf_twi_errorsrc_get_and_clear(NRF_TWI_Type * p_reg)
{
uint32_t error_source = p_reg->ERRORSRC;
// [error flags are cleared by writing '1' on their position]
p_reg->ERRORSRC = error_source;
return error_source;
}
__STATIC_INLINE void nrf_twi_address_set(NRF_TWI_Type * p_reg, uint8_t address)
{
p_reg->ADDRESS = address;
}
__STATIC_INLINE uint8_t nrf_twi_rxd_get(NRF_TWI_Type * p_reg)
{
return (uint8_t)p_reg->RXD;
}
__STATIC_INLINE void nrf_twi_txd_set(NRF_TWI_Type * p_reg, uint8_t data)
{
p_reg->TXD = data;
}
__STATIC_INLINE void nrf_twi_shorts_set(NRF_TWI_Type * p_reg,
uint32_t mask)
{
p_reg->SHORTS = mask;
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_TWI_H__
+619
View File
@@ -0,0 +1,619 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_TWIM_H__
#define NRF_TWIM_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_twim_hal TWIM HAL
* @{
* @ingroup nrf_twim
* @brief Hardware access layer for managing the TWIM peripheral.
*/
/** @brief TWIM tasks. */
typedef enum
{
NRF_TWIM_TASK_STARTRX = offsetof(NRF_TWIM_Type, TASKS_STARTRX), ///< Start TWI receive sequence.
NRF_TWIM_TASK_STARTTX = offsetof(NRF_TWIM_Type, TASKS_STARTTX), ///< Start TWI transmit sequence.
NRF_TWIM_TASK_STOP = offsetof(NRF_TWIM_Type, TASKS_STOP), ///< Stop TWI transaction.
NRF_TWIM_TASK_SUSPEND = offsetof(NRF_TWIM_Type, TASKS_SUSPEND), ///< Suspend TWI transaction.
NRF_TWIM_TASK_RESUME = offsetof(NRF_TWIM_Type, TASKS_RESUME) ///< Resume TWI transaction.
} nrf_twim_task_t;
/** @brief TWIM events. */
typedef enum
{
NRF_TWIM_EVENT_STOPPED = offsetof(NRF_TWIM_Type, EVENTS_STOPPED), ///< TWI stopped.
NRF_TWIM_EVENT_ERROR = offsetof(NRF_TWIM_Type, EVENTS_ERROR), ///< TWI error.
NRF_TWIM_EVENT_SUSPENDED = 0x148, ///< TWI suspended.
NRF_TWIM_EVENT_RXSTARTED = offsetof(NRF_TWIM_Type, EVENTS_RXSTARTED), ///< Receive sequence started.
NRF_TWIM_EVENT_TXSTARTED = offsetof(NRF_TWIM_Type, EVENTS_TXSTARTED), ///< Transmit sequence started.
NRF_TWIM_EVENT_LASTRX = offsetof(NRF_TWIM_Type, EVENTS_LASTRX), ///< Byte boundary, starting to receive the last byte.
NRF_TWIM_EVENT_LASTTX = offsetof(NRF_TWIM_Type, EVENTS_LASTTX) ///< Byte boundary, starting to transmit the last byte.
} nrf_twim_event_t;
/** @brief TWIM shortcuts. */
typedef enum
{
NRF_TWIM_SHORT_LASTTX_STARTRX_MASK = TWIM_SHORTS_LASTTX_STARTRX_Msk, ///< Shortcut between LASTTX event and STARTRX task.
NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK = TWIM_SHORTS_LASTTX_SUSPEND_Msk, ///< Shortcut between LASTTX event and SUSPEND task.
NRF_TWIM_SHORT_LASTTX_STOP_MASK = TWIM_SHORTS_LASTTX_STOP_Msk, ///< Shortcut between LASTTX event and STOP task.
NRF_TWIM_SHORT_LASTRX_STARTTX_MASK = TWIM_SHORTS_LASTRX_STARTTX_Msk, ///< Shortcut between LASTRX event and STARTTX task.
NRF_TWIM_SHORT_LASTRX_STOP_MASK = TWIM_SHORTS_LASTRX_STOP_Msk, ///< Shortcut between LASTRX event and STOP task.
NRF_TWIM_ALL_SHORTS_MASK = TWIM_SHORTS_LASTTX_STARTRX_Msk |
TWIM_SHORTS_LASTTX_SUSPEND_Msk |
TWIM_SHORTS_LASTTX_STOP_Msk |
TWIM_SHORTS_LASTRX_STARTTX_Msk |
TWIM_SHORTS_LASTRX_STOP_Msk ///< All TWIM shortcuts.
} nrf_twim_short_mask_t;
/** @brief TWIM interrupts. */
typedef enum
{
NRF_TWIM_INT_STOPPED_MASK = TWIM_INTENSET_STOPPED_Msk, ///< Interrupt on STOPPED event.
NRF_TWIM_INT_ERROR_MASK = TWIM_INTENSET_ERROR_Msk, ///< Interrupt on ERROR event.
NRF_TWIM_INT_SUSPENDED_MASK = TWIM_INTENSET_SUSPENDED_Msk, ///< Interrupt on SUSPENDED event.
NRF_TWIM_INT_RXSTARTED_MASK = TWIM_INTENSET_RXSTARTED_Msk, ///< Interrupt on RXSTARTED event.
NRF_TWIM_INT_TXSTARTED_MASK = TWIM_INTENSET_TXSTARTED_Msk, ///< Interrupt on TXSTARTED event.
NRF_TWIM_INT_LASTRX_MASK = TWIM_INTENSET_LASTRX_Msk, ///< Interrupt on LASTRX event.
NRF_TWIM_INT_LASTTX_MASK = TWIM_INTENSET_LASTTX_Msk, ///< Interrupt on LASTTX event.
NRF_TWIM_ALL_INTS_MASK = TWIM_INTENSET_STOPPED_Msk |
TWIM_INTENSET_ERROR_Msk |
TWIM_INTENSET_SUSPENDED_Msk |
TWIM_INTENSET_RXSTARTED_Msk |
TWIM_INTENSET_TXSTARTED_Msk |
TWIM_INTENSET_LASTRX_Msk |
TWIM_INTENSET_LASTTX_Msk ///< All TWIM interrupts.
} nrf_twim_int_mask_t;
/** @brief TWIM master clock frequency. */
typedef enum
{
NRF_TWIM_FREQ_100K = TWIM_FREQUENCY_FREQUENCY_K100, ///< 100 kbps.
NRF_TWIM_FREQ_250K = TWIM_FREQUENCY_FREQUENCY_K250, ///< 250 kbps.
NRF_TWIM_FREQ_400K = TWIM_FREQUENCY_FREQUENCY_K400 ///< 400 kbps.
} nrf_twim_frequency_t;
/** @brief TWIM error source. */
typedef enum
{
NRF_TWIM_ERROR_ADDRESS_NACK = TWIM_ERRORSRC_ANACK_Msk, ///< NACK received after sending the address.
NRF_TWIM_ERROR_DATA_NACK = TWIM_ERRORSRC_DNACK_Msk, ///< NACK received after sending a data byte.
NRF_TWIM_ERROR_OVERRUN = TWIM_ERRORSRC_OVERRUN_Msk ///< Overrun error.
/**< A new byte was received before the previous byte was
* handled by peripheral. (previous data is lost). */
} nrf_twim_error_t;
/**
* @brief Function for activating the specified TWIM task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task to be activated.
*/
__STATIC_INLINE void nrf_twim_task_trigger(NRF_TWIM_Type * p_reg,
nrf_twim_task_t task);
/**
* @brief Function for getting the address of the specified TWIM task register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task The specified task.
*
* @return Address of the specified task register.
*/
__STATIC_INLINE uint32_t * nrf_twim_task_address_get(NRF_TWIM_Type * p_reg,
nrf_twim_task_t task);
/**
* @brief Function for clearing the specified TWIM event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to clear.
*/
__STATIC_INLINE void nrf_twim_event_clear(NRF_TWIM_Type * p_reg,
nrf_twim_event_t event);
/**
* @brief Function for retrieving the state of the TWIM event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be checked.
*
* @retval true The event has been generated.
* @retval false The event has not been generated.
*/
__STATIC_INLINE bool nrf_twim_event_check(NRF_TWIM_Type * p_reg,
nrf_twim_event_t event);
/**
* @brief Function for getting the address of the specified TWIM event register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event The specified event.
*
* @return Address of the specified event register.
*/
__STATIC_INLINE uint32_t * nrf_twim_event_address_get(NRF_TWIM_Type * p_reg,
nrf_twim_event_t event);
/**
* @brief Function for enabling the specified shortcuts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Shortcuts to be enabled.
*/
__STATIC_INLINE void nrf_twim_shorts_enable(NRF_TWIM_Type * p_reg,
uint32_t mask);
/**
* @brief Function for disabling the specified shortcuts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Shortcuts to be disabled.
*/
__STATIC_INLINE void nrf_twim_shorts_disable(NRF_TWIM_Type * p_reg,
uint32_t mask);
/**
* @brief Function for enabling the specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of interrupts to be enabled.
*/
__STATIC_INLINE void nrf_twim_int_enable(NRF_TWIM_Type * p_reg,
uint32_t mask);
/**
* @brief Function for disabling the specified interrupts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Mask of interrupts to be disabled.
*/
__STATIC_INLINE void nrf_twim_int_disable(NRF_TWIM_Type * p_reg,
uint32_t mask);
/**
* @brief Function for checking the state of a given interrupt.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] twim_int Interrupt to be checked.
*
* @retval true The interrupt is enabled.
* @retval false The interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_twim_int_enable_check(NRF_TWIM_Type * p_reg,
nrf_twim_int_mask_t twim_int);
#if defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting the subscribe configuration for a given
* TWIM task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task for which to set the configuration.
* @param[in] channel Channel through which to subscribe events.
*/
__STATIC_INLINE void nrf_twim_subscribe_set(NRF_TWIM_Type * p_reg,
nrf_twim_task_t task,
uint8_t channel);
/**
* @brief Function for clearing the subscribe configuration for a given
* TWIM task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task for which to clear the configuration.
*/
__STATIC_INLINE void nrf_twim_subscribe_clear(NRF_TWIM_Type * p_reg,
nrf_twim_task_t task);
/**
* @brief Function for setting the publish configuration for a given
* TWIM event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event for which to set the configuration.
* @param[in] channel Channel through which to publish the event.
*/
__STATIC_INLINE void nrf_twim_publish_set(NRF_TWIM_Type * p_reg,
nrf_twim_event_t event,
uint8_t channel);
/**
* @brief Function for clearing the publish configuration for a given
* TWIM event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event for which to clear the configuration.
*/
__STATIC_INLINE void nrf_twim_publish_clear(NRF_TWIM_Type * p_reg,
nrf_twim_event_t event);
#endif // defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for enabling the TWIM peripheral.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_twim_enable(NRF_TWIM_Type * p_reg);
/**
* @brief Function for disabling the TWIM peripheral.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_twim_disable(NRF_TWIM_Type * p_reg);
/**
* @brief Function for configuring TWI pins.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] scl_pin SCL pin number.
* @param[in] sda_pin SDA pin number.
*/
__STATIC_INLINE void nrf_twim_pins_set(NRF_TWIM_Type * p_reg,
uint32_t scl_pin,
uint32_t sda_pin);
/**
* @brief Function for setting the TWI master clock frequency.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] frequency TWI frequency.
*/
__STATIC_INLINE void nrf_twim_frequency_set(NRF_TWIM_Type * p_reg,
nrf_twim_frequency_t frequency);
/**
* @brief Function for checking the TWI error source.
*
* The error flags are cleared after reading.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Mask with error source flags.
*/
__STATIC_INLINE uint32_t nrf_twim_errorsrc_get_and_clear(NRF_TWIM_Type * p_reg);
/**
* @brief Function for setting the address to be used in TWI transfers.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] address Address to be used in transfers.
*/
__STATIC_INLINE void nrf_twim_address_set(NRF_TWIM_Type * p_reg,
uint8_t address);
/**
* @brief Function for setting the transmit buffer.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] p_buffer Pointer to the buffer with data to send.
* @param[in] length Maximum number of data bytes to transmit.
*/
__STATIC_INLINE void nrf_twim_tx_buffer_set(NRF_TWIM_Type * p_reg,
uint8_t const * p_buffer,
size_t length);
/**
* @brief Function for setting the receive buffer.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] p_buffer Pointer to the buffer for received data.
* @param[in] length Maximum number of data bytes to receive.
*/
__STATIC_INLINE void nrf_twim_rx_buffer_set(NRF_TWIM_Type * p_reg,
uint8_t * p_buffer,
size_t length);
/**
* @brief Function for setting the specified shortcuts.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] mask Shortcuts to be set.
*/
__STATIC_INLINE void nrf_twim_shorts_set(NRF_TWIM_Type * p_reg,
uint32_t mask);
/**
* @brief Function for getting the shortcut setting.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Current shortcut configuration.
*/
__STATIC_INLINE uint32_t nrf_twim_shorts_get(NRF_TWIM_Type const * p_reg);
/**
* @brief Function for getting the amount of transmitted bytes.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Amount of transmitted bytes.
*/
__STATIC_INLINE size_t nrf_twim_txd_amount_get(NRF_TWIM_Type * p_reg);
/**
* @brief Function for getting the amount of received bytes.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @return Amount of received bytes.
*/
__STATIC_INLINE size_t nrf_twim_rxd_amount_get(NRF_TWIM_Type * p_reg);
/**
* @brief Function for enabling the TX list feature.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_twim_tx_list_enable(NRF_TWIM_Type * p_reg);
/**
* @brief Function for disabling the TX list feature.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_twim_tx_list_disable(NRF_TWIM_Type * p_reg);
/**
* @brief Function for enabling the RX list feature.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_twim_rx_list_enable(NRF_TWIM_Type * p_reg);
/**
* @brief Function for disabling the RX list feature.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_twim_rx_list_disable(NRF_TWIM_Type * p_reg);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_twim_task_trigger(NRF_TWIM_Type * p_reg,
nrf_twim_task_t task)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)task)) = 0x1UL;
}
__STATIC_INLINE uint32_t * nrf_twim_task_address_get(NRF_TWIM_Type * p_reg,
nrf_twim_task_t task)
{
return (uint32_t *)((uint8_t *)p_reg + (uint32_t)task);
}
__STATIC_INLINE void nrf_twim_event_clear(NRF_TWIM_Type * p_reg,
nrf_twim_event_t event)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0x0UL;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event));
(void)dummy;
#endif
}
__STATIC_INLINE bool nrf_twim_event_check(NRF_TWIM_Type * p_reg,
nrf_twim_event_t event)
{
return (bool)*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE uint32_t * nrf_twim_event_address_get(NRF_TWIM_Type * p_reg,
nrf_twim_event_t event)
{
return (uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE void nrf_twim_shorts_enable(NRF_TWIM_Type * p_reg,
uint32_t mask)
{
p_reg->SHORTS |= mask;
}
__STATIC_INLINE void nrf_twim_shorts_disable(NRF_TWIM_Type * p_reg,
uint32_t mask)
{
p_reg->SHORTS &= ~(mask);
}
__STATIC_INLINE void nrf_twim_int_enable(NRF_TWIM_Type * p_reg,
uint32_t mask)
{
p_reg->INTENSET = mask;
}
__STATIC_INLINE void nrf_twim_int_disable(NRF_TWIM_Type * p_reg,
uint32_t mask)
{
p_reg->INTENCLR = mask;
}
__STATIC_INLINE bool nrf_twim_int_enable_check(NRF_TWIM_Type * p_reg,
nrf_twim_int_mask_t twim_int)
{
return (bool)(p_reg->INTENSET & twim_int);
}
#if defined(DPPI_PRESENT)
__STATIC_INLINE void nrf_twim_subscribe_set(NRF_TWIM_Type * p_reg,
nrf_twim_task_t task,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) task + 0x80uL)) =
((uint32_t)channel | TWIM_SUBSCRIBE_STARTRX_EN_Msk);
}
__STATIC_INLINE void nrf_twim_subscribe_clear(NRF_TWIM_Type * p_reg,
nrf_twim_task_t task)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) task + 0x80uL)) = 0;
}
__STATIC_INLINE void nrf_twim_publish_set(NRF_TWIM_Type * p_reg,
nrf_twim_event_t event,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) event + 0x80uL)) =
((uint32_t)channel | TWIM_PUBLISH_STOPPED_EN_Msk);
}
__STATIC_INLINE void nrf_twim_publish_clear(NRF_TWIM_Type * p_reg,
nrf_twim_event_t event)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) event + 0x80uL)) = 0;
}
#endif // defined(DPPI_PRESENT)
__STATIC_INLINE void nrf_twim_enable(NRF_TWIM_Type * p_reg)
{
p_reg->ENABLE = (TWIM_ENABLE_ENABLE_Enabled << TWIM_ENABLE_ENABLE_Pos);
}
__STATIC_INLINE void nrf_twim_disable(NRF_TWIM_Type * p_reg)
{
p_reg->ENABLE = (TWIM_ENABLE_ENABLE_Disabled << TWIM_ENABLE_ENABLE_Pos);
}
__STATIC_INLINE void nrf_twim_pins_set(NRF_TWIM_Type * p_reg,
uint32_t scl_pin,
uint32_t sda_pin)
{
p_reg->PSEL.SCL = scl_pin;
p_reg->PSEL.SDA = sda_pin;
}
__STATIC_INLINE void nrf_twim_frequency_set(NRF_TWIM_Type * p_reg,
nrf_twim_frequency_t frequency)
{
p_reg->FREQUENCY = frequency;
}
__STATIC_INLINE uint32_t nrf_twim_errorsrc_get_and_clear(NRF_TWIM_Type * p_reg)
{
uint32_t error_source = p_reg->ERRORSRC;
// [error flags are cleared by writing '1' on their position]
p_reg->ERRORSRC = error_source;
return error_source;
}
__STATIC_INLINE void nrf_twim_address_set(NRF_TWIM_Type * p_reg,
uint8_t address)
{
p_reg->ADDRESS = address;
}
__STATIC_INLINE void nrf_twim_tx_buffer_set(NRF_TWIM_Type * p_reg,
uint8_t const * p_buffer,
size_t length)
{
p_reg->TXD.PTR = (uint32_t)p_buffer;
p_reg->TXD.MAXCNT = length;
}
__STATIC_INLINE void nrf_twim_rx_buffer_set(NRF_TWIM_Type * p_reg,
uint8_t * p_buffer,
size_t length)
{
p_reg->RXD.PTR = (uint32_t)p_buffer;
p_reg->RXD.MAXCNT = length;
}
__STATIC_INLINE void nrf_twim_shorts_set(NRF_TWIM_Type * p_reg,
uint32_t mask)
{
p_reg->SHORTS = mask;
}
__STATIC_INLINE size_t nrf_twim_txd_amount_get(NRF_TWIM_Type * p_reg)
{
return p_reg->TXD.AMOUNT;
}
__STATIC_INLINE uint32_t nrf_twim_shorts_get(NRF_TWIM_Type const * p_reg)
{
return p_reg->SHORTS;
}
__STATIC_INLINE size_t nrf_twim_rxd_amount_get(NRF_TWIM_Type * p_reg)
{
return p_reg->RXD.AMOUNT;
}
__STATIC_INLINE void nrf_twim_tx_list_enable(NRF_TWIM_Type * p_reg)
{
p_reg->TXD.LIST = 1;
}
__STATIC_INLINE void nrf_twim_tx_list_disable(NRF_TWIM_Type * p_reg)
{
p_reg->TXD.LIST = 0;
}
__STATIC_INLINE void nrf_twim_rx_list_enable(NRF_TWIM_Type * p_reg)
{
p_reg->RXD.LIST = 1;
}
__STATIC_INLINE void nrf_twim_rx_list_disable(NRF_TWIM_Type * p_reg)
{
p_reg->RXD.LIST = 0;
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_TWIM_H__
+511
View File
@@ -0,0 +1,511 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_UART_H__
#define NRF_UART_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_uart_hal UART HAL
* @{
* @ingroup nrf_uart
* @brief Hardware access layer for managing the UART peripheral.
*/
/** @brief Pin disconnected value. */
#define NRF_UART_PSEL_DISCONNECTED 0xFFFFFFFF
/** @brief UART tasks. */
typedef enum
{
NRF_UART_TASK_STARTRX = offsetof(NRF_UART_Type, TASKS_STARTRX), /**< Task for starting reception. */
NRF_UART_TASK_STOPRX = offsetof(NRF_UART_Type, TASKS_STOPRX), /**< Task for stopping reception. */
NRF_UART_TASK_STARTTX = offsetof(NRF_UART_Type, TASKS_STARTTX), /**< Task for starting transmission. */
NRF_UART_TASK_STOPTX = offsetof(NRF_UART_Type, TASKS_STOPTX), /**< Task for stopping transmission. */
NRF_UART_TASK_SUSPEND = offsetof(NRF_UART_Type, TASKS_SUSPEND), /**< Task for suspending UART. */
} nrf_uart_task_t;
/** @brief UART events. */
typedef enum
{
NRF_UART_EVENT_CTS = offsetof(NRF_UART_Type, EVENTS_CTS), /**< Event from CTS line activation. */
NRF_UART_EVENT_NCTS = offsetof(NRF_UART_Type, EVENTS_NCTS), /**< Event from CTS line deactivation. */
NRF_UART_EVENT_RXDRDY = offsetof(NRF_UART_Type, EVENTS_RXDRDY),/**< Event from data ready in RXD. */
NRF_UART_EVENT_TXDRDY = offsetof(NRF_UART_Type, EVENTS_TXDRDY),/**< Event from data sent from TXD. */
NRF_UART_EVENT_ERROR = offsetof(NRF_UART_Type, EVENTS_ERROR), /**< Event from error detection. */
NRF_UART_EVENT_RXTO = offsetof(NRF_UART_Type, EVENTS_RXTO) /**< Event from receiver timeout. */
} nrf_uart_event_t;
/** @brief UART interrupts. */
typedef enum
{
NRF_UART_INT_MASK_CTS = UART_INTENCLR_CTS_Msk, /**< CTS line activation interrupt. */
NRF_UART_INT_MASK_NCTS = UART_INTENCLR_NCTS_Msk, /**< CTS line deactivation interrupt. */
NRF_UART_INT_MASK_RXDRDY = UART_INTENCLR_RXDRDY_Msk, /**< Data ready in RXD interrupt. */
NRF_UART_INT_MASK_TXDRDY = UART_INTENCLR_TXDRDY_Msk, /**< Data sent from TXD interrupt. */
NRF_UART_INT_MASK_ERROR = UART_INTENCLR_ERROR_Msk, /**< Error detection interrupt. */
NRF_UART_INT_MASK_RXTO = UART_INTENCLR_RXTO_Msk /**< Receiver timeout interrupt. */
} nrf_uart_int_mask_t;
/** @brief Baudrates supported by UART. */
typedef enum
{
NRF_UART_BAUDRATE_1200 = UART_BAUDRATE_BAUDRATE_Baud1200, /**< 1200 baud. */
NRF_UART_BAUDRATE_2400 = UART_BAUDRATE_BAUDRATE_Baud2400, /**< 2400 baud. */
NRF_UART_BAUDRATE_4800 = UART_BAUDRATE_BAUDRATE_Baud4800, /**< 4800 baud. */
NRF_UART_BAUDRATE_9600 = UART_BAUDRATE_BAUDRATE_Baud9600, /**< 9600 baud. */
NRF_UART_BAUDRATE_14400 = UART_BAUDRATE_BAUDRATE_Baud14400, /**< 14400 baud. */
NRF_UART_BAUDRATE_19200 = UART_BAUDRATE_BAUDRATE_Baud19200, /**< 19200 baud. */
NRF_UART_BAUDRATE_28800 = UART_BAUDRATE_BAUDRATE_Baud28800, /**< 28800 baud. */
NRF_UART_BAUDRATE_31250 = UART_BAUDRATE_BAUDRATE_Baud31250, /**< 31250 baud. */
NRF_UART_BAUDRATE_38400 = UART_BAUDRATE_BAUDRATE_Baud38400, /**< 38400 baud. */
NRF_UART_BAUDRATE_56000 = UART_BAUDRATE_BAUDRATE_Baud56000, /**< 56000 baud. */
NRF_UART_BAUDRATE_57600 = UART_BAUDRATE_BAUDRATE_Baud57600, /**< 57600 baud. */
NRF_UART_BAUDRATE_76800 = UART_BAUDRATE_BAUDRATE_Baud76800, /**< 76800 baud. */
NRF_UART_BAUDRATE_115200 = UART_BAUDRATE_BAUDRATE_Baud115200, /**< 115200 baud. */
NRF_UART_BAUDRATE_230400 = UART_BAUDRATE_BAUDRATE_Baud230400, /**< 230400 baud. */
NRF_UART_BAUDRATE_250000 = UART_BAUDRATE_BAUDRATE_Baud250000, /**< 250000 baud. */
NRF_UART_BAUDRATE_460800 = UART_BAUDRATE_BAUDRATE_Baud460800, /**< 460800 baud. */
NRF_UART_BAUDRATE_921600 = UART_BAUDRATE_BAUDRATE_Baud921600, /**< 921600 baud. */
NRF_UART_BAUDRATE_1000000 = UART_BAUDRATE_BAUDRATE_Baud1M, /**< 1000000 baud. */
} nrf_uart_baudrate_t;
/** @brief Types of UART error masks. */
typedef enum
{
NRF_UART_ERROR_OVERRUN_MASK = UART_ERRORSRC_OVERRUN_Msk, /**< Overrun error. */
NRF_UART_ERROR_PARITY_MASK = UART_ERRORSRC_PARITY_Msk, /**< Parity error. */
NRF_UART_ERROR_FRAMING_MASK = UART_ERRORSRC_FRAMING_Msk, /**< Framing error. */
NRF_UART_ERROR_BREAK_MASK = UART_ERRORSRC_BREAK_Msk, /**< Break error. */
} nrf_uart_error_mask_t;
/** @brief Types of UART parity modes. */
typedef enum
{
NRF_UART_PARITY_EXCLUDED = UART_CONFIG_PARITY_Excluded << UART_CONFIG_PARITY_Pos, /**< Parity excluded. */
NRF_UART_PARITY_INCLUDED = UART_CONFIG_PARITY_Included << UART_CONFIG_PARITY_Pos, /**< Parity included. */
} nrf_uart_parity_t;
/** @brief Types of UART flow control modes. */
typedef enum
{
NRF_UART_HWFC_DISABLED = UART_CONFIG_HWFC_Disabled, /**< Hardware flow control disabled. */
NRF_UART_HWFC_ENABLED = UART_CONFIG_HWFC_Enabled, /**< Hardware flow control enabled. */
} nrf_uart_hwfc_t;
/**
* @brief Function for clearing the specified UART event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to clear.
*/
__STATIC_INLINE void nrf_uart_event_clear(NRF_UART_Type * p_reg, nrf_uart_event_t event);
/**
* @brief Function for retrieving the state of the UART event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be checked.
*
* @retval true The event has been generated.
* @retval false The event has not been generated.
*/
__STATIC_INLINE bool nrf_uart_event_check(NRF_UART_Type * p_reg, nrf_uart_event_t event);
/**
* @brief Function for returning the address of the specified UART event register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Desired event.
*
* @return Address of the specified event register.
*/
__STATIC_INLINE uint32_t nrf_uart_event_address_get(NRF_UART_Type * p_reg,
nrf_uart_event_t event);
/**
* @brief Function for enabling the specified interrupt.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param mask Mask of interrupts to be enabled.
*/
__STATIC_INLINE void nrf_uart_int_enable(NRF_UART_Type * p_reg, uint32_t mask);
/**
* @brief Function for retrieving the state of a given interrupt.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param mask Mask of interrupts to be checked.
*
* @retval true The interrupt is enabled.
* @retval false The interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_uart_int_enable_check(NRF_UART_Type * p_reg, uint32_t mask);
/**
* @brief Function for disabling the specified interrupts.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param mask Mask of interrupts to be disabled.
*/
__STATIC_INLINE void nrf_uart_int_disable(NRF_UART_Type * p_reg, uint32_t mask);
/**
* @brief Function for getting error source mask. Function is clearing error source flags after reading.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return Mask with error source flags.
*/
__STATIC_INLINE uint32_t nrf_uart_errorsrc_get_and_clear(NRF_UART_Type * p_reg);
/**
* @brief Function for enabling UART.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_uart_enable(NRF_UART_Type * p_reg);
/**
* @brief Function for disabling UART.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_uart_disable(NRF_UART_Type * p_reg);
/**
* @brief Function for configuring TX/RX pins.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param pseltxd TXD pin number.
* @param pselrxd RXD pin number.
*/
__STATIC_INLINE void nrf_uart_txrx_pins_set(NRF_UART_Type * p_reg, uint32_t pseltxd, uint32_t pselrxd);
/**
* @brief Function for disconnecting TX/RX pins.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_uart_txrx_pins_disconnect(NRF_UART_Type * p_reg);
/**
* @brief Function for getting TX pin.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return TX pin number.
*/
__STATIC_INLINE uint32_t nrf_uart_tx_pin_get(NRF_UART_Type * p_reg);
/**
* @brief Function for getting RX pin.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return RX pin number.
*/
__STATIC_INLINE uint32_t nrf_uart_rx_pin_get(NRF_UART_Type * p_reg);
/**
* @brief Function for getting RTS pin.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return RTS pin number.
*/
__STATIC_INLINE uint32_t nrf_uart_rts_pin_get(NRF_UART_Type * p_reg);
/**
* @brief Function for getting CTS pin.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return CTS pin number.
*/
__STATIC_INLINE uint32_t nrf_uart_cts_pin_get(NRF_UART_Type * p_reg);
/**
* @brief Function for configuring flow control pins.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param pselrts RTS pin number.
* @param pselcts CTS pin number.
*/
__STATIC_INLINE void nrf_uart_hwfc_pins_set(NRF_UART_Type * p_reg,
uint32_t pselrts,
uint32_t pselcts);
/**
* @brief Function for disconnecting flow control pins.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_uart_hwfc_pins_disconnect(NRF_UART_Type * p_reg);
/**
* @brief Function for reading RX data.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return Received byte.
*/
__STATIC_INLINE uint8_t nrf_uart_rxd_get(NRF_UART_Type * p_reg);
/**
* @brief Function for setting Tx data.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param txd Byte.
*/
__STATIC_INLINE void nrf_uart_txd_set(NRF_UART_Type * p_reg, uint8_t txd);
/**
* @brief Function for starting an UART task.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param task Task.
*/
__STATIC_INLINE void nrf_uart_task_trigger(NRF_UART_Type * p_reg, nrf_uart_task_t task);
/**
* @brief Function for returning the address of the specified task register.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param task Task.
*
* @return Task address.
*/
__STATIC_INLINE uint32_t nrf_uart_task_address_get(NRF_UART_Type * p_reg, nrf_uart_task_t task);
/**
* @brief Function for configuring UART.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param hwfc Hardware flow control. Enabled if true.
* @param parity Parity. Included if true.
*/
__STATIC_INLINE void nrf_uart_configure(NRF_UART_Type * p_reg,
nrf_uart_parity_t parity,
nrf_uart_hwfc_t hwfc);
/**
* @brief Function for setting UART baud rate.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param baudrate Baud rate.
*/
__STATIC_INLINE void nrf_uart_baudrate_set(NRF_UART_Type * p_reg, nrf_uart_baudrate_t baudrate);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_uart_event_clear(NRF_UART_Type * p_reg, nrf_uart_event_t event)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0x0UL;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event));
(void)dummy;
#endif
}
__STATIC_INLINE bool nrf_uart_event_check(NRF_UART_Type * p_reg, nrf_uart_event_t event)
{
return (bool)*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE uint32_t nrf_uart_event_address_get(NRF_UART_Type * p_reg,
nrf_uart_event_t event)
{
return (uint32_t)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE void nrf_uart_int_enable(NRF_UART_Type * p_reg, uint32_t mask)
{
p_reg->INTENSET = mask;
}
__STATIC_INLINE bool nrf_uart_int_enable_check(NRF_UART_Type * p_reg, uint32_t mask)
{
return (bool)(p_reg->INTENSET & mask);
}
__STATIC_INLINE void nrf_uart_int_disable(NRF_UART_Type * p_reg, uint32_t mask)
{
p_reg->INTENCLR = mask;
}
__STATIC_INLINE uint32_t nrf_uart_errorsrc_get_and_clear(NRF_UART_Type * p_reg)
{
uint32_t errsrc_mask = p_reg->ERRORSRC;
p_reg->ERRORSRC = errsrc_mask;
return errsrc_mask;
}
__STATIC_INLINE void nrf_uart_enable(NRF_UART_Type * p_reg)
{
p_reg->ENABLE = UART_ENABLE_ENABLE_Enabled;
}
__STATIC_INLINE void nrf_uart_disable(NRF_UART_Type * p_reg)
{
p_reg->ENABLE = UART_ENABLE_ENABLE_Disabled;
}
__STATIC_INLINE void nrf_uart_txrx_pins_set(NRF_UART_Type * p_reg, uint32_t pseltxd, uint32_t pselrxd)
{
#if defined(UART_PSEL_RXD_CONNECT_Pos)
p_reg->PSEL.RXD = pselrxd;
#else
p_reg->PSELRXD = pselrxd;
#endif
#if defined(UART_PSEL_TXD_CONNECT_Pos)
p_reg->PSEL.TXD = pseltxd;
#else
p_reg->PSELTXD = pseltxd;
#endif
}
__STATIC_INLINE void nrf_uart_txrx_pins_disconnect(NRF_UART_Type * p_reg)
{
nrf_uart_txrx_pins_set(p_reg, NRF_UART_PSEL_DISCONNECTED, NRF_UART_PSEL_DISCONNECTED);
}
__STATIC_INLINE uint32_t nrf_uart_tx_pin_get(NRF_UART_Type * p_reg)
{
#if defined(UART_PSEL_TXD_CONNECT_Pos)
return p_reg->PSEL.TXD;
#else
return p_reg->PSELTXD;
#endif
}
__STATIC_INLINE uint32_t nrf_uart_rx_pin_get(NRF_UART_Type * p_reg)
{
#if defined(UART_PSEL_RXD_CONNECT_Pos)
return p_reg->PSEL.RXD;
#else
return p_reg->PSELRXD;
#endif
}
__STATIC_INLINE uint32_t nrf_uart_rts_pin_get(NRF_UART_Type * p_reg)
{
#if defined(UART_PSEL_RTS_CONNECT_Pos)
return p_reg->PSEL.RTS;
#else
return p_reg->PSELRTS;
#endif
}
__STATIC_INLINE uint32_t nrf_uart_cts_pin_get(NRF_UART_Type * p_reg)
{
#if defined(UART_PSEL_RTS_CONNECT_Pos)
return p_reg->PSEL.CTS;
#else
return p_reg->PSELCTS;
#endif
}
__STATIC_INLINE void nrf_uart_hwfc_pins_set(NRF_UART_Type * p_reg, uint32_t pselrts, uint32_t pselcts)
{
#if defined(UART_PSEL_RTS_CONNECT_Pos)
p_reg->PSEL.RTS = pselrts;
#else
p_reg->PSELRTS = pselrts;
#endif
#if defined(UART_PSEL_RTS_CONNECT_Pos)
p_reg->PSEL.CTS = pselcts;
#else
p_reg->PSELCTS = pselcts;
#endif
}
__STATIC_INLINE void nrf_uart_hwfc_pins_disconnect(NRF_UART_Type * p_reg)
{
nrf_uart_hwfc_pins_set(p_reg, NRF_UART_PSEL_DISCONNECTED, NRF_UART_PSEL_DISCONNECTED);
}
__STATIC_INLINE uint8_t nrf_uart_rxd_get(NRF_UART_Type * p_reg)
{
return p_reg->RXD;
}
__STATIC_INLINE void nrf_uart_txd_set(NRF_UART_Type * p_reg, uint8_t txd)
{
p_reg->TXD = txd;
}
__STATIC_INLINE void nrf_uart_task_trigger(NRF_UART_Type * p_reg, nrf_uart_task_t task)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)task)) = 0x1UL;
}
__STATIC_INLINE uint32_t nrf_uart_task_address_get(NRF_UART_Type * p_reg, nrf_uart_task_t task)
{
return (uint32_t)p_reg + (uint32_t)task;
}
__STATIC_INLINE void nrf_uart_configure(NRF_UART_Type * p_reg,
nrf_uart_parity_t parity,
nrf_uart_hwfc_t hwfc)
{
p_reg->CONFIG = (uint32_t)parity | (uint32_t)hwfc;
}
__STATIC_INLINE void nrf_uart_baudrate_set(NRF_UART_Type * p_reg, nrf_uart_baudrate_t baudrate)
{
p_reg->BAUDRATE = baudrate;
}
#endif //SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif //NRF_UART_H__
+637
View File
@@ -0,0 +1,637 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_UARTE_H__
#define NRF_UARTE_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
#define NRF_UARTE_PSEL_DISCONNECTED 0xFFFFFFFF
/**
* @defgroup nrf_uarte_hal UARTE HAL
* @{
* @ingroup nrf_uarte
* @brief Hardware access layer for managing the UARTE peripheral.
*/
/** @brief UARTE tasks. */
typedef enum
{
NRF_UARTE_TASK_STARTRX = offsetof(NRF_UARTE_Type, TASKS_STARTRX), ///< Start UART receiver.
NRF_UARTE_TASK_STOPRX = offsetof(NRF_UARTE_Type, TASKS_STOPRX), ///< Stop UART receiver.
NRF_UARTE_TASK_STARTTX = offsetof(NRF_UARTE_Type, TASKS_STARTTX), ///< Start UART transmitter.
NRF_UARTE_TASK_STOPTX = offsetof(NRF_UARTE_Type, TASKS_STOPTX), ///< Stop UART transmitter.
NRF_UARTE_TASK_FLUSHRX = offsetof(NRF_UARTE_Type, TASKS_FLUSHRX) ///< Flush RX FIFO in RX buffer.
} nrf_uarte_task_t;
/** @brief UARTE events. */
typedef enum
{
NRF_UARTE_EVENT_CTS = offsetof(NRF_UARTE_Type, EVENTS_CTS), ///< CTS is activated.
NRF_UARTE_EVENT_NCTS = offsetof(NRF_UARTE_Type, EVENTS_NCTS), ///< CTS is deactivated.
NRF_UARTE_EVENT_RXDRDY = offsetof(NRF_UARTE_Type, EVENTS_RXDRDY), ///< Data received in RXD (but potentially not yet transferred to Data RAM).
NRF_UARTE_EVENT_ENDRX = offsetof(NRF_UARTE_Type, EVENTS_ENDRX), ///< Receive buffer is filled up.
NRF_UARTE_EVENT_TXDRDY = offsetof(NRF_UARTE_Type, EVENTS_TXDRDY), ///< Data sent from TXD.
NRF_UARTE_EVENT_ENDTX = offsetof(NRF_UARTE_Type, EVENTS_ENDTX), ///< Last TX byte transmitted.
NRF_UARTE_EVENT_ERROR = offsetof(NRF_UARTE_Type, EVENTS_ERROR), ///< Error detected.
NRF_UARTE_EVENT_RXTO = offsetof(NRF_UARTE_Type, EVENTS_RXTO), ///< Receiver timeout.
NRF_UARTE_EVENT_RXSTARTED = offsetof(NRF_UARTE_Type, EVENTS_RXSTARTED), ///< Receiver has started.
NRF_UARTE_EVENT_TXSTARTED = offsetof(NRF_UARTE_Type, EVENTS_TXSTARTED), ///< Transmitter has started.
NRF_UARTE_EVENT_TXSTOPPED = offsetof(NRF_UARTE_Type, EVENTS_TXSTOPPED) ///< Transmitted stopped.
} nrf_uarte_event_t;
/** @brief Types of UARTE shortcuts. */
typedef enum
{
NRF_UARTE_SHORT_ENDRX_STARTRX = UARTE_SHORTS_ENDRX_STARTRX_Msk, ///< Shortcut between ENDRX event and STARTRX task.
NRF_UARTE_SHORT_ENDRX_STOPRX = UARTE_SHORTS_ENDRX_STOPRX_Msk ///< Shortcut between ENDRX event and STOPRX task.
} nrf_uarte_short_t;
/** @brief UARTE interrupts. */
typedef enum
{
NRF_UARTE_INT_CTS_MASK = UARTE_INTENSET_CTS_Msk, ///< Interrupt on CTS event.
NRF_UARTE_INT_NCTS_MASK = UARTE_INTENSET_NCTS_Msk, ///< Interrupt on NCTS event.
NRF_UARTE_INT_RXDRDY_MASK = UARTE_INTENSET_RXDRDY_Msk, ///< Interrupt on RXDRDY event.
NRF_UARTE_INT_ENDRX_MASK = UARTE_INTENSET_ENDRX_Msk, ///< Interrupt on ENDRX event.
NRF_UARTE_INT_TXDRDY_MASK = UARTE_INTENSET_TXDRDY_Msk, ///< Interrupt on TXDRDY event.
NRF_UARTE_INT_ENDTX_MASK = UARTE_INTENSET_ENDTX_Msk, ///< Interrupt on ENDTX event.
NRF_UARTE_INT_ERROR_MASK = UARTE_INTENSET_ERROR_Msk, ///< Interrupt on ERROR event.
NRF_UARTE_INT_RXTO_MASK = UARTE_INTENSET_RXTO_Msk, ///< Interrupt on RXTO event.
NRF_UARTE_INT_RXSTARTED_MASK = UARTE_INTENSET_RXSTARTED_Msk, ///< Interrupt on RXSTARTED event.
NRF_UARTE_INT_TXSTARTED_MASK = UARTE_INTENSET_TXSTARTED_Msk, ///< Interrupt on TXSTARTED event.
NRF_UARTE_INT_TXSTOPPED_MASK = UARTE_INTENSET_TXSTOPPED_Msk ///< Interrupt on TXSTOPPED event.
} nrf_uarte_int_mask_t;
/** @brief Baudrates supported by UARTE. */
typedef enum
{
NRF_UARTE_BAUDRATE_1200 = UARTE_BAUDRATE_BAUDRATE_Baud1200, ///< 1200 baud.
NRF_UARTE_BAUDRATE_2400 = UARTE_BAUDRATE_BAUDRATE_Baud2400, ///< 2400 baud.
NRF_UARTE_BAUDRATE_4800 = UARTE_BAUDRATE_BAUDRATE_Baud4800, ///< 4800 baud.
NRF_UARTE_BAUDRATE_9600 = UARTE_BAUDRATE_BAUDRATE_Baud9600, ///< 9600 baud.
NRF_UARTE_BAUDRATE_14400 = UARTE_BAUDRATE_BAUDRATE_Baud14400, ///< 14400 baud.
NRF_UARTE_BAUDRATE_19200 = UARTE_BAUDRATE_BAUDRATE_Baud19200, ///< 19200 baud.
NRF_UARTE_BAUDRATE_28800 = UARTE_BAUDRATE_BAUDRATE_Baud28800, ///< 28800 baud.
NRF_UARTE_BAUDRATE_31250 = UARTE_BAUDRATE_BAUDRATE_Baud31250, ///< 31250 baud.
NRF_UARTE_BAUDRATE_38400 = UARTE_BAUDRATE_BAUDRATE_Baud38400, ///< 38400 baud.
NRF_UARTE_BAUDRATE_56000 = UARTE_BAUDRATE_BAUDRATE_Baud56000, ///< 56000 baud.
NRF_UARTE_BAUDRATE_57600 = UARTE_BAUDRATE_BAUDRATE_Baud57600, ///< 57600 baud.
NRF_UARTE_BAUDRATE_76800 = UARTE_BAUDRATE_BAUDRATE_Baud76800, ///< 76800 baud.
NRF_UARTE_BAUDRATE_115200 = UARTE_BAUDRATE_BAUDRATE_Baud115200, ///< 115200 baud.
NRF_UARTE_BAUDRATE_230400 = UARTE_BAUDRATE_BAUDRATE_Baud230400, ///< 230400 baud.
NRF_UARTE_BAUDRATE_250000 = UARTE_BAUDRATE_BAUDRATE_Baud250000, ///< 250000 baud.
NRF_UARTE_BAUDRATE_460800 = UARTE_BAUDRATE_BAUDRATE_Baud460800, ///< 460800 baud.
NRF_UARTE_BAUDRATE_921600 = UARTE_BAUDRATE_BAUDRATE_Baud921600, ///< 921600 baud.
NRF_UARTE_BAUDRATE_1000000 = UARTE_BAUDRATE_BAUDRATE_Baud1M ///< 1000000 baud.
} nrf_uarte_baudrate_t;
/** @brief Types of UARTE error masks. */
typedef enum
{
NRF_UARTE_ERROR_OVERRUN_MASK = UARTE_ERRORSRC_OVERRUN_Msk, ///< Overrun error.
NRF_UARTE_ERROR_PARITY_MASK = UARTE_ERRORSRC_PARITY_Msk, ///< Parity error.
NRF_UARTE_ERROR_FRAMING_MASK = UARTE_ERRORSRC_FRAMING_Msk, ///< Framing error.
NRF_UARTE_ERROR_BREAK_MASK = UARTE_ERRORSRC_BREAK_Msk ///< Break error.
} nrf_uarte_error_mask_t;
/** @brief Types of UARTE parity modes. */
typedef enum
{
NRF_UARTE_PARITY_EXCLUDED = UARTE_CONFIG_PARITY_Excluded << UARTE_CONFIG_PARITY_Pos, ///< Parity excluded.
NRF_UARTE_PARITY_INCLUDED = UARTE_CONFIG_PARITY_Included << UARTE_CONFIG_PARITY_Pos ///< Parity included.
} nrf_uarte_parity_t;
/** @brief Types of UARTE flow control modes. */
typedef enum
{
NRF_UARTE_HWFC_DISABLED = UARTE_CONFIG_HWFC_Disabled << UARTE_CONFIG_HWFC_Pos, ///< Hardware flow control disabled.
NRF_UARTE_HWFC_ENABLED = UARTE_CONFIG_HWFC_Enabled << UARTE_CONFIG_HWFC_Pos ///< Hardware flow control enabled.
} nrf_uarte_hwfc_t;
/**
* @brief Function for clearing the specified UARTE event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to clear.
*/
__STATIC_INLINE void nrf_uarte_event_clear(NRF_UARTE_Type * p_reg, nrf_uarte_event_t event);
/**
* @brief Function for retrieving the state of the UARTE event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event to be checked.
*
* @retval true The event has been generated.
* @retval false The event has not been generated.
*/
__STATIC_INLINE bool nrf_uarte_event_check(NRF_UARTE_Type * p_reg, nrf_uarte_event_t event);
/**
* @brief Function for returning the address of the specified UARTE event register.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event The specified event.
*
* @return Address of specified event register.
*/
__STATIC_INLINE uint32_t nrf_uarte_event_address_get(NRF_UARTE_Type * p_reg,
nrf_uarte_event_t event);
/**
* @brief Function for enabling UARTE shortcuts.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param mask Shortcuts to be enabled.
*/
__STATIC_INLINE void nrf_uarte_shorts_enable(NRF_UARTE_Type * p_reg, uint32_t mask);
/**
* @brief Function for disabling UARTE shortcuts.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param mask Shortcuts to be disabled.
*/
__STATIC_INLINE void nrf_uarte_shorts_disable(NRF_UARTE_Type * p_reg, uint32_t mask);
/**
* @brief Function for enabling UARTE interrupts.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param mask Mask of interrupts to be enabled.
*/
__STATIC_INLINE void nrf_uarte_int_enable(NRF_UARTE_Type * p_reg, uint32_t mask);
/**
* @brief Function for retrieving the state of the specified interrupt.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param mask Mask of interrupts to be checked.
*
* @retval true The interrupt is enabled.
* @retval false The interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_uarte_int_enable_check(NRF_UARTE_Type * p_reg, nrf_uarte_int_mask_t mask);
/**
* @brief Function for disabling the specified interrupts.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param mask Mask of interrupts to be disabled.
*/
__STATIC_INLINE void nrf_uarte_int_disable(NRF_UARTE_Type * p_reg, uint32_t mask);
#if defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting the subscribe configuration for a given
* UARTE task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task for which to set the configuration.
* @param[in] channel Channel through which to subscribe events.
*/
__STATIC_INLINE void nrf_uarte_subscribe_set(NRF_UARTE_Type * p_reg,
nrf_uarte_task_t task,
uint8_t channel);
/**
* @brief Function for clearing the subscribe configuration for a given
* UARTE task.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] task Task for which to clear the configuration.
*/
__STATIC_INLINE void nrf_uarte_subscribe_clear(NRF_UARTE_Type * p_reg,
nrf_uarte_task_t task);
/**
* @brief Function for setting the publish configuration for a given
* UARTE event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event for which to set the configuration.
* @param[in] channel Channel through which to publish the event.
*/
__STATIC_INLINE void nrf_uarte_publish_set(NRF_UARTE_Type * p_reg,
nrf_uarte_event_t event,
uint8_t channel);
/**
* @brief Function for clearing the publish configuration for a given
* UARTE event.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] event Event for which to clear the configuration.
*/
__STATIC_INLINE void nrf_uarte_publish_clear(NRF_UARTE_Type * p_reg,
nrf_uarte_event_t event);
#endif // defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for getting error source mask. Function is clearing error source flags after reading.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return Mask with error source flags.
*/
__STATIC_INLINE uint32_t nrf_uarte_errorsrc_get_and_clear(NRF_UARTE_Type * p_reg);
/**
* @brief Function for enabling UARTE.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_uarte_enable(NRF_UARTE_Type * p_reg);
/**
* @brief Function for disabling UARTE.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_uarte_disable(NRF_UARTE_Type * p_reg);
/**
* @brief Function for configuring TX/RX pins.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param pseltxd TXD pin number.
* @param pselrxd RXD pin number.
*/
__STATIC_INLINE void nrf_uarte_txrx_pins_set(NRF_UARTE_Type * p_reg,
uint32_t pseltxd,
uint32_t pselrxd);
/**
* @brief Function for disconnecting TX/RX pins.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_uarte_txrx_pins_disconnect(NRF_UARTE_Type * p_reg);
/**
* @brief Function for getting TX pin.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return TX pin number.
*/
__STATIC_INLINE uint32_t nrf_uarte_tx_pin_get(NRF_UARTE_Type * p_reg);
/**
* @brief Function for getting RX pin.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return RX pin number.
*/
__STATIC_INLINE uint32_t nrf_uarte_rx_pin_get(NRF_UARTE_Type * p_reg);
/**
* @brief Function for getting RTS pin.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return RTS pin number.
*/
__STATIC_INLINE uint32_t nrf_uarte_rts_pin_get(NRF_UARTE_Type * p_reg);
/**
* @brief Function for getting CTS pin.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*
* @return CTS pin number.
*/
__STATIC_INLINE uint32_t nrf_uarte_cts_pin_get(NRF_UARTE_Type * p_reg);
/**
* @brief Function for configuring flow control pins.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param pselrts RTS pin number.
* @param pselcts CTS pin number.
*/
__STATIC_INLINE void nrf_uarte_hwfc_pins_set(NRF_UARTE_Type * p_reg,
uint32_t pselrts,
uint32_t pselcts);
/**
* @brief Function for disconnecting flow control pins.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
*/
__STATIC_INLINE void nrf_uarte_hwfc_pins_disconnect(NRF_UARTE_Type * p_reg);
/**
* @brief Function for starting an UARTE task.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param task Task.
*/
__STATIC_INLINE void nrf_uarte_task_trigger(NRF_UARTE_Type * p_reg, nrf_uarte_task_t task);
/**
* @brief Function for returning the address of the specified task register.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param task Task.
*
* @return Task address.
*/
__STATIC_INLINE uint32_t nrf_uarte_task_address_get(NRF_UARTE_Type * p_reg, nrf_uarte_task_t task);
/**
* @brief Function for configuring UARTE.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param hwfc Hardware flow control. Enabled if true.
* @param parity Parity. Included if true.
*/
__STATIC_INLINE void nrf_uarte_configure(NRF_UARTE_Type * p_reg,
nrf_uarte_parity_t parity,
nrf_uarte_hwfc_t hwfc);
/**
* @brief Function for setting UARTE baud rate.
*
* @param p_reg Pointer to the structure of registers of the peripheral.
* @param baudrate Baud rate.
*/
__STATIC_INLINE void nrf_uarte_baudrate_set(NRF_UARTE_Type * p_reg, nrf_uarte_baudrate_t baudrate);
/**
* @brief Function for setting the transmit buffer.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] p_buffer Pointer to the buffer with data to send.
* @param[in] length Maximum number of data bytes to transmit.
*/
__STATIC_INLINE void nrf_uarte_tx_buffer_set(NRF_UARTE_Type * p_reg,
uint8_t const * p_buffer,
size_t length);
/**
* @brief Function for getting number of bytes transmitted in the last transaction.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @retval Amount of bytes transmitted.
*/
__STATIC_INLINE uint32_t nrf_uarte_tx_amount_get(NRF_UARTE_Type * p_reg);
/**
* @brief Function for setting the receive buffer.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] p_buffer Pointer to the buffer for received data.
* @param[in] length Maximum number of data bytes to receive.
*/
__STATIC_INLINE void nrf_uarte_rx_buffer_set(NRF_UARTE_Type * p_reg,
uint8_t * p_buffer,
size_t length);
/**
* @brief Function for getting number of bytes received in the last transaction.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
*
* @retval Amount of bytes received.
*/
__STATIC_INLINE uint32_t nrf_uarte_rx_amount_get(NRF_UARTE_Type * p_reg);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_uarte_event_clear(NRF_UARTE_Type * p_reg, nrf_uarte_event_t event)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0x0UL;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event));
(void)dummy;
#endif
}
__STATIC_INLINE bool nrf_uarte_event_check(NRF_UARTE_Type * p_reg, nrf_uarte_event_t event)
{
return (bool)*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE uint32_t nrf_uarte_event_address_get(NRF_UARTE_Type * p_reg,
nrf_uarte_event_t event)
{
return (uint32_t)((uint8_t *)p_reg + (uint32_t)event);
}
__STATIC_INLINE void nrf_uarte_shorts_enable(NRF_UARTE_Type * p_reg, uint32_t mask)
{
p_reg->SHORTS |= mask;
}
__STATIC_INLINE void nrf_uarte_shorts_disable(NRF_UARTE_Type * p_reg, uint32_t mask)
{
p_reg->SHORTS &= ~(mask);
}
__STATIC_INLINE void nrf_uarte_int_enable(NRF_UARTE_Type * p_reg, uint32_t mask)
{
p_reg->INTENSET = mask;
}
__STATIC_INLINE bool nrf_uarte_int_enable_check(NRF_UARTE_Type * p_reg, nrf_uarte_int_mask_t mask)
{
return (bool)(p_reg->INTENSET & mask);
}
__STATIC_INLINE void nrf_uarte_int_disable(NRF_UARTE_Type * p_reg, uint32_t mask)
{
p_reg->INTENCLR = mask;
}
#if defined(DPPI_PRESENT)
__STATIC_INLINE void nrf_uarte_subscribe_set(NRF_UARTE_Type * p_reg,
nrf_uarte_task_t task,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) task + 0x80uL)) =
((uint32_t)channel | UARTE_SUBSCRIBE_STARTRX_EN_Msk);
}
__STATIC_INLINE void nrf_uarte_subscribe_clear(NRF_UARTE_Type * p_reg,
nrf_uarte_task_t task)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) task + 0x80uL)) = 0;
}
__STATIC_INLINE void nrf_uarte_publish_set(NRF_UARTE_Type * p_reg,
nrf_uarte_event_t event,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) event + 0x80uL)) =
((uint32_t)channel | UARTE_PUBLISH_CTS_EN_Msk);
}
__STATIC_INLINE void nrf_uarte_publish_clear(NRF_UARTE_Type * p_reg,
nrf_uarte_event_t event)
{
*((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) event + 0x80uL)) = 0;
}
#endif // defined(DPPI_PRESENT)
__STATIC_INLINE uint32_t nrf_uarte_errorsrc_get_and_clear(NRF_UARTE_Type * p_reg)
{
uint32_t errsrc_mask = p_reg->ERRORSRC;
p_reg->ERRORSRC = errsrc_mask;
return errsrc_mask;
}
__STATIC_INLINE void nrf_uarte_enable(NRF_UARTE_Type * p_reg)
{
p_reg->ENABLE = UARTE_ENABLE_ENABLE_Enabled;
}
__STATIC_INLINE void nrf_uarte_disable(NRF_UARTE_Type * p_reg)
{
p_reg->ENABLE = UARTE_ENABLE_ENABLE_Disabled;
}
__STATIC_INLINE void nrf_uarte_txrx_pins_set(NRF_UARTE_Type * p_reg, uint32_t pseltxd, uint32_t pselrxd)
{
p_reg->PSEL.TXD = pseltxd;
p_reg->PSEL.RXD = pselrxd;
}
__STATIC_INLINE void nrf_uarte_txrx_pins_disconnect(NRF_UARTE_Type * p_reg)
{
nrf_uarte_txrx_pins_set(p_reg, NRF_UARTE_PSEL_DISCONNECTED, NRF_UARTE_PSEL_DISCONNECTED);
}
__STATIC_INLINE uint32_t nrf_uarte_tx_pin_get(NRF_UARTE_Type * p_reg)
{
return p_reg->PSEL.TXD;
}
__STATIC_INLINE uint32_t nrf_uarte_rx_pin_get(NRF_UARTE_Type * p_reg)
{
return p_reg->PSEL.RXD;
}
__STATIC_INLINE uint32_t nrf_uarte_rts_pin_get(NRF_UARTE_Type * p_reg)
{
return p_reg->PSEL.RTS;
}
__STATIC_INLINE uint32_t nrf_uarte_cts_pin_get(NRF_UARTE_Type * p_reg)
{
return p_reg->PSEL.CTS;
}
__STATIC_INLINE void nrf_uarte_hwfc_pins_set(NRF_UARTE_Type * p_reg, uint32_t pselrts, uint32_t pselcts)
{
p_reg->PSEL.RTS = pselrts;
p_reg->PSEL.CTS = pselcts;
}
__STATIC_INLINE void nrf_uarte_hwfc_pins_disconnect(NRF_UARTE_Type * p_reg)
{
nrf_uarte_hwfc_pins_set(p_reg, NRF_UARTE_PSEL_DISCONNECTED, NRF_UARTE_PSEL_DISCONNECTED);
}
__STATIC_INLINE void nrf_uarte_task_trigger(NRF_UARTE_Type * p_reg, nrf_uarte_task_t task)
{
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)task)) = 0x1UL;
}
__STATIC_INLINE uint32_t nrf_uarte_task_address_get(NRF_UARTE_Type * p_reg, nrf_uarte_task_t task)
{
return (uint32_t)p_reg + (uint32_t)task;
}
__STATIC_INLINE void nrf_uarte_configure(NRF_UARTE_Type * p_reg,
nrf_uarte_parity_t parity,
nrf_uarte_hwfc_t hwfc)
{
p_reg->CONFIG = (uint32_t)parity | (uint32_t)hwfc;
}
__STATIC_INLINE void nrf_uarte_baudrate_set(NRF_UARTE_Type * p_reg, nrf_uarte_baudrate_t baudrate)
{
p_reg->BAUDRATE = baudrate;
}
__STATIC_INLINE void nrf_uarte_tx_buffer_set(NRF_UARTE_Type * p_reg,
uint8_t const * p_buffer,
size_t length)
{
p_reg->TXD.PTR = (uint32_t)p_buffer;
p_reg->TXD.MAXCNT = length;
}
__STATIC_INLINE uint32_t nrf_uarte_tx_amount_get(NRF_UARTE_Type * p_reg)
{
return p_reg->TXD.AMOUNT;
}
__STATIC_INLINE void nrf_uarte_rx_buffer_set(NRF_UARTE_Type * p_reg,
uint8_t * p_buffer,
size_t length)
{
p_reg->RXD.PTR = (uint32_t)p_buffer;
p_reg->RXD.MAXCNT = length;
}
__STATIC_INLINE uint32_t nrf_uarte_rx_amount_get(NRF_UARTE_Type * p_reg)
{
return p_reg->RXD.AMOUNT;
}
#endif //SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif //NRF_UARTE_H__
+259
View File
@@ -0,0 +1,259 @@
/**
* Copyright (c) 2018 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_VMC_H__
#define NRF_VMC_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_vmc_hal VMC HAL
* @{
* @ingroup nrf_vmc
* @brief Hardware access layer for managing the Volatile Memory Controller (VMC) peripheral.
*/
/** @brief Power configuration bits for each section in particular RAM block. */
typedef enum
{
NRF_VMC_POWER_S0 = VMC_RAM_POWER_S0POWER_Msk, ///< Keep retention on RAM section S0 of the particular RAM block when RAM section is switched off.
NRF_VMC_POWER_S1 = VMC_RAM_POWER_S1POWER_Msk, ///< Keep retention on RAM section S1 of the particular RAM block when RAM section is switched off.
NRF_VMC_POWER_S2 = VMC_RAM_POWER_S2POWER_Msk, ///< Keep retention on RAM section S2 of the particular RAM block when RAM section is switched off.
NRF_VMC_POWER_S3 = VMC_RAM_POWER_S3POWER_Msk, ///< Keep retention on RAM section S3 of the particular RAM block when RAM section is switched off.
} nrf_vmc_power_t;
/** @brief Retention configuration bits for each section in particular RAM block. */
typedef enum
{
NRF_VMC_RETENTION_S0 = VMC_RAM_POWER_S0RETENTION_Msk, ///< Keep RAM section S0 of the particular RAM block on or off in System ON mode.
NRF_VMC_RETENTION_S1 = VMC_RAM_POWER_S1RETENTION_Msk, ///< Keep RAM section S1 of the particular RAM block on or off in System ON mode.
NRF_VMC_RETENTION_S2 = VMC_RAM_POWER_S2RETENTION_Msk, ///< Keep RAM section S2 of the particular RAM block on or off in System ON mode.
NRF_VMC_RETENTION_S3 = VMC_RAM_POWER_S3RETENTION_Msk, ///< Keep RAM section S3 of the particular RAM block on or off in System ON mode.
} nrf_vmc_retention_t;
/**
* @brief Function for setting power configuration for the particular RAM block.
*
* @note Overrides current configuration.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] ram_block_num RAM block number.
* @param[in] power_mask Bitmask with sections configuration of particular RAM block.
* @ref nrf_vmc_power_t should be use to prepare this bitmask.
* @param[in] retention_mask Bitmask with sections configuration of particular RAM block.
* @ref nrf_vmc_retention_t should be use to prepare this bitmask.
*/
__STATIC_INLINE void nrf_vmc_ram_block_config(NRF_VMC_Type * p_reg,
uint8_t ram_block_num,
uint32_t power_mask,
uint32_t retention_mask);
/**
* @brief Function for clearing power configuration for the particular RAM block.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] ram_block_num RAM block number.
*/
__STATIC_INLINE void nrf_vmc_ram_block_clear(NRF_VMC_Type * p_reg, uint8_t ram_block_num);
/**
* @brief Function for setting power configuration for the particular RAM block.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] ram_block_num RAM block number.
* @param[in] sect_power Paricular section of the RAM block.
*/
__STATIC_INLINE void nrf_vmc_ram_block_power_set(NRF_VMC_Type * p_reg,
uint8_t ram_block_num,
nrf_vmc_power_t sect_power);
/**
* @brief Function for clearing power configuration for the particular RAM block.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] ram_block_num RAM block number.
* @param[in] sect_power Paricular section of the RAM block.
*/
__STATIC_INLINE void nrf_vmc_ram_block_power_clear(NRF_VMC_Type * p_reg,
uint8_t ram_block_num,
nrf_vmc_power_t sect_power);
/**
* @brief Function for getting power configuration of the particular RAM block.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] ram_block_num RAM block number.
*
* @return Bitmask with power configuration of sections of particular RAM block.
*/
__STATIC_INLINE uint32_t nrf_vmc_ram_block_power_mask_get(NRF_VMC_Type const * p_reg,
uint8_t ram_block_num);
/**
* @brief Function for setting retention configuration for the particular RAM block.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] ram_block_num RAM block number.
* @param[in] sect_retention Paricular section of the RAM block.
*/
__STATIC_INLINE void nrf_vmc_ram_block_retention_set(NRF_VMC_Type * p_reg,
uint8_t ram_block_num,
nrf_vmc_retention_t sect_retention);
/**
* @brief Function for clearing retention configuration for the particular RAM block.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] ram_block_num RAM block number.
* @param[in] sect_retention Paricular section of the RAM block.
*/
__STATIC_INLINE void nrf_vmc_ram_block_retention_clear(NRF_VMC_Type * p_reg,
uint8_t ram_block_num,
nrf_vmc_retention_t sect_retention);
/**
* @brief Function for getting retention configuration of the particular RAM block.
*
* @param[in] p_reg Pointer to the structure of registers of the peripheral.
* @param[in] ram_block_num RAM block number.
*
* @return Bitmask with retention configuration of sections of particular RAM block
*/
__STATIC_INLINE uint32_t nrf_vmc_ram_block_retention_mask_get(NRF_VMC_Type const * p_reg,
uint8_t ram_block_num);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_vmc_ram_block_config(NRF_VMC_Type * p_reg,
uint8_t ram_block_num,
uint32_t power_mask,
uint32_t retention_mask)
{
p_reg->RAM[ram_block_num].POWER =
(power_mask & (
VMC_RAM_POWER_S0POWER_Msk |
VMC_RAM_POWER_S1POWER_Msk |
VMC_RAM_POWER_S2POWER_Msk |
VMC_RAM_POWER_S3POWER_Msk)) |
(retention_mask & (
VMC_RAM_POWER_S0RETENTION_Msk |
VMC_RAM_POWER_S1RETENTION_Msk |
VMC_RAM_POWER_S2RETENTION_Msk |
VMC_RAM_POWER_S3RETENTION_Msk));
// Perform dummy read of the POWER register to ensure that configuration of sections was
// written to the VMC peripheral.
volatile uint32_t dummy = p_reg->RAM[ram_block_num].POWER;
(void)dummy;
}
__STATIC_INLINE void nrf_vmc_ram_block_clear(NRF_VMC_Type * p_reg, uint8_t ram_block_num)
{
p_reg->RAM[ram_block_num].POWER = 0;
}
__STATIC_INLINE void nrf_vmc_ram_block_power_set(NRF_VMC_Type * p_reg,
uint8_t ram_block_num,
nrf_vmc_power_t sect_power)
{
p_reg->RAM[ram_block_num].POWERSET = (uint32_t)sect_power;
// Perform dummy read of the POWERSET register to ensure that configuration of sections was
// written to the VMC peripheral.
volatile uint32_t dummy = p_reg->RAM[ram_block_num].POWERSET;
(void)dummy;
}
__STATIC_INLINE void nrf_vmc_ram_block_power_clear(NRF_VMC_Type * p_reg,
uint8_t ram_block_num,
nrf_vmc_power_t sect_power)
{
p_reg->RAM[ram_block_num].POWERCLR = (uint32_t)sect_power;
}
__STATIC_INLINE uint32_t nrf_vmc_ram_block_power_mask_get(NRF_VMC_Type const * p_reg,
uint8_t ram_block_num)
{
return p_reg->RAM[ram_block_num].POWER & (
VMC_RAM_POWER_S0POWER_Msk |
VMC_RAM_POWER_S1POWER_Msk |
VMC_RAM_POWER_S2POWER_Msk |
VMC_RAM_POWER_S3POWER_Msk);
}
__STATIC_INLINE void nrf_vmc_ram_block_retention_set(NRF_VMC_Type * p_reg,
uint8_t ram_block_num,
nrf_vmc_retention_t sect_retention)
{
p_reg->RAM[ram_block_num].POWERSET = (uint32_t)sect_retention;
// Perform dummy read of the POWERSET register to ensure that configuration of sections was
// written to the VMC peripheral.
volatile uint32_t dummy = p_reg->RAM[ram_block_num].POWERSET;
(void)dummy;
}
__STATIC_INLINE void nrf_vmc_ram_block_retention_clear(NRF_VMC_Type * p_reg,
uint8_t ram_block_num,
nrf_vmc_retention_t sect_retention)
{
p_reg->RAM[ram_block_num].POWERCLR = (uint32_t)sect_retention;
}
__STATIC_INLINE uint32_t nrf_vmc_ram_block_retention_mask_get(NRF_VMC_Type const * p_reg,
uint8_t ram_block_num)
{
return p_reg->RAM[ram_block_num].POWER & (
VMC_RAM_POWER_S0RETENTION_Msk |
VMC_RAM_POWER_S1RETENTION_Msk |
VMC_RAM_POWER_S2RETENTION_Msk |
VMC_RAM_POWER_S3RETENTION_Msk);
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_VMC_H__
+402
View File
@@ -0,0 +1,402 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRF_WDT_H__
#define NRF_WDT_H__
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_wdt_hal WDT HAL
* @{
* @ingroup nrf_wdt
* @brief Hardware access layer for managing the Watchdog Timer (WDT) peripheral.
*/
/** @brief Number of WDT channels. */
#define NRF_WDT_CHANNEL_NUMBER 0x8UL
/** @brief WDT register reload value. */
#define NRF_WDT_RR_VALUE 0x6E524635UL /* Fixed value; should not be modified. */
/** @brief WDT tasks. */
typedef enum
{
NRF_WDT_TASK_START = offsetof(NRF_WDT_Type, TASKS_START), /**< Task for starting WDT. */
} nrf_wdt_task_t;
/** @brief WDT events. */
typedef enum
{
NRF_WDT_EVENT_TIMEOUT = offsetof(NRF_WDT_Type, EVENTS_TIMEOUT), /**< Event from WDT time-out. */
} nrf_wdt_event_t;
/** @brief WDT behavior in the SLEEP or HALT CPU modes. */
typedef enum
{
NRF_WDT_BEHAVIOUR_RUN_SLEEP = WDT_CONFIG_SLEEP_Msk, /**< WDT will run when CPU is in SLEEP mode. */
NRF_WDT_BEHAVIOUR_RUN_HALT = WDT_CONFIG_HALT_Msk, /**< WDT will run when CPU is in HALT mode. */
NRF_WDT_BEHAVIOUR_RUN_SLEEP_HALT = WDT_CONFIG_SLEEP_Msk | WDT_CONFIG_HALT_Msk, /**< WDT will run when CPU is in SLEEP or HALT mode. */
NRF_WDT_BEHAVIOUR_PAUSE_SLEEP_HALT = 0, /**< WDT will be paused when CPU is in SLEEP or HALT mode. */
} nrf_wdt_behaviour_t;
/** @brief WDT reload request registers. */
typedef enum
{
NRF_WDT_RR0 = 0, /**< Reload request register 0. */
NRF_WDT_RR1, /**< Reload request register 1. */
NRF_WDT_RR2, /**< Reload request register 2. */
NRF_WDT_RR3, /**< Reload request register 3. */
NRF_WDT_RR4, /**< Reload request register 4. */
NRF_WDT_RR5, /**< Reload request register 5. */
NRF_WDT_RR6, /**< Reload request register 6. */
NRF_WDT_RR7 /**< Reload request register 7. */
} nrf_wdt_rr_register_t;
/** @brief WDT interrupts. */
typedef enum
{
NRF_WDT_INT_TIMEOUT_MASK = WDT_INTENSET_TIMEOUT_Msk, /**< WDT interrupt from time-out event. */
} nrf_wdt_int_mask_t;
/**
* @brief Function for configuring the watchdog behavior when the CPU is sleeping or halted.
*
* @param behaviour Watchdog behavior when CPU is in SLEEP or HALT mode.
*/
__STATIC_INLINE void nrf_wdt_behaviour_set(nrf_wdt_behaviour_t behaviour);
/**
* @brief Function for starting the WDT task.
*
* @param[in] task Task.
*/
__STATIC_INLINE void nrf_wdt_task_trigger(nrf_wdt_task_t task);
/**
* @brief Function for clearing the WDT event register.
*
* @param[in] event Event.
*/
__STATIC_INLINE void nrf_wdt_event_clear(nrf_wdt_event_t event);
/**
* @brief Function for retrieving the state of the WDT event.
*
* @param[in] event Event to be checked.
*
* @retval true The event has been generated.
* @retval false The event has not been generated.
*/
__STATIC_INLINE bool nrf_wdt_event_check(nrf_wdt_event_t event);
/**
* @brief Function for enabling the specified interrupt.
*
* @param[in] int_mask Interrupt.
*/
__STATIC_INLINE void nrf_wdt_int_enable(uint32_t int_mask);
/**
* @brief Function for retrieving the state of given interrupt.
*
* @param[in] int_mask Interrupt.
*
* @retval true Interrupt is enabled.
* @retval false Interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_wdt_int_enable_check(uint32_t int_mask);
/**
* @brief Function for disabling a specific interrupt.
*
* @param[in] int_mask Interrupt.
*/
__STATIC_INLINE void nrf_wdt_int_disable(uint32_t int_mask);
#if defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting the subscribe configuration for a given
* WDT task.
*
* @param[in] task Task for which to set the configuration.
* @param[in] channel Channel through which to subscribe events.
*/
__STATIC_INLINE void nrf_wdt_subscribe_set(nrf_wdt_task_t task,
uint8_t channel);
/**
* @brief Function for clearing the subscribe configuration for a given
* WDT task.
*
* @param[in] task Task for which to clear the configuration.
*/
__STATIC_INLINE void nrf_wdt_subscribe_clear(nrf_wdt_task_t task);
/**
* @brief Function for setting the publish configuration for a given
* WDT event.
*
* @param[in] event Event for which to set the configuration.
* @param[in] channel Channel through which to publish the event.
*/
__STATIC_INLINE void nrf_wdt_publish_set(nrf_wdt_event_t event,
uint8_t channel);
/**
* @brief Function for clearing the publish configuration for a given
* WDT event.
*
* @param[in] event Event for which to clear the configuration.
*/
__STATIC_INLINE void nrf_wdt_publish_clear(nrf_wdt_event_t event);
#endif // defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for returning the address of a specific WDT task register.
*
* @param[in] task Task.
*/
__STATIC_INLINE uint32_t nrf_wdt_task_address_get(nrf_wdt_task_t task);
/**
* @brief Function for returning the address of a specific WDT event register.
*
* @param[in] event Event.
*
* @return Address of requested event register
*/
__STATIC_INLINE uint32_t nrf_wdt_event_address_get(nrf_wdt_event_t event);
/**
* @brief Function for retrieving the watchdog status.
*
* @retval true The watchdog is started.
* @retval false The watchdog is not started.
*/
__STATIC_INLINE bool nrf_wdt_started(void);
/**
* @brief Function for retrieving the watchdog reload request status.
*
* @param[in] rr_register Reload request register to be checked.
*
* @retval true Reload request is running.
* @retval false No reload requests are running.
*/
__STATIC_INLINE bool nrf_wdt_request_status(nrf_wdt_rr_register_t rr_register);
/**
* @brief Function for setting the watchdog reload value.
*
* @param[in] reload_value Watchdog counter initial value.
*/
__STATIC_INLINE void nrf_wdt_reload_value_set(uint32_t reload_value);
/**
* @brief Function for retrieving the watchdog reload value.
*
* @return Reload value.
*/
__STATIC_INLINE uint32_t nrf_wdt_reload_value_get(void);
/**
* @brief Function for enabling a specific reload request register.
*
* @param[in] rr_register Reload request register to be enabled.
*/
__STATIC_INLINE void nrf_wdt_reload_request_enable(nrf_wdt_rr_register_t rr_register);
/**
* @brief Function for disabling a specific reload request register.
*
* @param[in] rr_register Reload request register to be disabled.
*/
__STATIC_INLINE void nrf_wdt_reload_request_disable(nrf_wdt_rr_register_t rr_register);
/**
* @brief Function for retrieving the status of a specific reload request register.
*
* @param[in] rr_register Reload request register to be checked.
*
* @retval true The reload request register is enabled.
* @retval false The reload request register is not enabled.
*/
__STATIC_INLINE bool nrf_wdt_reload_request_is_enabled(nrf_wdt_rr_register_t rr_register);
/**
* @brief Function for setting a specific reload request register.
*
* @param[in] rr_register Reload request register to set.
*/
__STATIC_INLINE void nrf_wdt_reload_request_set(nrf_wdt_rr_register_t rr_register);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_wdt_behaviour_set(nrf_wdt_behaviour_t behaviour)
{
NRF_WDT->CONFIG = behaviour;
}
__STATIC_INLINE void nrf_wdt_task_trigger(nrf_wdt_task_t task)
{
*((volatile uint32_t *)((uint8_t *)NRF_WDT + (uint32_t)task)) = 0x01UL;
}
__STATIC_INLINE void nrf_wdt_event_clear(nrf_wdt_event_t event)
{
*((volatile uint32_t *)((uint8_t *)NRF_WDT + (uint32_t)event)) = 0x0UL;
#if __CORTEX_M == 0x04
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)NRF_WDT + (uint32_t)event));
(void)dummy;
#endif
}
__STATIC_INLINE bool nrf_wdt_event_check(nrf_wdt_event_t event)
{
return (bool)*((volatile uint32_t *)((uint8_t *)NRF_WDT + (uint32_t)event));
}
__STATIC_INLINE void nrf_wdt_int_enable(uint32_t int_mask)
{
NRF_WDT->INTENSET = int_mask;
}
__STATIC_INLINE bool nrf_wdt_int_enable_check(uint32_t int_mask)
{
return (bool)(NRF_WDT->INTENSET & int_mask);
}
__STATIC_INLINE void nrf_wdt_int_disable(uint32_t int_mask)
{
NRF_WDT->INTENCLR = int_mask;
}
#if defined(DPPI_PRESENT)
__STATIC_INLINE void nrf_wdt_subscribe_set(nrf_wdt_task_t task,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) NRF_WDT + (uint32_t) task + 0x80uL)) =
((uint32_t)channel | WDT_SUBSCRIBE_START_EN_Msk);
}
__STATIC_INLINE void nrf_wdt_subscribe_clear(nrf_wdt_task_t task)
{
*((volatile uint32_t *) ((uint8_t *) NRF_WDT + (uint32_t) task + 0x80uL)) = 0;
}
__STATIC_INLINE void nrf_wdt_publish_set(nrf_wdt_event_t event,
uint8_t channel)
{
*((volatile uint32_t *) ((uint8_t *) NRF_WDT + (uint32_t) event + 0x80uL)) =
((uint32_t)channel | WDT_PUBLISH_TIMEOUT_EN_Msk);
}
__STATIC_INLINE void nrf_wdt_publish_clear(nrf_wdt_event_t event)
{
*((volatile uint32_t *) ((uint8_t *) NRF_WDT + (uint32_t) event + 0x80uL)) = 0;
}
#endif // defined(DPPI_PRESENT)
__STATIC_INLINE uint32_t nrf_wdt_task_address_get(nrf_wdt_task_t task)
{
return ((uint32_t)NRF_WDT + (uint32_t)task);
}
__STATIC_INLINE uint32_t nrf_wdt_event_address_get(nrf_wdt_event_t event)
{
return ((uint32_t)NRF_WDT + (uint32_t)event);
}
__STATIC_INLINE bool nrf_wdt_started(void)
{
return (bool)(NRF_WDT->RUNSTATUS);
}
__STATIC_INLINE bool nrf_wdt_request_status(nrf_wdt_rr_register_t rr_register)
{
return (bool)(((NRF_WDT->REQSTATUS) >> rr_register) & 0x1UL);
}
__STATIC_INLINE void nrf_wdt_reload_value_set(uint32_t reload_value)
{
NRF_WDT->CRV = reload_value;
}
__STATIC_INLINE uint32_t nrf_wdt_reload_value_get(void)
{
return (uint32_t)NRF_WDT->CRV;
}
__STATIC_INLINE void nrf_wdt_reload_request_enable(nrf_wdt_rr_register_t rr_register)
{
NRF_WDT->RREN |= 0x1UL << rr_register;
}
__STATIC_INLINE void nrf_wdt_reload_request_disable(nrf_wdt_rr_register_t rr_register)
{
NRF_WDT->RREN &= ~(0x1UL << rr_register);
}
__STATIC_INLINE bool nrf_wdt_reload_request_is_enabled(nrf_wdt_rr_register_t rr_register)
{
return (bool)(NRF_WDT->RREN & (0x1UL << rr_register));
}
__STATIC_INLINE void nrf_wdt_reload_request_set(nrf_wdt_rr_register_t rr_register)
{
NRF_WDT->RR[rr_register] = NRF_WDT_RR_VALUE;
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_WDT_H__
+586
View File
@@ -0,0 +1,586 @@
/**
* Copyright (c) 2019 - 2021, Nordic Semiconductor ASA
*
* 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. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#ifndef NRFX_GPPI_H
#define NRFX_GPPI_H
#include <nrfx.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrfx_gppi Generic PPI layer
* @{
* @ingroup nrfx
* @ingroup nrf_dppi
* @ingroup nrf_ppi
*
* @brief Helper layer that provides the common functionality of PPI and DPPI drivers.
*
* Use PPI and DPPI drivers directly.
* This layer is provided only to help create generic code that can be built
* for SoCs equipped with either of these peripherals. When using this layer,
* take into account that there are significant differences between the PPI and DPPI
* interfaces that affect the behavior of this layer.
*
* One difference is that PPI allows associating of one task or event with
* more than one channel, whereas DPPI does not allow this. In DPPI, the second
* association overwrites the first one. Consequently, this helper layer cannot
* be used in applications that need to connect a task or event to multiple
* channels.
*
* Another difference is that in DPPI one channel can be associated with
* multiple tasks and multiple events, while in PPI this is not possible (with
* the exception of the association of a second task as a fork). Because of
* this difference, it is important to clear the previous endpoints of the channel that
* is to be reused with some different ones. Otherwise, the behavior of this
* helper layer will be different, depending on the actual interface used:
* in DPPI the channel configuration will be extended with the new endpoints, and
* in PPI the new endpoints will replace the previous ones.
*/
#if defined(PPI_PRESENT)
#include <hal/nrf_ppi.h>
typedef enum
{
NRFX_GPPI_CHANNEL_GROUP0 = NRF_PPI_CHANNEL_GROUP0,
NRFX_GPPI_CHANNEL_GROUP1 = NRF_PPI_CHANNEL_GROUP1,
NRFX_GPPI_CHANNEL_GROUP2 = NRF_PPI_CHANNEL_GROUP2,
NRFX_GPPI_CHANNEL_GROUP3 = NRF_PPI_CHANNEL_GROUP3,
#if (PPI_GROUP_NUM > 4)
NRFX_GPPI_CHANNEL_GROUP4 = NRF_PPI_CHANNEL_GROUP4,
NRFX_GPPI_CHANNEL_GROUP5 = NRF_PPI_CHANNEL_GROUP5,
#endif
} nrfx_gppi_channel_group_t;
typedef enum
{
NRFX_GPPI_TASK_CHG0_EN = NRF_PPI_TASK_CHG0_EN,
NRFX_GPPI_TASK_CHG0_DIS = NRF_PPI_TASK_CHG0_DIS,
NRFX_GPPI_TASK_CHG1_EN = NRF_PPI_TASK_CHG1_EN,
NRFX_GPPI_TASK_CHG1_DIS = NRF_PPI_TASK_CHG1_DIS,
NRFX_GPPI_TASK_CHG2_EN = NRF_PPI_TASK_CHG2_EN,
NRFX_GPPI_TASK_CHG2_DIS = NRF_PPI_TASK_CHG2_DIS,
NRFX_GPPI_TASK_CHG3_EN = NRF_PPI_TASK_CHG3_EN,
NRFX_GPPI_TASK_CHG3_DIS = NRF_PPI_TASK_CHG3_DIS,
#if (PPI_GROUP_NUM > 4)
NRFX_GPPI_TASK_CHG4_EN = NRF_PPI_TASK_CHG4_EN,
NRFX_GPPI_TASK_CHG4_DIS = NRF_PPI_TASK_CHG4_DIS,
NRFX_GPPI_TASK_CHG5_EN = NRF_PPI_TASK_CHG5_EN,
NRFX_GPPI_TASK_CHG5_DIS = NRF_PPI_TASK_CHG5_DIS
#endif
} nrfx_gppi_task_t;
#elif defined(DPPI_PRESENT)
#include <hal/nrf_dppi.h>
typedef enum
{
NRFX_GPPI_CHANNEL_GROUP0 = NRF_DPPI_CHANNEL_GROUP0,
NRFX_GPPI_CHANNEL_GROUP1 = NRF_DPPI_CHANNEL_GROUP1,
NRFX_GPPI_CHANNEL_GROUP2 = NRF_DPPI_CHANNEL_GROUP2,
NRFX_GPPI_CHANNEL_GROUP3 = NRF_DPPI_CHANNEL_GROUP3,
NRFX_GPPI_CHANNEL_GROUP4 = NRF_DPPI_CHANNEL_GROUP4,
NRFX_GPPI_CHANNEL_GROUP5 = NRF_DPPI_CHANNEL_GROUP5,
} nrfx_gppi_channel_group_t;
typedef enum
{
NRFX_GPPI_TASK_CHG0_EN = NRF_DPPI_TASK_CHG0_EN,
NRFX_GPPI_TASK_CHG0_DIS = NRF_DPPI_TASK_CHG0_DIS,
NRFX_GPPI_TASK_CHG1_EN = NRF_DPPI_TASK_CHG1_EN,
NRFX_GPPI_TASK_CHG1_DIS = NRF_DPPI_TASK_CHG1_DIS,
NRFX_GPPI_TASK_CHG2_EN = NRF_DPPI_TASK_CHG2_EN,
NRFX_GPPI_TASK_CHG2_DIS = NRF_DPPI_TASK_CHG2_DIS,
NRFX_GPPI_TASK_CHG3_EN = NRF_DPPI_TASK_CHG3_EN,
NRFX_GPPI_TASK_CHG3_DIS = NRF_DPPI_TASK_CHG3_DIS,
NRFX_GPPI_TASK_CHG4_EN = NRF_DPPI_TASK_CHG4_EN,
NRFX_GPPI_TASK_CHG4_DIS = NRF_DPPI_TASK_CHG4_DIS,
NRFX_GPPI_TASK_CHG5_EN = NRF_DPPI_TASK_CHG5_EN,
NRFX_GPPI_TASK_CHG5_DIS = NRF_DPPI_TASK_CHG5_DIS
} nrfx_gppi_task_t;
#elif defined(__NRFX_DOXYGEN__)
/** @brief Generic PPI channel groups. */
typedef enum
{
NRFX_GPPI_CHANNEL_GROUP0, /**< Channel group 0.*/
NRFX_GPPI_CHANNEL_GROUP1, /**< Channel group 1.*/
NRFX_GPPI_CHANNEL_GROUP2, /**< Channel group 2.*/
NRFX_GPPI_CHANNEL_GROUP3, /**< Channel group 3.*/
NRFX_GPPI_CHANNEL_GROUP4, /**< Channel group 4.*/
NRFX_GPPI_CHANNEL_GROUP5, /**< Channel group 5.*/
} nrfx_gppi_channel_group_t;
/** @brief Generic PPI tasks. */
typedef enum
{
NRFX_GPPI_TASK_CHG0_EN, /**< Task for enabling channel group 0 */
NRFX_GPPI_TASK_CHG0_DIS, /**< Task for disabling channel group 0 */
NRFX_GPPI_TASK_CHG1_EN, /**< Task for enabling channel group 1 */
NRFX_GPPI_TASK_CHG1_DIS, /**< Task for disabling channel group 1 */
NRFX_GPPI_TASK_CHG2_EN, /**< Task for enabling channel group 2 */
NRFX_GPPI_TASK_CHG2_DIS, /**< Task for disabling channel group 2 */
NRFX_GPPI_TASK_CHG3_EN, /**< Task for enabling channel group 3 */
NRFX_GPPI_TASK_CHG3_DIS, /**< Task for disabling channel group 3 */
NRFX_GPPI_TASK_CHG4_EN, /**< Task for enabling channel group 4 */
NRFX_GPPI_TASK_CHG4_DIS, /**< Task for disabling channel group 4 */
NRFX_GPPI_TASK_CHG5_EN, /**< Task for enabling channel group 5 */
NRFX_GPPI_TASK_CHG5_DIS, /**< Task for disabling channel group 5 */
} nrfx_gppi_task_t;
#endif // defined(__NRFX_DOXYGEN__)
/**
* @brief Function for checking if a given channel is enabled.
*
* @param[in] channel Channel to check.
*
* @retval true The channel is enabled.
* @retval false The channel is not enabled.
*/
__STATIC_INLINE bool nrfx_gppi_channel_check(uint8_t channel);
/** @brief Function for disabling all channels. */
__STATIC_INLINE void nrfx_gppi_channels_disable_all(void);
/**
* @brief Function for enabling multiple channels.
*
* The bits in @c mask value correspond to particular channels. This means that
* writing 1 to bit 0 enables channel 0, writing 1 to bit 1 enables channel 1, etc.
*
* @param[in] mask Channel mask.
*/
__STATIC_INLINE void nrfx_gppi_channels_enable(uint32_t mask);
/**
* @brief Function for disabling multiple channels.
*
* The bits in @c mask value correspond to particular channels. This means that
* writing 1 to bit 0 disables channel 0, writing 1 to bit 1 disables channel 1, etc.
*
* @param[in] mask Channel mask.
*/
__STATIC_INLINE void nrfx_gppi_channels_disable(uint32_t mask);
/**
* @brief Function for associating a given channel with the specified event register.
*
* This function sets the DPPI publish configuration for a given event
* or sets the PPI event endpoint register.
*
* @param[in] channel Channel to which to assign the event.
* @param[in] eep Address of the event register.
*/
__STATIC_INLINE void nrfx_gppi_event_endpoint_setup(uint8_t channel, uint32_t eep);
/**
* @brief Function for associating a given channel with the specified task register.
*
* This function sets the DPPI subscribe configuration for a given task
* or sets the PPI task endpoint register.
*
* @param[in] channel Channel to which to assign the task.
* @param[in] tep Address of the task register.
*/
__STATIC_INLINE void nrfx_gppi_task_endpoint_setup(uint8_t channel, uint32_t tep);
/**
* @brief Function for setting up the event and task endpoints for a given channel.
*
* @param[in] channel Channel to which the given endpoints are assigned.
* @param[in] eep Address of the event register.
* @param[in] tep Address of the task register.
*/
__STATIC_INLINE void nrfx_gppi_channel_endpoints_setup(uint8_t channel,
uint32_t eep,
uint32_t tep);
/**
* @brief Function for clearing the DPPI publish configuration for a given event
* register or for clearing the PPI event endpoint register.
*
* @param[in] channel Channel for which to clear the event endpoint. Not used in DPPI.
* @param[in] eep Address of the event register. Not used in PPI.
*/
__STATIC_INLINE void nrfx_gppi_event_endpoint_clear(uint8_t channel, uint32_t eep);
/**
* @brief Function for clearing the DPPI subscribe configuration for a given task
* register or for clearing the PPI task endpoint register.
*
* @param[in] channel Channel from which to disconnect the task enpoint. Not used in DPPI.
* @param[in] tep Address of the task register. Not used in PPI.
*/
__STATIC_INLINE void nrfx_gppi_task_endpoint_clear(uint8_t channel, uint32_t tep);
#if defined(PPI_FEATURE_FORKS_PRESENT) || defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for setting up the task endpoint for a given PPI fork or for
* associating the DPPI channel with an additional task register.
*
* @param[in] channel Channel to which the given fork endpoint is assigned.
* @param[in] fork_tep Address of the task register.
*/
__STATIC_INLINE void nrfx_gppi_fork_endpoint_setup(uint8_t channel, uint32_t fork_tep);
/**
* @brief Function for clearing the task endpoint for a given PPI fork or for clearing
* the DPPI subscribe register.
*
* @param[in] channel Channel for which to clear the fork endpoint. Not used in DPPI.
* @param[in] fork_tep Address of the task register. Not used in PPI.
*/
__STATIC_INLINE void nrfx_gppi_fork_endpoint_clear(uint8_t channel, uint32_t fork_tep);
#endif // defined(PPI_FEATURE_FORKS_PRESENT) || defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__)
/**
* @brief Function for including multiple channels in a channel group.
*
* @param[in] channel_mask Channels to be included in the group.
* @param[in] channel_group Channel group.
*/
__STATIC_INLINE void nrfx_gppi_channels_include_in_group(uint32_t channel_mask,
nrfx_gppi_channel_group_t channel_group);
/**
* @brief Function for removing multiple channels from a channel group.
*
* @param[in] channel_mask Channels to be removed from the group.
* @param[in] channel_group Channel group.
*/
__STATIC_INLINE void nrfx_gppi_channels_remove_from_group(uint32_t channel_mask,
nrfx_gppi_channel_group_t channel_group);
/**
* @brief Function for removing all channels from a channel group.
*
* @param[in] channel_group Channel group.
*/
__STATIC_INLINE void nrfx_gppi_group_clear(nrfx_gppi_channel_group_t channel_group);
/**
* @brief Function for enabling a channel group.
*
* @param[in] channel_group Channel group.
*/
__STATIC_INLINE void nrfx_gppi_group_enable(nrfx_gppi_channel_group_t channel_group);
/**
* @brief Function for disabling a group.
*
* @param[in] channel_group Channel group.
*/
__STATIC_INLINE void nrfx_gppi_group_disable(nrfx_gppi_channel_group_t channel_group);
/**
* @brief Function for activating a task.
*
* @param[in] task Task to be activated.
*/
__STATIC_INLINE void nrfx_gppi_task_trigger(nrfx_gppi_task_t task);
/**
* @brief Function for returning the address of a specific task register.
*
* @param[in] task PPI or DPPI task.
*
* @return Address of the requested task register.
*/
__STATIC_INLINE uint32_t nrfx_gppi_task_address_get(nrfx_gppi_task_t task);
/**
* @brief Function for returning the address of a channel group disable task.
*
* @param[in] group Channel group.
*
* @return Disable task address of the specified group.
*/
__STATIC_INLINE nrfx_gppi_task_t nrfx_gppi_group_disable_task_get(nrfx_gppi_channel_group_t group);
/**
* @brief Function for returning the address of a channel group enable task.
*
* @param[in] group Channel group.
*
* @return Enable task address of the specified group.
*/
__STATIC_INLINE nrfx_gppi_task_t nrfx_gppi_group_enable_task_get(nrfx_gppi_channel_group_t group);
/** @} */
#if defined(PPI_PRESENT)
__STATIC_INLINE bool nrfx_gppi_channel_check(uint8_t channel)
{
return (nrf_ppi_channel_enable_get((nrf_ppi_channel_t)channel) == NRF_PPI_CHANNEL_ENABLED);
}
__STATIC_INLINE void nrfx_gppi_channels_disable_all(void)
{
nrf_ppi_channel_disable_all();
}
__STATIC_INLINE void nrfx_gppi_channels_enable(uint32_t mask)
{
nrf_ppi_channels_enable(mask);
}
__STATIC_INLINE void nrfx_gppi_channels_disable(uint32_t mask)
{
nrf_ppi_channels_disable(mask);
}
__STATIC_INLINE void nrfx_gppi_event_endpoint_setup(uint8_t channel, uint32_t eep)
{
nrf_ppi_event_endpoint_setup((nrf_ppi_channel_t)channel, eep);
}
__STATIC_INLINE void nrfx_gppi_task_endpoint_setup(uint8_t channel, uint32_t tep)
{
nrf_ppi_task_endpoint_setup((nrf_ppi_channel_t)channel, tep);
}
__STATIC_INLINE void nrfx_gppi_channel_endpoints_setup(uint8_t channel,
uint32_t eep,
uint32_t tep)
{
nrf_ppi_channel_endpoint_setup((nrf_ppi_channel_t)channel, eep, tep);
}
__STATIC_INLINE void nrfx_gppi_event_endpoint_clear(uint8_t channel, uint32_t eep)
{
(void)eep;
nrf_ppi_event_endpoint_setup((nrf_ppi_channel_t)channel, 0);
}
__STATIC_INLINE void nrfx_gppi_task_endpoint_clear(uint8_t channel, uint32_t tep)
{
(void)tep;
nrf_ppi_task_endpoint_setup((nrf_ppi_channel_t)channel, 0);
}
#if defined(PPI_FEATURE_FORKS_PRESENT)
__STATIC_INLINE void nrfx_gppi_fork_endpoint_setup(uint8_t channel, uint32_t fork_tep)
{
nrf_ppi_fork_endpoint_setup((nrf_ppi_channel_t)channel, fork_tep);
}
__STATIC_INLINE void nrfx_gppi_fork_endpoint_clear(uint8_t channel, uint32_t fork_tep)
{
(void)fork_tep;
nrf_ppi_fork_endpoint_setup((nrf_ppi_channel_t)channel, 0);
}
#endif
__STATIC_INLINE void nrfx_gppi_channels_include_in_group(uint32_t channel_mask,
nrfx_gppi_channel_group_t channel_group)
{
nrf_ppi_channels_include_in_group(channel_mask, channel_group);
}
__STATIC_INLINE void nrfx_gppi_channels_remove_from_group(uint32_t channel_mask,
nrfx_gppi_channel_group_t channel_group)
{
nrf_ppi_channels_remove_from_group(channel_mask, channel_group);
}
__STATIC_INLINE void nrfx_gppi_group_clear(nrfx_gppi_channel_group_t channel_group)
{
nrf_ppi_channel_group_clear(channel_group);
}
__STATIC_INLINE void nrfx_gppi_group_enable(nrfx_gppi_channel_group_t channel_group)
{
nrf_ppi_group_enable(channel_group);
}
__STATIC_INLINE void nrfx_gppi_group_disable(nrfx_gppi_channel_group_t channel_group)
{
nrf_ppi_group_disable(channel_group);
}
__STATIC_INLINE void nrfx_gppi_task_trigger(nrfx_gppi_task_t task)
{
nrf_ppi_task_trigger(task);
}
__STATIC_INLINE uint32_t nrfx_gppi_task_address_get(nrfx_gppi_task_t task)
{
return (uint32_t)nrf_ppi_task_address_get(task);
}
__STATIC_INLINE nrfx_gppi_task_t nrfx_gppi_group_disable_task_get(nrfx_gppi_channel_group_t group)
{
return (nrfx_gppi_task_t)nrf_ppi_group_disable_task_get((uint8_t)group);
}
__STATIC_INLINE nrfx_gppi_task_t nrfx_gppi_group_enable_task_get(nrfx_gppi_channel_group_t group)
{
return (nrfx_gppi_task_t)nrf_ppi_group_enable_task_get((uint8_t)group);
}
#elif defined(DPPI_PRESENT)
__STATIC_INLINE bool nrfx_gppi_channel_check(uint8_t channel)
{
return nrf_dppi_channel_check(NRF_DPPIC, channel);
}
__STATIC_INLINE void nrfx_gppi_channels_disable_all(void)
{
nrf_dppi_channels_disable_all(NRF_DPPIC);
}
__STATIC_INLINE void nrfx_gppi_channels_enable(uint32_t mask)
{
nrf_dppi_channels_enable(NRF_DPPIC, mask);
}
__STATIC_INLINE void nrfx_gppi_channels_disable(uint32_t mask)
{
nrf_dppi_channels_disable(NRF_DPPIC, mask);
}
__STATIC_INLINE void nrfx_gppi_task_trigger(nrfx_gppi_task_t task)
{
nrf_dppi_task_trigger(NRF_DPPIC, task);
}
__STATIC_INLINE void nrfx_gppi_event_endpoint_setup(uint8_t channel, uint32_t eep)
{
NRFX_ASSERT(eep);
*((volatile uint32_t *)(eep + 0x80uL)) = ((uint32_t)channel | DPPIC_SUBSCRIBE_CHG_EN_EN_Msk);
}
__STATIC_INLINE void nrfx_gppi_task_endpoint_setup(uint8_t channel, uint32_t tep)
{
NRFX_ASSERT(tep);
*((volatile uint32_t *)(tep + 0x80uL)) = ((uint32_t)channel | DPPIC_SUBSCRIBE_CHG_EN_EN_Msk);
}
__STATIC_INLINE void nrfx_gppi_channel_endpoints_setup(uint8_t channel,
uint32_t eep,
uint32_t tep)
{
nrfx_gppi_event_endpoint_setup(channel, eep);
nrfx_gppi_task_endpoint_setup(channel, tep);
}
__STATIC_INLINE void nrfx_gppi_event_endpoint_clear(uint8_t channel, uint32_t eep)
{
NRFX_ASSERT(eep);
(void)channel;
*((volatile uint32_t *)(eep + 0x80uL)) = 0;
}
__STATIC_INLINE void nrfx_gppi_task_endpoint_clear(uint8_t channel, uint32_t tep)
{
NRFX_ASSERT(tep);
(void)channel;
*((volatile uint32_t *)(tep + 0x80uL)) = 0;
}
__STATIC_INLINE void nrfx_gppi_fork_endpoint_setup(uint8_t channel, uint32_t fork_tep)
{
nrfx_gppi_task_endpoint_setup(channel, fork_tep);
}
__STATIC_INLINE void nrfx_gppi_fork_endpoint_clear(uint8_t channel, uint32_t fork_tep)
{
nrfx_gppi_task_endpoint_clear(channel, fork_tep);
}
__STATIC_INLINE void nrfx_gppi_channels_include_in_group(uint32_t channel_mask,
nrfx_gppi_channel_group_t channel_group)
{
nrf_dppi_channels_include_in_group(NRF_DPPIC, channel_mask, channel_group);
}
__STATIC_INLINE void nrfx_gppi_channels_remove_from_group(uint32_t channel_mask,
nrfx_gppi_channel_group_t channel_group)
{
nrf_dppi_channels_remove_from_group(NRF_DPPIC, channel_mask, channel_group);
}
__STATIC_INLINE void nrfx_gppi_group_clear(nrfx_gppi_channel_group_t channel_group)
{
nrf_dppi_group_clear(NRF_DPPIC, channel_group);
}
__STATIC_INLINE void nrfx_gppi_group_enable(nrfx_gppi_channel_group_t channel_group)
{
nrf_dppi_group_enable(NRF_DPPIC, channel_group);
}
__STATIC_INLINE void nrfx_gppi_group_disable(nrfx_gppi_channel_group_t channel_group)
{
nrf_dppi_group_disable(NRF_DPPIC, channel_group);
}
__STATIC_INLINE uint32_t nrfx_gppi_task_address_get(nrfx_gppi_task_t gppi_task)
{
return (uint32_t) ((uint8_t *) NRF_DPPIC + (uint32_t) gppi_task);
}
__STATIC_INLINE nrfx_gppi_task_t nrfx_gppi_group_disable_task_get(nrfx_gppi_channel_group_t group)
{
return (nrfx_gppi_task_t) nrf_dppi_group_disable_task_get((uint8_t)group);
}
__STATIC_INLINE nrfx_gppi_task_t nrfx_gppi_group_enable_task_get(nrfx_gppi_channel_group_t group)
{
return (nrfx_gppi_task_t) nrf_dppi_group_enable_task_get((uint8_t)group);
}
#else
#error "Neither PPI nor DPPI is present in the SoC currently in use."
#endif
#ifdef __cplusplus
}
#endif
#endif // NRFX_GPPI_H

Some files were not shown because too many files have changed in this diff Show More