1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge branch 'RIOT-OS:master' into stm32_adc_cal

This commit is contained in:
david-vankampen 2023-11-27 14:22:39 -05:00 committed by GitHub
commit b09713e058
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
138 changed files with 21066 additions and 641 deletions

View File

@ -2,6 +2,8 @@ name: check-commits
on:
pull_request:
types: [opened, reopened, synchronize]
merge_group:
jobs:
check-commits:
runs-on: ubuntu-latest
@ -24,3 +26,10 @@ jobs:
- name: Run checks
run: |
./dist/tools/${{ matrix.check }}/check.sh "${{ github.base_ref }}"
check-commits-success:
needs: check-commits
if: github.event_name != 'merge_group'
runs-on: ubuntu-latest
steps:
- name: check-commits succeeded
run: exit 0

View File

@ -4,8 +4,11 @@ on:
types: [opened, reopened, labeled, unlabeled, synchronize]
pull_request_review:
types: [submitted, dismissed]
merge_group:
jobs:
check-labels:
if: github.event_name != 'merge_group'
runs-on: ubuntu-latest
steps:
- uses: RIOT-OS/check-labels-action@v1.1.1

View File

@ -3,10 +3,12 @@ name: pr-labeler
on:
pull_request_target:
types: [opened, synchronize, reopened]
merge_group:
jobs:
triage:
runs-on: ubuntu-latest
if: github.event_name != 'merge_group'
steps:
- uses: actions/labeler@main
with:

View File

@ -13,6 +13,7 @@ on:
pull_request:
branches:
- '*'
merge_group:
jobs:
static-tests:
@ -21,11 +22,18 @@ jobs:
- uses: actions/checkout@main
with:
fetch-depth: 0
- name: set CI_BASE_BRANCH
run: |
if [ -n "${{ github.base_ref }}" ]; then
echo "CI_BASE_BRANCH=${{ github.base_ref }}" >> $GITHUB_ENV
elif [ -n "${{ github.event.merge_group.base_ref }}" ]; then
echo "CI_BASE_BRANCH=${{ github.event.merge_group.base_ref }}" | sed s.=refs/heads/.=. >> $GITHUB_ENV
fi
- name: Setup git
run: |
# Note: ${{ github.base_ref }} is empty when not in a PR
if [ -n "${{ github.base_ref }}" ]; then
git fetch origin ${{ github.base_ref }}:${{ github.base_ref }} --no-tags
# Note: CI_BASE_BRANCH is empty when not in a PR
if [ -n "${CI_BASE_BRANCH}" ]; then
git fetch origin ${CI_BASE_BRANCH}:${CI_BASE_BRANCH} --no-tags
else
git config diff.renameLimit 16384
fi
@ -34,9 +42,9 @@ jobs:
run: docker pull riot/static-test-tools:latest
- name: Run static-tests
run: |
# Note: ${{ github.base_ref }} is empty when not in a PR
# Note: ${CI_BASE_BRANCH} is empty when not in a PR
docker run --rm \
-e CI_BASE_BRANCH=${{ github.base_ref }} \
-e CI_BASE_BRANCH \
-e GITHUB_RUN_ID=${GITHUB_RUN_ID} \
-v $(pwd):/data/riotbuild \
riot/static-test-tools:latest \

View File

@ -11,6 +11,7 @@ on:
pull_request:
branches:
- '*'
merge_group:
jobs:
tools-build:

View File

@ -9,9 +9,11 @@ on:
pull_request:
branches:
- '*'
merge_group:
jobs:
python-tests:
if: github.event_name != 'merge_group'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main

View File

@ -178,22 +178,18 @@ check_label() {
return $?
}
# this function returns 0 when this is build is building one of the two bors
# branches ("staging" or "trying", 1 otherwise.
is_bors_build() {
test "${CI_BUILD_BRANCH}" = "staging" || test "${CI_BUILD_BRANCH}" = "trying"
# true if "$2" starts with "$1", false otherwise
startswith() {
case "${2}" in
${1}*) true ;;
*) false ;;
esac
}
# Set CI_BASE_COMMIT in case of a bors build.
# This assumes that bors always adds a single merge commit (possibly itself
# including multiple merges for PRs) on the base branch.
# That git command outputs the hash of the second merge commit (the one before
# the topmost merge), which should be the base branch HEAD.
# (CI_BASE_COMMIT is used by `can_fast_ci_run.py` to only build changes.)
if test -z "${CI_BASE_COMMIT}" && is_bors_build ; then
previous_merge="$(git log --merges --max-count 1 --skip 1 --pretty=format:%H)"
export CI_BASE_COMMIT="${previous_merge}"
fi
# this function returns 0 when this build is building a merge queue branch.
is_merge_queue_build() {
startswith "gh-readonly-queue/" "${CI_BUILD_BRANCH}"
}
# fullbuild logic
# non-full-builds are those where can_fast_ci_run might reduce the build
@ -216,8 +212,8 @@ fi
# configurations.
if [ -z "${QUICK_BUILD}" ]; then
export QUICK_BUILD=0
if is_bors_build ; then
# always do full build for bors' branches
if is_merge_queue_build; then
# always do full build for merge queue' branches
true
elif [ ${FULL_BUILD} -eq 1 ]; then
# full build if building nightly or full build requested by label
@ -323,14 +319,6 @@ error() {
exit 1
}
# true if "$2" starts with "$1", false otherwise
startswith() {
case "${2}" in
${1}*) true ;;
*) false ;;
esac
}
# if MURDOCK_HOOK is set, this function will execute it and pass on all it's
# parameters. should the hook script exit with negative exit code, hook() makes
# this script exit with error, too.

View File

@ -3,6 +3,8 @@ push:
# these two enable potential bors support:
- '^staging$'
- '^trying$'
# github merge trains:
- '^gh-readonly-queue/'
pr:
enable_comments: true

View File

@ -117,7 +117,6 @@ ifneq ($(RIOT_CI_BUILD),1)
ifeq ($(MAKELEVEL),0)
ifneq (,$(BOARDSDIR))
$(warning Using BOARDSDIR is deprecated use EXTERNAL_BOARD_DIRS instead)
$(info EXTERNAL_BOARD_DIRS can contain multiple folders separated by space)
endif
endif
endif

View File

@ -43,9 +43,21 @@ extern "C" {
* @name UART configuration
* @{
*/
#define UART_NUMOF (1U)
#define UART_PIN_RX GPIO_PIN(0, 30)
#define UART_PIN_TX GPIO_PIN(0, 31)
static const uart_conf_t uart_config[] = {
{
.dev = NRF_UARTE0,
.rx_pin = GPIO_PIN(0, 30),
.tx_pin = GPIO_PIN(0, 31),
#ifdef MODULE_PERIPH_UART_HW_FC
.rts_pin = GPIO_UNDEF,
.cts_pin = GPIO_UNDEF,
#endif
.irqn = UARTE0_UART0_IRQn,
},
};
#define UART_NUMOF ARRAY_SIZE(uart_config)
#define UART_0_ISR (isr_uart0)
/** @} */
/**

View File

@ -31,13 +31,23 @@
/**
* @name UART configuration
*
* The CPU only supports one UART device, so we keep it simple
* @{
*/
#define UART_NUMOF (1U)
#define UART_PIN_RX 17
#define UART_PIN_TX 18
static const uart_conf_t uart_config[] = {
{ /* Mapped to USB virtual COM port */
.dev = NRF_UART0,
.rx_pin = GPIO_PIN(0, 17),
.tx_pin = GPIO_PIN(0, 18),
#ifdef MODULE_PERIPH_UART_HW_FC
.rts_pin = GPIO_UNDEF,
.cts_pin = GPIO_UNDEF,
#endif
.irqn = UART0_IRQn,
},
};
#define UART_NUMOF ARRAY_SIZE(uart_config)
#define UART_0_ISR isr_uart0
/** @} */
/**

View File

@ -33,10 +33,21 @@ extern "C" {
* @name UART configuration
* @{
*/
#define UART_NUMOF (1U)
/* UART pin configuration */
#define UART_PIN_RX 25
#define UART_PIN_TX 24
static const uart_conf_t uart_config[] = {
{
.dev = NRF_UART0,
.rx_pin = GPIO_PIN(0, 25),
.tx_pin = GPIO_PIN(0, 24),
#ifdef MODULE_PERIPH_UART_HW_FC
.rts_pin = GPIO_UNDEF,
.cts_pin = GPIO_UNDEF,
#endif
.irqn = UART0_IRQn,
},
};
#define UART_NUMOF ARRAY_SIZE(uart_config)
#define UART_0_ISR isr_uart0
/** @} */
/**

View File

@ -56,14 +56,6 @@ extern "C" {
#define XTIMER_BACKOFF (19)
/** @} */
/* The boards debug header only exports SWD, so JTAG-only pins PA15, PB3(*),
* and PB4 can be remapped as regular GPIOs instead. (Note: PB3 is also used as
* SWO. The user needs to take care to not enable SWO with the debugger while
* at the same time PB3 is used as GPIO. But RIOT does not use SWO in any case,
* so if a user adds this feature in her/his own code, she/he should be well
* aware of this.)
*/
#define STM32F1_DISABLE_JTAG /**< Disable JTAG to allow pins being used as GPIOs */
#ifdef __cplusplus
}
#endif

View File

@ -8,9 +8,10 @@
/**
* @defgroup boards_common_esp32x ESP32x Common
* @ingroup boards_common
* @brief Definitions and configurations that are common for
* all ESP32 boards.
* all ESP32x boards.
*
* For detailed information about the ESP32, configuring and compiling RIOT
* for ESP32 boards, please refer \ref esp32_riot.
* For detailed information about ESP32x SoCs, configuring and compiling RIOT
* for ESP32x boards, please refer \ref esp32_riot.
*/

View File

@ -41,10 +41,13 @@ extern "C" {
* @name Arduino's SPI buses
* @{
*/
/**
* @brief SPI_DEV(1) is connected to D11/D12/D13
*/
#if !defined(ARDUINO_SPI_D11D12D13) && defined(SPI_NUMOF)
/**
* @brief SPI_DEV(0) is connected to D11/D12/D13 for most Nucleo-64 boards
*
* This can be overwritten in `boards/nucleo-<foobar>/include/periph_conf.h` by
* providing a custom `ARDUINO_SPI_D11D12D13`.
*/
#define ARDUINO_SPI_D11D12D13 SPI_DEV(0)
#endif
/** @} */

View File

@ -36,7 +36,11 @@ static const timer_conf_t timer_config[] = {
{
.dev = TIM2,
.max = 0xffffffff,
#if defined(RCC_APB1ENR_TIM2EN)
.rcc_mask = RCC_APB1ENR_TIM2EN,
#else
.rcc_mask = RCC_APB1ENR1_TIM2EN,
#endif
.bus = APB1,
.irqn = TIM2_IRQn
},

View File

@ -20,10 +20,10 @@
#ifndef PERIPH_CONF_H
#define PERIPH_CONF_H
#include "periph_cpu.h"
#include "cfg_clock_32_1.h"
#include "cfg_rtt_default.h"
#include "cfg_timer_default.h"
#include "periph_cpu.h"
#ifdef __cplusplus
extern "C" {
@ -33,9 +33,21 @@ extern "C" {
* @name UART configuration
* @{
*/
#define UART_NUMOF (1U)
#define UART_PIN_RX GPIO_PIN(0, 11)
#define UART_PIN_TX GPIO_PIN(0, 5)
static const uart_conf_t uart_config[] = {
{ /* Mapped to USB virtual COM port */
.dev = NRF_UARTE0,
.rx_pin = GPIO_PIN(0, 11),
.tx_pin = GPIO_PIN(0, 5),
#ifdef MODULE_PERIPH_UART_HW_FC
.rts_pin = GPIO_UNDEF,
.cts_pin = GPIO_UNDEF,
#endif
.irqn = UARTE0_UART0_IRQn,
},
};
#define UART_NUMOF ARRAY_SIZE(uart_config)
#define UART_0_ISR (isr_uart0)
/** @} */
/**

View File

@ -24,6 +24,7 @@ config BOARD_ESP32S3_WT32_SC01_PLUS
select HAVE_FT5X06
select HAVE_LCD_PARALLEL if MODULE_ST7796
select HAVE_LCD_PARALLEL_LL_MCU if MODULE_ST7796
select HAVE_MTD_SDCARD_DEFAULT
select HAVE_ST7796

View File

@ -29,6 +29,7 @@ endif
ifneq (,$(filter st7796,$(USEMODULE)))
USEMODULE += lcd_parallel
USEMODULE += lcd_parallel_ll_mcu
endif
ifneq (,$(filter touch_dev,$(USEMODULE)))

View File

@ -29,13 +29,24 @@ extern "C" {
#endif
/**
* @name UART configuration
* @name UART configuration
* @{
*/
#define UART_NUMOF (1U)
/* UART pin configuration */
#define UART_PIN_RX 25
#define UART_PIN_TX 24
static const uart_conf_t uart_config[] = {
{ /* Mapped to USB virtual COM port */
.dev = NRF_UART0,
.rx_pin = GPIO_PIN(0, 25),
.tx_pin = GPIO_PIN(0, 24),
#ifdef MODULE_PERIPH_UART_HW_FC
.rts_pin = GPIO_UNDEF,
.cts_pin = GPIO_UNDEF,
#endif
.irqn = UART0_IRQn,
},
};
#define UART_NUMOF ARRAY_SIZE(uart_config)
#define UART_0_ISR isr_uart0
/** @} */
/**

View File

@ -12,6 +12,13 @@ config BOARD_NRF51DK
default y
select BOARD_COMMON_NRF51
select CPU_MODEL_NRF51X22XXAC
select HAS_ARDUINO_ANALOG
select HAS_ARDUINO_I2C
select HAS_ARDUINO_PINS
select HAS_ARDUINO_SHIELD_ISP
select HAS_ARDUINO_SHIELD_UNO
select HAS_ARDUINO_SPI
select HAS_PERIPH_ADC
select HAS_PERIPH_I2C
select HAS_PERIPH_SPI
select HAS_PERIPH_UART

View File

@ -1,11 +1,18 @@
CPU_MODEL = nrf51x22xxac
# Put defined MCU peripherals here (in alphabetical order)
FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_uart
FEATURES_PROVIDED += periph_uart_hw_fc
FEATURES_PROVIDED += vdd_lc_filter_reg1
FEATURES_PROVIDED += arduino_analog
FEATURES_PROVIDED += arduino_i2c
FEATURES_PROVIDED += arduino_pins
FEATURES_PROVIDED += arduino_shield_isp
FEATURES_PROVIDED += arduino_shield_uno
FEATURES_PROVIDED += arduino_spi
# include common nrf51 based boards features
include $(RIOTBOARD)/common/nrf51/Makefile.features

View File

@ -0,0 +1,123 @@
/*
* Copyright (C) 2023 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_nrf51dk
* @{
*
* @file
* @brief Mapping from MCU pins to Arduino pins
*
* You can use the defines in this file for simplified interaction with the
* Arduino specific pin numbers.
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*/
#ifndef ARDUINO_IOMAP_H
#define ARDUINO_IOMAP_H
#include "periph/gpio.h"
#include "periph/adc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Arduino's SPI buses
* @{
*/
/**
* @brief SPI_DEV(0) is connected to D11/D12/D13
*/
/* D11/D12/D13 are on P0.25, P0.28, P0.29 */
#define ARDUINO_SPI_D11D12D13 SPI_DEV(0)
/* The ISP SPI bus is also connected to P0.25, P0.28, P0.29 */
#define ARDUINO_SPI_ISP SPI_DEV(0)
/** @} */
/**
* @name Arduino's I2C buses
* @{
*/
/**
* @brief The first I2C bus is where shields for the Arduino UNO/Mega expect
* it
*/
#define ARDUINO_I2C_UNO I2C_DEV(0)
/** @} */
/**
* @name Mapping of MCU pins to Arduino pins
* @{
*/
/* P3 header on the nRF51DK */
#define ARDUINO_PIN_0 GPIO_PIN(0, 12)
#define ARDUINO_PIN_1 GPIO_PIN(0, 13)
#define ARDUINO_PIN_2 GPIO_PIN(0, 14)
#define ARDUINO_PIN_3 GPIO_PIN(0, 15)
#define ARDUINO_PIN_4 GPIO_PIN(0, 16)
#define ARDUINO_PIN_5 GPIO_PIN(0, 17)
#define ARDUINO_PIN_6 GPIO_PIN(0, 18)
#define ARDUINO_PIN_7 GPIO_PIN(0, 19)
/* P4 header on the nRF51DK */
#define ARDUINO_PIN_8 GPIO_PIN(0, 20)
#define ARDUINO_PIN_9 GPIO_PIN(0, 23)
#define ARDUINO_PIN_10 GPIO_PIN(0, 24)
#define ARDUINO_PIN_11 GPIO_PIN(0, 25)
#define ARDUINO_PIN_12 GPIO_PIN(0, 28)
#define ARDUINO_PIN_13 GPIO_PIN(0, 29)
/* SCL and SDA on this header are not available as digital pins in the
* Arduino world. It is P0.30 and P0.07 here, though. Also what would be
* AREF in the Arduino world is P0.00 here */
/* P2 header on the nRF51DK */
#define ARDUINO_PIN_14 GPIO_PIN(0, 1)
#define ARDUINO_PIN_15 GPIO_PIN(0, 2)
#define ARDUINO_PIN_16 GPIO_PIN(0, 3)
#define ARDUINO_PIN_17 GPIO_PIN(0, 4)
#define ARDUINO_PIN_18 GPIO_PIN(0, 5)
#define ARDUINO_PIN_19 GPIO_PIN(0, 6)
#define ARDUINO_PIN_LAST 19
/** @} */
/**
* @name Aliases for analog pins
* @{
*/
#define ARDUINO_PIN_A0 ARDUINO_PIN_14
#define ARDUINO_PIN_A1 ARDUINO_PIN_15
#define ARDUINO_PIN_A2 ARDUINO_PIN_16
#define ARDUINO_PIN_A3 ARDUINO_PIN_17
#define ARDUINO_PIN_A4 ARDUINO_PIN_18
#define ARDUINO_PIN_A5 ARDUINO_PIN_19
/** @} */
/**
* @name Mapping of Arduino analog pins to RIOT ADC lines
* @{
*/
#define ARDUINO_A0 ADC_LINE(0)
#define ARDUINO_A1 ADC_LINE(1)
#define ARDUINO_A2 ADC_LINE(2)
#define ARDUINO_A3 ADC_LINE(3)
#define ARDUINO_A4 ADC_LINE(4)
#define ARDUINO_A5 ADC_LINE(5)
#define ARDUINO_ANALOG_PIN_LAST 5
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* ARDUINO_IOMAP_H */
/** @} */

View File

@ -29,15 +29,24 @@ extern "C" {
#endif
/**
* @name UART configuration
* @name UART configuration
* @{
*/
#define UART_NUMOF (1U)
/* UART pin configuration */
#define UART_PIN_RX 11
#define UART_PIN_TX 9
#define UART_PIN_RTS 8
#define UART_PIN_CTS 10
static const uart_conf_t uart_config[] = {
{ /* Mapped to USB virtual COM port */
.dev = NRF_UART0,
.rx_pin = GPIO_PIN(0, 11),
.tx_pin = GPIO_PIN(0, 9),
#ifdef MODULE_PERIPH_UART_HW_FC
.rts_pin = GPIO_PIN(0, 8),
.cts_pin = GPIO_PIN(0, 10),
#endif
.irqn = UART0_IRQn,
},
};
#define UART_NUMOF ARRAY_SIZE(uart_config)
#define UART_0_ISR isr_uart0
/** @} */
/**
@ -73,6 +82,30 @@ static const i2c_conf_t i2c_config[] = {
#define I2C_NUMOF ARRAY_SIZE(i2c_config)
/** @} */
/**
* @name ADC configuration
*
* The ADC channels have a fixed mapping:
*
* | Channel | MCU Pin | Arduino pin on board |
* |:---------- |:--------- |:------------------------------------- |
* | AIN0 | P0.26 | -- (exposed, by no Arduino UNO pin) |
* | AIN1 | P0.27 | -- (exposed, by no Arduino UNO pin) |
* | AIN2 | P0.01 | A0 |
* | AIN3 | P0.02 | A1 |
* | AIN4 | P0.03 | A2 |
* | AIN5 | P0.04 | A3 |
* | AIN6 | P0.05 | A4 |
* | AIN7 | P0.06 | A5 |
*
* Expose those on Arduino pins A0 to A5
* @{
*/
static const adc_conf_t adc_config[] = {2, 3, 4, 5, 6, 7};
#define ADC_NUMOF ARRAY_SIZE(adc_config)
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -29,15 +29,24 @@ extern "C" {
#endif
/**
* @name UART configuration
* @name UART configuration
* @{
*/
#define UART_NUMOF (1U)
/* UART pin configuration */
#define UART_PIN_RX 11
#define UART_PIN_TX 9
#define UART_PIN_RTS 8
#define UART_PIN_CTS 10
static const uart_conf_t uart_config[] = {
{
.dev = NRF_UART0,
.rx_pin = GPIO_PIN(0, 11),
.tx_pin = GPIO_PIN(0, 9),
#ifdef MODULE_PERIPH_UART_HW_FC
.rts_pin = GPIO_PIN(0, 8),
.cts_pin = GPIO_PIN(0, 10),
#endif
.irqn = UART0_IRQn,
},
};
#define UART_NUMOF ARRAY_SIZE(uart_config)
#define UART_0_ISR isr_uart0
/** @} */
#ifdef __cplusplus

View File

@ -35,9 +35,21 @@ extern "C" {
* @name UART configuration
* @{
*/
#define UART_NUMOF (1U)
#define UART_PIN_RX GPIO_PIN(0, 19)
#define UART_PIN_TX GPIO_PIN(0, 20)
static const uart_conf_t uart_config[] = {
{
.dev = NRF_UARTE0,
.rx_pin = GPIO_PIN(0, 19),
.tx_pin = GPIO_PIN(0, 20),
#ifdef MODULE_PERIPH_UART_HW_FC
.rts_pin = GPIO_UNDEF,
.cts_pin = GPIO_UNDEF,
#endif
.irqn = UARTE0_UART0_IRQn,
},
};
#define UART_NUMOF ARRAY_SIZE(uart_config)
#define UART_0_ISR (isr_uart0)
/** @} */
#ifdef __cplusplus

View File

@ -48,9 +48,21 @@ static const spi_conf_t spi_config[] = {
* @name UART configuration
* @{
*/
#define UART_NUMOF (1U)
#define UART_PIN_RX GPIO_PIN(0, 8)
#define UART_PIN_TX GPIO_PIN(0, 6)
static const uart_conf_t uart_config[] = {
{ /* Mapped to USB virtual COM port */
.dev = NRF_UARTE0,
.rx_pin = GPIO_PIN(0, 8),
.tx_pin = GPIO_PIN(0, 6),
#ifdef MODULE_PERIPH_UART_HW_FC
.rts_pin = GPIO_UNDEF,
.cts_pin = GPIO_UNDEF,
#endif
.irqn = UARTE0_UART0_IRQn,
},
};
#define UART_NUMOF ARRAY_SIZE(uart_config)
#define UART_0_ISR (isr_uart0)
/** @} */
#ifdef __cplusplus

View File

@ -35,14 +35,21 @@ extern "C" {
* @name UART configuration
* @{
*/
#define UART_NUMOF (1U)
#define UART_IRQ_PRIO 1
static const uart_conf_t uart_config[] = {
{
.dev = NRF_UART0,
.rx_pin = GPIO_PIN(0, 16),
.tx_pin = GPIO_PIN(0, 17),
#ifdef MODULE_PERIPH_UART_HW_FC
.rts_pin = GPIO_PIN(0, 19),
.cts_pin = GPIO_PIN(0, 18),
#endif
.irqn = UART0_IRQn,
},
};
/* UART pin configuration */
#define UART_PIN_RX 16
#define UART_PIN_TX 17
#define UART_PIN_RTS 19
#define UART_PIN_CTS 18
#define UART_NUMOF ARRAY_SIZE(uart_config)
#define UART_0_ISR isr_uart0
/** @} */
/**

View File

@ -16,8 +16,10 @@ config BOARD_NUCLEO_F030R8
# Put defined MCU peripherals here (in alphabetical order)
select HAS_PERIPH_ADC
select HAS_PERIPH_I2C
select HAS_PERIPH_PWM
select HAS_PERIPH_RTC
select HAS_PERIPH_SPI
select HAS_PERIPH_TIMER
select HAS_PERIPH_UART

View File

@ -3,11 +3,13 @@ CPU_MODEL = stm32f030r8
# Put defined MCU peripherals here (in alphabetical order)
FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_pwm
# For RTC, Nucleos with MB1136 C-02 or MB1136 C-03 -sticker on it have the
# required LSE oscillator provided on the X2 slot.
# See Nucleo User Manual UM1724 section 5.6.2.
FEATURES_PROVIDED += periph_rtc
FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_uart

View File

@ -33,6 +33,7 @@
#include "periph_cpu.h"
#include "clk_conf.h"
#include "cfg_i2c1_pb8_pb9.h"
#ifdef __cplusplus
extern "C" {

View File

@ -16,9 +16,11 @@ config BOARD_NUCLEO_F070RB
# Put defined MCU peripherals here (in alphabetical order)
select HAS_PERIPH_ADC
select HAS_PERIPH_DMA
select HAS_PERIPH_I2C
select HAS_PERIPH_PWM
select HAS_PERIPH_RTC
select HAS_PERIPH_SPI
select HAS_PERIPH_TIMER
select HAS_PERIPH_UART

View File

@ -3,12 +3,14 @@ CPU_MODEL = stm32f070rb
# Put defined MCU peripherals here (in alphabetical order)
FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_dma
FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_pwm
# For RTC, Nucleos with MB1136 C-02 or MB1136 C-03 -sticker on it have the
# required LSE oscillator provided on the X2 slot.
# See Nucleo User Manual UM1724 section 5.6.2.
FEATURES_PROVIDED += periph_rtc
FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_uart

View File

@ -102,6 +102,21 @@ static const uart_conf_t uart_config[] = {
#define UART_NUMOF ARRAY_SIZE(uart_config)
/** @} */
/**
* @name DMA streams configuration
* @{
*/
static const dma_conf_t dma_config[] = {
{ .stream = 1 },
{ .stream = 2 },
};
#define DMA_SHARED_ISR_0 isr_dma1_ch2_3_dma2_ch1_2
#define DMA_SHARED_ISR_0_STREAMS { 0, 1 } /* Indexes 0 and 1 of dma_config share the same isr */
#define DMA_NUMOF ARRAY_SIZE(dma_config)
/** @} */
/**
* @name PWM configuration
* @{
@ -148,6 +163,42 @@ static const adc_conf_t adc_config[] = {
#define ADC_NUMOF ARRAY_SIZE(adc_config)
/** @} */
/**
* @name SPI configuration
*
* To find appriopate device and pins find in the MCU datasheet table
* concerning "Alternate function AF0 to AF7" a texts similar to
* SPI[X]_MOSI/_MISO/_SCK where SPI[X] is SPI device.
*
* For nucleo-f070rb this information is in the datasheet, Tables 11, 12 and 13,
* page 30.
* @{
*/
static const spi_conf_t spi_config[] = {
{
.dev = SPI1,
.mosi_pin = GPIO_PIN(PORT_A, 7),
.miso_pin = GPIO_PIN(PORT_A, 6),
.sclk_pin = GPIO_PIN(PORT_A, 5),
.cs_pin = GPIO_UNDEF,
.mosi_af = GPIO_AF0,
.miso_af = GPIO_AF0,
.sclk_af = GPIO_AF0,
.cs_af = GPIO_AF0,
.rccmask = RCC_APB2ENR_SPI1EN,
.apbbus = APB2,
#ifdef MODULE_PERIPH_DMA
.tx_dma = 1,
.tx_dma_chan = 0,
.rx_dma = 0,
.rx_dma_chan = 0,
#endif
}
};
#define SPI_NUMOF ARRAY_SIZE(spi_config)
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -1,9 +1,2 @@
# load the common Makefile.include for Nucleo boards
include $(RIOTBOARD)/common/nucleo64/Makefile.include
# On-board debugger uses SWD, so JTAG-only pins PA15, PB3(*), and PB4 can be
# remapped as regular GPIOs instead. (Note: PB3 is also used as SWO. The user
# needs to take care to not enable SWO with the debugger while at the same time
# PB3 is used as GPIO. But RIOT does not use SWO in any case, so if a user adds
# this feature in her/his own code, she/he should be well aware of this.)
CFLAGS += -DSTM32F1_DISABLE_JTAG

View File

@ -33,7 +33,7 @@
#include "periph_cpu.h"
#include "clk_conf.h"
#include "cfg_timer_tim2.h"
#include "cfg_timer_tim2_tim15_tim16.h"
#ifdef __cplusplus
extern "C" {

View File

@ -8,6 +8,33 @@
The Nucleo-L433RC is a board from ST's Nucleo family supporting a ARM
Cortex-M4 STM32L433RC microcontroller with 64KiB of RAM and 256KiB of Flash.
### Hardware
![Nucleo64 L433RC](https://www.st.com/bin/ecommerce/api/image.PF264788.en.feature-description-include-personalized-no-cpn-large.jpg)
### MCU
| MCU | STM32L476RG |
|:---------- |:------------------- |
| Family | ARM Cortex-M4 |
| Vendor | ST Microelectronics |
| RAM | 64KiB |
| Flash | 256KiB |
| Frequency | up to 80MHz |
| FPU | yes |
| Timers | 11 (2x watchdog, 1 SysTick, 7x 16-bit, 1x 32-bit) |
| ADCs | 1x 12-bit |
| UARTs | 5 (four USARTs and one Low-Power UART) |
| SPIs | 3 |
| I2Cs | 3 |
| RTC | 1 |
| CAN | 1 |
| Vcc | 1.71 V - 3.6V |
| Datasheet | [Datasheet](https://www.st.com/resource/en/datasheet/stm32l433rc.pdf) |
| Reference Manual | [Reference Manual](https://www.st.com/resource/en/reference_manual/rm0394-stm32l41xxx42xxx43xxx44xxx45xxx46xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf) |
| Programming Manual | [Programming Manual](http://www.st.com/content/ccc/resource/technical/document/programming_manual/6c/3a/cb/e7/e4/ea/44/9b/DM00046982.pdf/files/DM00046982.pdf/jcr:content/translations/en.DM00046982.pdf) |
| Board Manual | [Board Manual](http://www.st.com/resource/en/user_manual/um2206-stm32-nucleo64p-boards-mb1319-stmicroelectronics.pdf) |
### Flashing the Board Using ST-LINK Removable Media
On-board ST-LINK programmer provides via composite USB device removable media.

View File

@ -30,6 +30,16 @@
extern "C" {
#endif
/**
* @name Arduino's I2C buses
* @{
*/
/**
* @brief The first I2C bus is where shields for the Arduino UNO expect it
*/
#define ARDUINO_I2C_UNO I2C_DEV(0)
/** @} */
/**
* @brief Mapping of MCU pins to Arduino pins
* @{

View File

@ -117,7 +117,12 @@ static const spi_conf_t spi_config[] = {
#endif
};
#define SPI_NUMOF ARRAY_SIZE(spi_config)
#define SPI_NUMOF ARRAY_SIZE(spi_config)
/**
* @brief Provide ARDUINO_SPI_D11D12D13 explicitly, as the first SPI
* interface is connected to the radio.
*/
#define ARDUINO_SPI_D11D12D13 SPI_DEV(1)
/** @} */
/**

View File

@ -26,8 +26,11 @@ config BOARD_P_NUCLEO_WB55
# Put other features for this board (in alphabetical order)
select HAS_ARDUINO_ANALOG
select HAS_ARDUINO_I2C
select HAS_ARDUINO_PINS
select HAS_ARDUINO_SHIELD_UNO
select HAS_ARDUINO_SPI
select HAS_ARDUINO_UART
select HAS_RIOTBOOT
select HAS_TINYUSB_DEVICE

View File

@ -14,7 +14,10 @@ FEATURES_PROVIDED += periph_usbdev
# Put other features for this board (in alphabetical order)
FEATURES_PROVIDED += arduino_analog
FEATURES_PROVIDED += arduino_i2c
FEATURES_PROVIDED += arduino_pins
FEATURES_PROVIDED += arduino_shield_uno
FEATURES_PROVIDED += arduino_spi
FEATURES_PROVIDED += arduino_uart
FEATURES_PROVIDED += riotboot
FEATURES_PROVIDED += tinyusb_device

View File

@ -8,29 +8,37 @@ Hardware
![st-nucleo-wb55](https://miro.medium.com/max/700/1*9OG-4Ix4EzHX9uBpMve2IA.jpeg)
## Pinout
@image html pinouts/p-nucleo-wb55.svg "Pinout for the p-nucleo-wb55" width=50%
MCU
---
| MCU | STM32WB55RG |
|:---------- |:------------------------------- |
| Family | ARM Cortex-M4 |
| Vendor | ST Microelectronics |
| RAM | 256KB |
| Flash | 512KB |
| Frequency | 64MHz |
| FPU | yes |
| Timers | 8 (3x 16-bit, 1x 32-bit [TIM5]) |
| LPTimers | 2x 16-bit |
| ADCs | 1x 19-channel 12-bit |
| UARTs | 1 |
| LUARTs | 1 |
| SPIs | 1 |
| I2Cs | 2 |
| RTC | 1 |
| Vcc | 1.65V - 3.6V |
| Datasheet | [Datasheet](https://www.st.com/resource/en/datasheet/stm32wb55cc.pdf)|
| Reference Manual | [Reference Manual](https://www.st.com/resource/en/datasheet/stm32wb55cc.pdf) |
| User Manual | [User Manual](https://www.st.com/content/ccc/resource/technical/document/user_manual/group1/13/58/22/1a/f2/ff/43/5c/DM00517423/files/DM00517423.pdf/jcr:content/translations/en.DM00517423.pdf) |
| MCU | STM32WB55RG |
|:----------------- |:------------------------------------- |
| Family | ARM Cortex-M4 |
| Vendor | ST Microelectronics |
| RAM | 256 KiB |
| Flash | 512 KiB |
| Frequency | 64 MHz |
| FPU | yes |
| Timers | 8 (3x 16-bit, 1x 32-bit [TIM5]) |
| LPTimers | 2x 16-bit |
| ADCs | 1x 19-channel 12-bit |
| UARTs | 1 |
| LUARTs | 1 |
| SPIs | 1 |
| I2Cs | 2 |
| RTC | 1 |
| Vcc | 1.65V - 3.6V |
| Datasheet | [Datasheet][Datasheet] |
| Reference Manual | [Reference Manual][Reference Manual] |
| User Manual | [User Manual][User Manual] |
[Datasheet]: https://www.st.com/resource/en/datasheet/stm32wb55cc.pdf
[Reference Manual]: https://www.st.com/resource/en/reference_manual/rm0434-multiprotocol-wireless-32bit-mcu-armbased-cortexm4-with-fpu-bluetooth-lowenergy-and-802154-radio-solution-stmicroelectronics.pdf
[User Manual]: https://www.st.com/content/ccc/resource/technical/document/user_manual/group1/13/58/22/1a/f2/ff/43/5c/DM00517423/files/DM00517423.pdf/jcr:content/translations/en.DM00517423.pdf
Overview
========
@ -82,25 +90,25 @@ User Interface
Implementation Status
---------------------
| Device | ID | Supported | Comments |
|:---------------- |:----------------- |:------- |:------- |
| MCU | stm32wb | yes | |
| | M0+ co-processor | no | |
| | BLE | no | |
| | 802.15.4 | no | |
| Low-level driver | GPIO | yes | |
| | UART | yes | UART1 |
| | LPUART | yes | LPUART1 |
| | I2C | yes | I2C1 |
| | SPI | yes | |
| | ADC | yes | |
| | RTT | yes | |
| | RTC | yes | |
| | RNG | yes | |
| | Timer | yes | TIM2 |
| | WDT | yes | |
| | USB | yes | |
| | PWM | no | |
| | AES | no | |
| Device | ID | Supported | Comments |
|:----------------- |:----------------- |:--------- |:--------- |
| MCU | stm32wb | yes | |
| | M0+ co-processor | no | |
| | BLE | no | |
| | 802.15.4 | no | |
| Low-level driver | GPIO | yes | |
| | UART | yes | UART1 |
| | LPUART | yes | LPUART1 |
| | I2C | yes | I2C1 |
| | SPI | yes | |
| | ADC | yes | |
| | RTT | yes | |
| | RTC | yes | |
| | RNG | yes | |
| | Timer | yes | TIM2 |
| | WDT | yes | |
| | USB | yes | |
| | PWM | no | |
| | AES | no | |
*/

View File

@ -88,6 +88,33 @@ extern "C" {
#define ARDUINO_ANALOG_PIN_LAST 5
/** @} */
/**
* @name Arduino's default UART device
* @{
*/
#define ARDUINO_UART_D0D1 UART_DEV(1)
/** @} */
/**
* @name Arduino's I2C buses
* @{
*/
/**
* @brief The only configured I2C
*/
#define ARDUINO_I2C_UNO I2C_DEV(0)
/** @} */
/**
* @name Arduino's SPI buses
* @{
*/
/**
* @brief SPI_DEV(0) is connected to D11/D12/D13
*/
#define ARDUINO_SPI_D11D12D13 SPI_DEV(0)
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -50,9 +50,21 @@ static const spi_conf_t spi_config[] = {
* @name UART configuration
* @{
*/
#define UART_NUMOF (1U)
#define UART_PIN_RX GPIO_PIN(0, 4)
#define UART_PIN_TX GPIO_PIN(0, 5)
static const uart_conf_t uart_config[] = {
{
.dev = NRF_UARTE0,
.rx_pin = GPIO_PIN(0, 4),
.tx_pin = GPIO_PIN(0, 5),
#ifdef MODULE_PERIPH_UART_HW_FC
.rts_pin = GPIO_UNDEF,
.cts_pin = GPIO_UNDEF,
#endif
.irqn = UARTE0_UART0_IRQn,
},
};
#define UART_NUMOF ARRAY_SIZE(uart_config)
#define UART_0_ISR (isr_uart0)
/** @} */
#ifdef __cplusplus

View File

@ -18,6 +18,7 @@ config BOARD_SAME54_XPRO
select HAS_PERIPH_RTC
select HAS_PERIPH_RTT
select HAS_PERIPH_PWM
select HAS_PERIPH_FREQM
select HAS_PERIPH_SDMMC
select HAS_PERIPH_SPI
select HAS_PERIPH_TIMER

View File

@ -14,6 +14,7 @@ FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_uart
FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_usbdev
FEATURES_PROVIDED += periph_freqm
# Put other features for this board (in alphabetical order)
FEATURES_PROVIDED += riotboot

View File

@ -3,4 +3,11 @@
# debugger.
TTY_BOARD_FILTER := --model 'EDBG CMSIS-DAP'
# Overwrite GCLK definitions, so that GCLK_IO[2..7] can be connected to GPIOs.
# This way the frequency of signals, connected to these pins, can be measured
# with the FREQM peripheral.
CFLAGS += -DSAM0_GCLK_TIMER=8
CFLAGS += -DSAM0_GCLK_PERIPH=9
CFLAGS += -DSAM0_GCLK_100MHZ=10
include $(RIOTMAKE)/boards/sam0.inc.mk

View File

@ -406,6 +406,18 @@ static const sam0_common_gmac_config_t sam_gmac_config[] = {
};
/** @} */
/**
* @name FREQM peripheral configuration
* @{
*/
static const freqm_config_t freqm_config[] = {
{
.pin = GPIO_PIN(PB, 17),
.gclk_src = SAM0_GCLK_32KHZ
}
};
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -33,9 +33,21 @@ extern "C" {
* @name UART configuration
* @{
*/
#define UART_NUMOF (1U)
#define UART_PIN_RX GPIO_PIN(0, 2)
#define UART_PIN_TX GPIO_PIN(0, 3)
static const uart_conf_t uart_config[] = {
{
.dev = NRF_UARTE0,
.rx_pin = GPIO_PIN(0, 2),
.tx_pin = GPIO_PIN(0, 3),
#ifdef MODULE_PERIPH_UART_HW_FC
.rts_pin = GPIO_UNDEF,
.cts_pin = GPIO_UNDEF,
#endif
.irqn = UARTE0_UART0_IRQn,
},
};
#define UART_NUMOF ARRAY_SIZE(uart_config)
#define UART_0_ISR (isr_uart0)
/** @} */
/**

View File

@ -29,13 +29,24 @@ extern "C" {
#endif
/**
* @name UART configuration
* @name UART configuration
* @{
*/
#define UART_NUMOF (1U)
/* UART pin configuration */
#define UART_PIN_RX 1
#define UART_PIN_TX 2
static const uart_conf_t uart_config[] = {
{ /* Mapped to USB virtual COM port */
.dev = NRF_UART0,
.rx_pin = GPIO_PIN(0, 1),
.tx_pin = GPIO_PIN(0, 2),
#ifdef MODULE_PERIPH_UART_HW_FC
.rts_pin = GPIO_UNDEF,
.cts_pin = GPIO_UNDEF,
#endif
.irqn = UART0_IRQn,
},
};
#define UART_NUMOF ARRAY_SIZE(uart_config)
#define UART_0_ISR isr_uart0
/** @} */
/**

View File

@ -7,4 +7,8 @@ ifneq (,$(filter printf_float,$(USEMODULE)))
LINKFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm
endif
# Add aliases for flash_printf, flash_fprintf, flash_snprintf:
LINKFLAGS += -Wl,--defsym=flash_printf=printf_P
LINKFLAGS += -Wl,--defsym=flash_fprintf=fprintf_P
LINKFLAGS += -Wl,--defsym=flash_snprintf=snprintf_P
include $(RIOTMAKE)/arch/avr8.inc.mk

View File

@ -21,7 +21,7 @@
#define FLASH_UTILS_ARCH_H
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <avr/pgmspace.h>
#ifdef __cplusplus
@ -35,20 +35,68 @@ extern "C" {
#define FLASH_ATTR __flash
#define PRIsflash "S"
#define TO_FLASH(x) __extension__({static FLASH_ATTR const char __c[] = (x); &__c[0];})
#define flash_strcmp strcmp_P
#define flash_strncmp strncmp_P
#define flash_strlen strlen_P
#define flash_strcpy strcpy_P
#define flash_strncpy strncpy_P
#define flash_printf printf_P
/* avrlibc seemingly forgot to provide vprintf_P(), but vfprintf_P() is there */
#define flash_vprintf(fmt, arglist) vfprintf_P(stdout, fmt, arglist)
#define flash_fprintf fprintf_P
#define flash_vfprintf vfprintf_P
#define flash_snprintf snprintf_P
#define flash_vsnprintf vsnprintf_P
#define flash_puts puts_P
#define flash_memcpy memcpy_P
static inline int flash_strcmp(const char *ram, FLASH_ATTR const char *flash)
{
return strcmp_P(ram, (const char *)flash);
}
static inline int flash_strncmp(const char *ram, FLASH_ATTR const char *flash, size_t n)
{
return strncmp_P(ram, (const char *)flash, n);
}
static inline size_t flash_strlen(FLASH_ATTR const char *flash)
{
return strlen_P((const char *)flash);
}
static inline char * flash_strcpy(char *ram, FLASH_ATTR const char *flash)
{
return strcpy_P(ram, (const char *)flash);
}
static inline char * flash_strncpy(char *ram, FLASH_ATTR const char *flash, size_t n)
{
return strncpy_P(ram, (const char *)flash, n);
}
static inline int flash_vprintf(FLASH_ATTR const char *flash, va_list args)
{
/* vprintf_P() is not provided by avr-libc. But vfprintf_P() with
* stdout as stream can be used to implement it */
return vfprintf_P(stdout, (const char *)flash, args);
}
static inline int flash_vfprintf(FILE *stream, FLASH_ATTR const char *flash,
va_list args)
{
return vfprintf_P(stream, (const char *)flash, args);
}
static inline int flash_vsnprintf(char *buf, size_t buf_len,
FLASH_ATTR const char *flash, va_list args)
{
return vsnprintf_P(buf, buf_len, (const char *)flash, args);
}
static inline void flash_puts(FLASH_ATTR const char *flash)
{
puts_P((const char *)flash);
}
static inline void * flash_memcpy(void *dest, FLASH_ATTR const void *src,
size_t n)
{
return memcpy_P(dest, (const void *)src, n);
}
/* aliases need to be provided by the linker, as passing through va-args is
* not possible */
int flash_printf(FLASH_ATTR const char *flash, ...);
int flash_fprintf(FILE *stream, FLASH_ATTR const char *flash, ...);
int flash_snprintf(char *buf, size_t buf_len, FLASH_ATTR const char *flash, ...);
#endif /* Doxygen */

View File

@ -0,0 +1,15 @@
#include <avr/pgmspace.h>
#include <stdio.h>
/* The outdated linker from Ubuntu's toolchain contains a bug in which it will
* garbage collect symbols referenced only by --defsym= command line options,
* and subsequently complain that the symbols are not defined. Adding other
* references to those symbols from an unused function makes that buggy linker
* happy. Since this function is never used, it will be garbage collected and
* not impact the ROM size. */
void work_around_for_shitty_ubuntu_toolchain_and_not_expected_to_be_called(void)
{
printf_P(NULL);
fprintf_P(stdout, NULL);
snprintf_P(NULL, 0, NULL);
}

View File

@ -35,6 +35,7 @@ rsource "bootloader/Kconfig"
rsource "esp-ble-nimble/Kconfig"
rsource "esp-idf/Kconfig"
rsource "esp-idf-api/Kconfig"
rsource "esp-lcd/Kconfig"
rsource "periph/Kconfig"
endif

View File

@ -29,6 +29,10 @@ ifneq (, $(filter esp_freertos, $(USEMODULE)))
DIRS += freertos
endif
ifneq (, $(filter esp_lcd, $(USEMODULE)))
DIRS += esp-lcd
endif
ifneq (, $(filter stdio_usb_serial_jtag, $(USEMODULE)))
DIRS += stdio_usb_serial_jtag
endif

View File

@ -128,6 +128,12 @@ ifneq (,$(filter esp_idf_heap,$(USEMODULE)))
USEPKG += tlsf
endif
ifneq (,$(filter lcd_parallel_ll_mcu,$(USEMODULE)))
USEMODULE += esp_lcd
USEMODULE += esp_idf_lcd
USEMODULE += esp_idf_heap
endif
ifneq (,$(filter mtd periph_flashpage,$(USEMODULE)))
USEMODULE += esp_idf_spi_flash
endif

View File

@ -113,6 +113,7 @@ PSEUDOMODULES += esp_hw_counter
PSEUDOMODULES += esp_idf_gpio_hal
PSEUDOMODULES += esp_i2c_hw
PSEUDOMODULES += esp_jtag
PSEUDOMODULES += esp_lcd_gpio
PSEUDOMODULES += esp_rtc_timer_32k
PSEUDOMODULES += esp_spi_ram
PSEUDOMODULES += esp_spi_oct
@ -167,6 +168,10 @@ ifneq (,$(filter esp_spi_ram,$(USEMODULE)))
INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/include/soc/$(CPU_FAM)
endif
ifneq (,$(filter esp_idf_lcd,$(USEMODULE)))
INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_lcd/include
endif
ifneq (,$(filter esp_idf_spi_flash,$(USEMODULE)))
INCLUDES += -I$(ESP32_SDK_DIR)/components/spi_flash/include
endif

View File

@ -26,6 +26,7 @@ rsource "eth/Kconfig"
rsource "event/Kconfig"
rsource "gpio/Kconfig"
rsource "heap/Kconfig"
rsource "lcd/Kconfig"
rsource "nvs_flash/Kconfig"
rsource "rmt/Kconfig"
rsource "spi_flash/Kconfig"

View File

@ -36,6 +36,10 @@ ifneq (,$(filter esp_idf_heap,$(USEMODULE)))
DIRS += heap
endif
ifneq (,$(filter esp_idf_lcd,$(USEMODULE)))
DIRS += lcd
endif
ifneq (,$(filter esp_idf_nvs_flash,$(USEMODULE)))
DIRS += nvs_flash
endif

View File

@ -10,6 +10,7 @@ config MODULE_ESP_IDF_HEAP
bool
depends on TEST_KCONFIG
depends on MODULE_ESP_IDF
default y if MODULE_LCD_PARALLEL_LL_MCU
select PACKAGE_TLSF
help
ESP-IDF heap library. This library is required if external SPI RAM

View File

@ -0,0 +1,16 @@
# Copyright (c) 2022 Gunar Schorcht
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
config MODULE_ESP_IDF_LCD
bool
depends on TEST_KCONFIG
depends on MODULE_ESP_IDF
default y if MODULE_LCD_PARALLEL_LL_MCU
help
ESP-IDF code for peripheral GPIO.

View File

@ -0,0 +1,36 @@
MODULE = esp_idf_lcd
# source files to be compiled for this module
ESP32_SDK_SRC = \
components/esp_lcd/src/esp_lcd_common.c \
components/esp_lcd/src/esp_lcd_panel_io.c \
components/esp_pm/pm_locks.c \
components/soc/$(CPU_FAM)/lcd_periph.c \
#
ifeq (esp32s3,$(CPU_FAM))
ESP32_SDK_SRC += \
components/driver/gdma.c \
components/esp_lcd/src/esp_lcd_panel_io_i80.c \
components/hal/gdma_hal.c \
components/hal/lcd_hal.c \
components/soc/$(CPU_FAM)/gdma_periph.c \
#
else ifneq (,$(filter esp32 esp32s2,$(CPU_FAM)))
ESP32_SDK_SRC = \
components/driver/i2s.c \
components/esp_lcd/src/esp_lcd_panel_io_i2s.c \
components/hal/i2s_hal.c \
#
endif
# additional include pathes required by this module
INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_lcd/include
INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_lcd/interface
include $(RIOTBASE)/Makefile.base
ESP32_SDK_BIN = $(BINDIR)/$(MODULE)
include ../esp_idf.mk
include ../esp_idf_cflags.mk

54
cpu/esp32/esp-lcd/Kconfig Normal file
View File

@ -0,0 +1,54 @@
# Copyright (c) 2023 Gunar Schorcht
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
menuconfig MODULE_ESP_LCD
bool "Enable LCD low-level parallel interface driver"
depends on MODULE_LCD
default y if HAVE_LCD_PARALLEL_LL_MCU
help
Enabe the MCU-driven low-level MCU 8080 8-/16-bit parallel interface
driver.
if MODULE_ESP_LCD
config MODULE_ESP_LCD_GPIO
bool "GPIO-driven low-level parallel interface driver"
depends on !CPU_FAM_ESP32 && !CPU_FAM_ESP32S2 && !CPU_FAM_ESP32S3
default y
help
The ESP32x SoC variant used does not have a peripheral for the parallel
low-level interface. However, it can be emulated with special low-level
GPIO operations. It is faster than the GPIO-driven 8-/16-bit parallel
interface implemented in the LCD driver, but requires 4 kByte RAM for
8-bit data bus width and 8 kByte RAM for 16-bit data bus width.
config LCD_WRITE_CLOCK_MHZ
int "LCD write clock rate in MHz"
range 1 80
depends on CPU_FAM_ESP32 || CPU_FAM_ESP32S2 || CPU_FAM_ESP32S3
default 10 if CPU_FAM_ESP32
default 40 if CPU_FAM_ESP32S2
default 20 if CPU_FAM_ESP32S3
help
Defines the clock rate that is used for the LCD write signal. It
depends on used ESP32x SoC variant and used display interface.
config LCD_DATA_BUF_SIZE
int "LCD data buffer size in byte"
depends on CPU_FAM_ESP32 || CPU_FAM_ESP32S2 || CPU_FAM_ESP32S3
default 512
help
Defines the size of the buffers used to write data to the LCD
screen. Since double buffering is used, there are two buffers
of this size. One buffer is used first by the LCD driver to
write the data that needs to be transferred to the LCD, and
one buffer from which the DMA then transfers the data to the
LCD peripherals. This allows data to be written before the
DMA transfer is complete. The larger the buffers, the better
the performance, but the higher the memory requirements.
endif

View File

@ -0,0 +1,9 @@
MODULE = esp_lcd
ifneq (,$(filter esp32 esp32s2 esp32s3,$(CPU_FAM)))
SRC = esp_lcd_mcu.c
else
SRC = esp_lcd_gpio.c
endif
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,269 @@
/*
* Copyright (C) 2023 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32
* @{
*
* @file
* @brief GPIO-driven low-Level parallel interface implementation for LCDs
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#include <assert.h>
#include "periph/gpio.h"
#include "lcd.h"
#include "ztimer.h"
#if MODULE_ESP_LCD_GPIO
#include "soc/gpio_reg.h"
#define ENABLE_DEBUG 0
#include "debug.h"
typedef struct {
uint32_t set_mask_0; /* port 0 set mask */
uint32_t set_mask_1; /* port 0 set mask */
uint32_t clr_mask_0; /* port 1 clear mask */
uint32_t clr_mask_1; /* port 1 clear mask */
} _pin_mask_t;
static _pin_mask_t _low_byte_masks[256] = {};
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
static _pin_mask_t _high_byte_masks[256] = {};
#endif
/*
* Following functions are not implemented by intention to let the
* GPIO-driven low-level implementation handle the configuration
* of the GPIOs. The function `_lcd_ll_mcu_set_data_dir` is used to
* initialize the GPIO masks when the clear masks are completely 0.
*/
#if 0
static void _lcd_ll_mcu_init(lcd_t *dev)
{
(void)dev;
}
static void _lcd_ll_mcu_cmd_start(lcd_t *dev, uint8_t cmd, bool cont)
{
(void)dev;
(void)cmd;
(void)cont;
}
#endif
static void _lcd_ll_mcu_set_data_dir(lcd_t *dev, bool output)
{
DEBUG("[lcd_ll_mcu] %s %u\n", __func__, output);
/* sanity check to ensure that data pins can be handled as array */
assert((&dev->params->d7_pin - &dev->params->d0_pin) == 7);
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
assert((&dev->params->d15_pin - &dev->params->d8_pin) == 7);
#endif
if ((_low_byte_masks[0].clr_mask_0 == 0) &&
(_low_byte_masks[0].clr_mask_1 == 0)) {
/* initialize the mask array if it is not yet initialized */
const gpio_t *pins = &dev->params->d0_pin;
for (unsigned data = 0; data < 256; data++) {
for (unsigned i = 0; i < 8; i++) {
if (data & (1 << i)) {
/* set mask */
if (pins[i] < 32) {
_low_byte_masks[data].set_mask_0 |= 1 << pins[i];
}
else {
_low_byte_masks[data].set_mask_1 |= 1 << (pins[i] - 32);
}
}
else {
/* clear mask */
if (pins[i] < 32) {
_low_byte_masks[data].clr_mask_0 |= 1 << pins[i];
}
else {
_low_byte_masks[data].clr_mask_1 |= 1 << (pins[i] - 32);
}
}
}
}
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
pins = &dev->params->d8_pin;
for (unsigned data = 0; data < 256; data++) {
for (unsigned i = 0; i < 8; i++) {
if (data & (1 << i)) {
/* set mask */
if (pins[i] < 32) {
_high_byte_masks[data].set_mask_0 |= 1 << pins[i];
}
else {
_high_byte_masks[data].set_mask_1 |= 1 << (pins[i] - 32);
}
}
else {
/* clear mask */
if (pins[i] < 32) {
_high_byte_masks[data].clr_mask_0 |= 1 << pins[i];
}
else {
_high_byte_masks[data].clr_mask_1 |= 1 << (pins[i] - 32);
}
}
}
}
#endif
}
gpio_init(dev->params->d0_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d1_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d2_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d3_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d4_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d5_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d6_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d7_pin, output ? GPIO_OUT : GPIO_IN);
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
gpio_init(dev->params->d8_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d9_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d10_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d11_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d12_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d13_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d14_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d15_pin, output ? GPIO_OUT : GPIO_IN);
#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */
}
static void _lcd_ll_mcu_write_data(lcd_t *dev, bool cont,
uint16_t data, unsigned pin_num)
{
if (gpio_is_valid(dev->params->cs_pin)) {
gpio_clear(dev->params->cs_pin);
}
gpio_clear(dev->params->wrx_pin);
uint8_t _byte = data & 0xff;
uint32_t set_mask_0 = _low_byte_masks[_byte].set_mask_0;
uint32_t clr_mask_0 = _low_byte_masks[_byte].clr_mask_0;
uint32_t set_mask_1 = _low_byte_masks[_byte].set_mask_1;
uint32_t clr_mask_1 = _low_byte_masks[_byte].clr_mask_1;
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
_byte = data >> 8;
set_mask_0 |= _high_byte_masks[_byte].set_mask_0;
clr_mask_0 |= _high_byte_masks[_byte].clr_mask_0;
set_mask_1 |= _high_byte_masks[_byte].set_mask_1;
clr_mask_1 |= _high_byte_masks[_byte].clr_mask_1;
#endif
*((uint32_t *)GPIO_OUT_W1TS_REG) = set_mask_0;
*((uint32_t *)GPIO_OUT_W1TC_REG) = clr_mask_0;
*((uint32_t *)GPIO_OUT1_W1TS_REG) = set_mask_1;
*((uint32_t *)GPIO_OUT1_W1TC_REG) = clr_mask_1;
gpio_set(dev->params->wrx_pin);
if (gpio_is_valid(dev->params->cs_pin) && !cont) {
gpio_set(dev->params->cs_pin);
}
}
static uint16_t _lcd_ll_mcu_read_data(lcd_t *dev, bool cont, unsigned pin_num)
{
const gpio_t *pins = &dev->params->d0_pin;
if (gpio_is_valid(dev->params->cs_pin)) {
gpio_clear(dev->params->cs_pin);
}
gpio_clear(dev->params->rdx_pin);
uint32_t in_0 = *((uint32_t *)GPIO_IN_REG);
uint32_t in_1 = *((uint32_t *)GPIO_IN1_REG);
gpio_set(dev->params->rdx_pin);
if (gpio_is_valid(dev->params->cs_pin) && !cont) {
gpio_set(dev->params->cs_pin);
};
uint16_t in = 0;
for (unsigned i = 0; i < pin_num; i++) {
if (pins[i] < 32) {
in |= in_0 & (1 << pins[i]) ? 1 : 0;
}
else {
in |= in_1 & (1 << (pins[i] - 32)) ? 1 : 0;
}
}
return in;
}
static void _lcd_ll_mcu_write_byte(lcd_t *dev, bool cont, uint8_t out)
{
DEBUG("[lcd_ll_mcu] write byte: %02x\n", out);
_lcd_ll_mcu_write_data(dev, cont, out, 8);
}
static uint8_t _lcd_ll_mcu_read_byte(lcd_t *dev, bool cont)
{
return _lcd_ll_mcu_read_data(dev, cont, 8);
}
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
static void _lcd_ll_mcu_write_word(lcd_t *dev, bool cont, uint16_t out)
{
DEBUG("[lcd_ll_mcu] write word: %04x\n", out);
_lcd_ll_mcu_write_data(dev, cont, out, 16);
}
static uint16_t _lcd_ll_mcu_read_word(lcd_t *dev, bool cont)
{
return _lcd_ll_mcu_read_data(dev, cont, 16);
}
#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */
const lcd_ll_par_driver_t lcd_ll_par_driver = {
.init = lcd_ll_par_gpio_init, /* GPIO-driven `init` is used */
.set_data_dir = _lcd_ll_mcu_set_data_dir,
.cmd_start = lcd_ll_par_gpio_cmd_start, /* GPIO-driven `cmd_start` is used */
.write_byte = _lcd_ll_mcu_write_byte,
.read_byte = _lcd_ll_mcu_read_byte,
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
.write_word = _lcd_ll_mcu_write_word,
.read_word = _lcd_ll_mcu_read_word,
#endif
};
#else /* MODULE_ESP_LCD_GPIO */
/* the GPIO-driven low-level interface is not used */
const lcd_ll_par_driver_t lcd_ll_par_driver = {
};
#endif /* MODULE_ESP_LCD_GPIO */

View File

@ -0,0 +1,260 @@
/*
* Copyright (C) 2023 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32
* @{
*
* @file
* @brief Peripheral low-Level parallel interface implementation for LCDs
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#include <assert.h>
#include <string.h>
#include "lcd.h"
#include "lcd_internal.h"
#include "log.h"
#include "macros/units.h"
#include "periph/gpio.h"
#include "ztimer.h"
#include "esp_lcd_panel_io.h"
#include "soc/gpio_reg.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#if !defined(CPU_FAM_ESP32) && !defined(CPU_FAM_ESP32S2) && !defined(CPU_FAM_ESP32S3)
#error "ESP32x SoC family not supported"
#endif
#ifndef CONFIG_LCD_WRITE_CLOCK_MHZ
#if CONFIG_LCD_I80_COLOR_IN_PSRAM
/* PCLK has to be low enough for SPI RAM */
#define CONFIG_LCD_WRITE_CLOCK_MHZ 2
#else
#if defined(CPU_FAM_ESP32S3)
#define CONFIG_LCD_WRITE_CLOCK_MHZ 20
#elif defined(CPU_FAM_ESP32S2)
#define CONFIG_LCD_WRITE_CLOCK_MHZ 40
#else /* ESP32 */
#define CONFIG_LCD_WRITE_CLOCK_MHZ 10
#endif
#endif /* CONFIG_LCD_I80_COLOR_IN_PSRAM */
#endif /* CONFIG_LCD_WRITE_CLOCK_MHZ */
static_assert(CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE >= 32,
"CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE mus be at least 32");
/* ESP32x SoCs support only one LCD peripheral so we can use single instances
* of the following variables */
int _cmd = -1; /* means no command needed in ESP-IDF */
size_t _idx_bytes = 0;
uint8_t _data_bytes[CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE];
uint8_t _trans_bytes[CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE];
esp_lcd_i80_bus_handle_t _i80_bus_handle = NULL;
esp_lcd_panel_io_handle_t _i80_io_handle = NULL;
/* indicates that a transfer of the data buffer is still in progress and must
* not be overwritten */
static bool _dma_transfer_in_progress = false;
static bool _dma_transfer_done(esp_lcd_panel_io_handle_t io_handle,
esp_lcd_panel_io_event_data_t *io_event_data,
void *user_ctx)
{
(void)io_handle;
(void)io_event_data;
(void)user_ctx;
_dma_transfer_in_progress = false;
return false;
}
static void _lcd_ll_mcu_init(lcd_t *dev)
{
esp_lcd_i80_bus_config_t i80_bus_config = {
.dc_gpio_num = dev->params->dcx_pin,
.wr_gpio_num = dev->params->wrx_pin,
.clk_src = LCD_CLK_SRC_PLL160M,
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
.data_gpio_nums = {
dev->params->d0_pin,
dev->params->d1_pin,
dev->params->d2_pin,
dev->params->d3_pin,
dev->params->d4_pin,
dev->params->d5_pin,
dev->params->d6_pin,
dev->params->d7_pin,
dev->params->d8_pin,
dev->params->d9_pin,
dev->params->d10_pin,
dev->params->d11_pin,
dev->params->d12_pin,
dev->params->d13_pin,
dev->params->d14_pin,
dev->params->d15_pin,
},
.bus_width = 16,
#else
.data_gpio_nums = {
dev->params->d0_pin,
dev->params->d1_pin,
dev->params->d2_pin,
dev->params->d3_pin,
dev->params->d4_pin,
dev->params->d5_pin,
dev->params->d6_pin,
dev->params->d7_pin,
},
.bus_width = 8,
#endif
.max_transfer_bytes = dev->params->rgb_channels * 40 * sizeof(uint16_t),
};
esp_lcd_panel_io_i80_config_t i80_io_config = {
.cs_gpio_num = gpio_is_valid(dev->params->cs_pin) ? (int)dev->params->cs_pin
: -1,
.pclk_hz = MHZ(CONFIG_LCD_WRITE_CLOCK_MHZ),
.trans_queue_depth = 10,
.dc_levels = {
.dc_idle_level = 0,
.dc_cmd_level = 0,
.dc_dummy_level = 1,
.dc_data_level = 1,
},
.on_color_trans_done = _dma_transfer_done,
.user_ctx = NULL,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
};
esp_lcd_new_i80_bus(&i80_bus_config, &_i80_bus_handle);
esp_lcd_new_panel_io_i80(_i80_bus_handle, &i80_io_config, &_i80_io_handle);
if (gpio_is_valid(dev->params->rdx_pin)) {
gpio_init(dev->params->rdx_pin, GPIO_IN_PU);
gpio_set(dev->params->rdx_pin);
}
if (gpio_is_valid(dev->params->cs_pin)) {
gpio_init(dev->params->cs_pin, GPIO_OUT);
gpio_clear(dev->params->cs_pin);
}
}
static void _lcd_ll_mcu_set_data_dir(lcd_t *dev, bool output)
{
(void)dev;
(void)output;
LOG_ERROR("[lcd_ll_mcu] set dir: %d is not supported\n", output);
/* not supported yet */
}
static void _lcd_ll_mcu_cmd_start(lcd_t *dev, uint8_t cmd, bool cont)
{
DEBUG("[lcd_ll_mcu] write cmd: %02x\n", cmd);
if (!cont) {
/* cmd without parameters */
esp_lcd_panel_io_tx_param(_i80_io_handle, cmd, NULL, 0);
_cmd = -1;
}
else {
/* cmd with parameters */
_cmd = cmd;
}
}
static void _lcd_ll_mcu_transfer(lcd_t *dev, bool cont)
{
if (!cont) {
/* if no further data follow, send the command with the data in the buffer */
esp_lcd_panel_io_tx_param(_i80_io_handle, _cmd, _data_bytes, _idx_bytes);
_cmd = -1;
_idx_bytes = 0;
}
else if (_idx_bytes == CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE) {
/* spin lock as long as a DMA data transfer is still in progress */
while (_dma_transfer_in_progress) {}
/* copy data buffer to the DMA transfer buffer */
memcpy(_trans_bytes, _data_bytes, _idx_bytes);
/* start DMA data transfer */
_dma_transfer_in_progress = true;
esp_lcd_panel_io_tx_color(_i80_io_handle, _cmd, _data_bytes, _idx_bytes);
/* It should only be possible to follow more data than
* CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE with the RAMWR command.
* Transferring more data to continue the operation with cmd=-1 does
* not seem to work. Therefore a RAMWRC generated in this
* case for further data */
_cmd = (_cmd == LCD_CMD_RAMWR) ? LCD_CMD_RAMWRC : _cmd;
_idx_bytes = 0;
}
}
static void _lcd_ll_mcu_write_byte(lcd_t *dev, bool cont, uint8_t out)
{
DEBUG("[lcd_ll_mcu] write byte: %02x\n", out);
_data_bytes[_idx_bytes++] = out;
/* transfer the data if necessary */
_lcd_ll_mcu_transfer(dev, cont);
}
static uint8_t _lcd_ll_mcu_read_byte(lcd_t *dev, bool cont)
{
LOG_ERROR("[lcd_ll_mcu] read from LCD is not supported\n");
return 0;
}
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
static void _lcd_ll_mcu_write_word(lcd_t *dev, bool cont, uint16_t out)
{
DEBUG("[lcd_ll_mcu] write word: %04x\n", out);
/* out is given in BE order */
_data_bytes[_idx_bytes++] = out >> 8;
_data_bytes[_idx_bytes++] = out & 0xff;
/* transfer the data if necessary */
_lcd_ll_mcu_transfer(dev, cont);
}
static uint16_t _lcd_ll_mcu_read_word(lcd_t *dev, bool cont)
{
LOG_ERROR("[lcd_ll_mcu] read from LCD is not supported\n");
/* not supported yet */
return 0;
}
#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */
const lcd_ll_par_driver_t lcd_ll_par_driver = {
.init = _lcd_ll_mcu_init,
.set_data_dir = _lcd_ll_mcu_set_data_dir,
.cmd_start = _lcd_ll_mcu_cmd_start,
.write_byte = _lcd_ll_mcu_write_byte,
.read_byte = _lcd_ll_mcu_read_byte,
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
.write_word = _lcd_ll_mcu_write_word,
.read_word = _lcd_ll_mcu_read_word,
#endif
};

View File

@ -47,6 +47,7 @@ extern "C" {
#define CPU_INUM_WDT 13 /**< Level interrupt with low priority 1 */
#define CPU_INUM_SOFTWARE 17 /**< Level interrupt with low priority 1 */
#define CPU_INUM_ETH 18 /**< Level interrupt with low priority 1 */
#define CPU_INUM_LCD 18 /**< Level interrupt with low priority 1 */
#define CPU_INUM_TIMER 19 /**< Level interrupt with medium priority 2 */
#define CPU_INUM_FRC2 20 /**< Level interrupt with medium priority 2 */
#define CPU_INUM_SYSTIMER 20 /**< Level interrupt with medium priority 2 */

View File

@ -233,6 +233,17 @@
#endif /* !CONFIG_ESP_FLASHPAGE_CAPACITY */
/**
* LCD driver configuration
*/
#if MODULE_ESP_IDF_LCD
#ifndef CONFIG_LCD_DATA_BUF_SIZE
#define CONFIG_LCD_DATA_BUF_SIZE 512
#endif
#define CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE CONFIG_LCD_DATA_BUF_SIZE
#endif
#endif /* DOXYGEN */
/**

View File

@ -87,10 +87,19 @@ static const struct intr_handle_data_t _irq_data_table[] = {
{ ETS_USB_SERIAL_JTAG_INTR_SOURCE, CPU_INUM_SERIAL_JTAG, 1 },
#endif
{ ETS_RMT_INTR_SOURCE, CPU_INUM_RMT, 1 },
#if defined(CPU_FAM_ESP32) || defined(CPU_FAM_ESP32S2)
{ ETS_I2S0_INTR_SOURCE, CPU_INUM_LCD, 1 },
#elif defined(CPU_FAM_ESP32S3)
{ ETS_LCD_CAM_INTR_SOURCE, CPU_INUM_LCD, 1 },
#endif
};
#define IRQ_DATA_TABLE_SIZE ARRAY_SIZE(_irq_data_table)
#if defined(CPU_FAM_ESP32) && MODULE_ESP_LCD && MODULE_ESP_ETH
#error "esp_eth and esp_lcd can't be used at the same time because of an interrupt conflict"
#endif
void esp_irq_init(void)
{
#ifdef SOC_CPU_HAS_FLEXIBLE_INTC
@ -172,6 +181,17 @@ esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler,
return ESP_OK;
}
esp_err_t esp_intr_alloc_intrstatus(int source, int flags,
uint32_t reg, uint32_t mask,
intr_handler_t handler,
void *arg, intr_handle_t *ret_handle)
{
/* TODO status register and status mask handling for shared interrupts */
(void)reg;
(void)mask;
return esp_intr_alloc(source, flags, handler, arg, ret_handle);
}
esp_err_t esp_intr_free(intr_handle_t handle)
{
return esp_intr_disable(handle);

View File

@ -26,18 +26,19 @@
* @}
*/
#include <time.h>
#include <sys/time.h>
#include <err.h>
#include <signal.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#include <sys/time.h>
#include <time.h>
#include "cpu.h"
#include "cpu_conf.h"
#include "native_internal.h"
#include "periph/timer.h"
#include "time_units.h"
#define ENABLE_DEBUG 0
#include "debug.h"
@ -49,7 +50,9 @@ static unsigned long time_null;
static timer_cb_t _callback;
static void *_cb_arg;
static struct itimerval itv;
static struct itimerspec its;
static timer_t itimer_monotonic;
/**
* returns ticks for give timespec
@ -89,8 +92,15 @@ int timer_init(tim_t dev, uint32_t freq, timer_cb_t cb, void *arg)
_callback = cb;
_cb_arg = arg;
if (timer_create(CLOCK_MONOTONIC, NULL, &itimer_monotonic) != 0) {
DEBUG_PUTS("Failed to create a monotonic itimer");
return -1;
}
if (register_interrupt(SIGALRM, native_isr_timer) != 0) {
DEBUG("darn!\n\n");
DEBUG_PUTS("Failed to register SIGALRM handler");
return -1;
}
return 0;
@ -104,14 +114,14 @@ static void do_timer_set(unsigned int offset, bool periodic)
offset = NATIVE_TIMER_MIN_RES;
}
memset(&itv, 0, sizeof(itv));
itv.it_value.tv_sec = (offset / 1000000);
itv.it_value.tv_usec = offset % 1000000;
memset(&its, 0, sizeof(its));
its.it_value.tv_sec = offset / NATIVE_TIMER_SPEED;
its.it_value.tv_nsec = (offset % NATIVE_TIMER_SPEED) * (NS_PER_SEC / NATIVE_TIMER_SPEED);
if (periodic) {
itv.it_interval = itv.it_value;
its.it_interval = its.it_value;
}
DEBUG("timer_set(): setting %lu.%06lu\n", itv.it_value.tv_sec, itv.it_value.tv_usec);
DEBUG("timer_set(): setting %lu.%09lu\n", (unsigned long)its.it_value.tv_sec, its.it_value.tv_nsec);
}
int timer_set(tim_t dev, int channel, unsigned int offset)
@ -171,8 +181,8 @@ void timer_start(tim_t dev)
DEBUG("%s\n", __func__);
_native_syscall_enter();
if (real_setitimer(ITIMER_REAL, &itv, NULL) == -1) {
err(EXIT_FAILURE, "timer_arm: setitimer");
if (timer_settime(itimer_monotonic, 0, &its, NULL) == -1) {
err(EXIT_FAILURE, "timer_start: timer_settime");
}
_native_syscall_leave();
}
@ -183,13 +193,13 @@ void timer_stop(tim_t dev)
DEBUG("%s\n", __func__);
_native_syscall_enter();
struct itimerval zero = {0};
if (real_setitimer(ITIMER_REAL, &zero, &itv) == -1) {
err(EXIT_FAILURE, "timer_arm: setitimer");
struct itimerspec zero = {0};
if (timer_settime(itimer_monotonic, 0, &zero, &its) == -1) {
err(EXIT_FAILURE, "timer_stop: timer_settime");
}
_native_syscall_leave();
DEBUG("time left: %lu.%06lu\n", itv.it_value.tv_sec, itv.it_value.tv_usec);
DEBUG("time left: %lu.%09lu\n", (unsigned long)its.it_value.tv_sec, its.it_value.tv_nsec);
}
unsigned int timer_read(tim_t dev)

View File

@ -88,8 +88,6 @@ int (*real_pause)(void);
int (*real_pipe)(int[2]);
int (*real_select)(int nfds, ...);
int (*real_poll)(struct pollfd *fds, ...);
int (*real_setitimer)(int which, const struct itimerval
*restrict value, struct itimerval *restrict ovalue);
int (*real_setsid)(void);
int (*real_setsockopt)(int socket, ...);
int (*real_socket)(int domain, int type, int protocol);
@ -535,7 +533,6 @@ void _native_init_syscalls(void)
*(void **)(&real_dup2) = dlsym(RTLD_NEXT, "dup2");
*(void **)(&real_select) = dlsym(RTLD_NEXT, "select");
*(void **)(&real_poll) = dlsym(RTLD_NEXT, "poll");
*(void **)(&real_setitimer) = dlsym(RTLD_NEXT, "setitimer");
*(void **)(&real_setsid) = dlsym(RTLD_NEXT, "setsid");
*(void **)(&real_setsockopt) = dlsym(RTLD_NEXT, "setsockopt");
*(void **)(&real_socket) = dlsym(RTLD_NEXT, "socket");

View File

@ -34,7 +34,6 @@ extern "C" {
* @brief Redefine some peripheral names to unify them between nRF51 and 52
* @{
*/
#define UART_IRQN (UART0_IRQn)
#define SPI_SCKSEL (dev(bus)->PSELSCK)
#define SPI_MOSISEL (dev(bus)->PSELMOSI)
#define SPI_MISOSEL (dev(bus)->PSELMISO)

View File

@ -103,7 +103,7 @@ static int write(i2c_t dev, uint16_t addr, const void *data, int len,
}
}
return len;
return 0;
}
void i2c_init(i2c_t dev)
@ -198,7 +198,7 @@ int i2c_read_bytes(i2c_t dev, uint16_t address, void *data, size_t length,
while (i2c(dev)->EVENTS_STOPPED == 0) {}
NRF_PPI->CHENCLR = (1 << i2c_config[dev].ppi);
return length;
return 0;
}
int i2c_read_regs(i2c_t dev, uint16_t address, uint16_t reg,

View File

@ -19,19 +19,18 @@ config CPU_FAM_NRF52
select HAS_CPU_NRF52
select HAS_PERIPH_I2C_RECONFIGURE
select HAS_PERIPH_SPI_GPIO_MODE
select HAS_PERIPH_UART_NONBLOCKING
## CPU Models
config CPU_MODEL_NRF52805XXAA
bool
select CPU_CORE_CORTEX_M4
select CPU_FAM_NRF52
select HAS_PERIPH_UART_NONBLOCKING
config CPU_MODEL_NRF52810XXAA
bool
select CPU_CORE_CORTEX_M4
select CPU_FAM_NRF52
select HAS_PERIPH_UART_NONBLOCKING
config CPU_MODEL_NRF52811XXAA
bool
@ -39,7 +38,6 @@ config CPU_MODEL_NRF52811XXAA
select CPU_FAM_NRF52
select HAS_BLE_PHY_CODED
select HAS_RADIO_NRF802154
select HAS_PERIPH_UART_NONBLOCKING
config CPU_MODEL_NRF52820XXAA
bool
@ -47,7 +45,6 @@ config CPU_MODEL_NRF52820XXAA
select CPU_FAM_NRF52
select HAS_BLE_PHY_CODED
select HAS_RADIO_NRF802154
select HAS_PERIPH_UART_NONBLOCKING
config CPU_MODEL_NRF52832XXAA
bool
@ -60,7 +57,6 @@ config CPU_MODEL_NRF52833XXAA
select CPU_FAM_NRF52
select HAS_BLE_PHY_CODED
select HAS_RADIO_NRF802154
select HAS_PERIPH_UART_NONBLOCKING
config CPU_MODEL_NRF52840XXAA
bool
@ -68,7 +64,6 @@ config CPU_MODEL_NRF52840XXAA
select CPU_FAM_NRF52
select HAS_BLE_PHY_CODED
select HAS_RADIO_NRF802154
select HAS_PERIPH_UART_NONBLOCKING
select HAS_PERIPH_HASH_SHA_1
select HAS_PERIPH_HASH_SHA_224
select HAS_PERIPH_HASH_SHA_256

View File

@ -23,9 +23,9 @@ ifneq (,$(filter nrf52840xxaa,$(CPU_MODEL)))
FEATURES_PROVIDED += periph_ecc_ed25519
endif
ifeq (,$(filter nrf52832%,$(CPU_MODEL)))
FEATURES_PROVIDED += periph_uart_nonblocking
endif
# All nRF52 CPUs use UARTE (UART + EasyDMA) for UART, so that can be used
# in non-blocking mode
FEATURES_PROVIDED += periph_uart_nonblocking
# The ADC does not depend on any board configuration, so always available
FEATURES_PROVIDED += periph_adc

View File

@ -66,9 +66,9 @@ extern "C" {
* The port definition is used (and zeroed) to suppress compiler warnings
*/
#if GPIO_COUNT > 1
#define GPIO_PIN(x,y) ((x << 5) | y)
#define GPIO_PIN(x, y) ((x << 5) | y)
#else
#define GPIO_PIN(x,y) ((x & 0) | y)
#define GPIO_PIN(x, y) ((x & 0) | y)
#endif
/**
@ -316,13 +316,16 @@ typedef struct {
*/
uint8_t gpio_int_get_exti(gpio_t pin);
#if !defined(CPU_MODEL_NRF52832XXAA) && !defined(CPU_FAM_NRF51)
/**
* @brief Structure for UART configuration data
*/
typedef struct {
#ifdef UARTE_PRESENT
NRF_UARTE_Type *dev; /**< UART with EasyDMA device base
* register address */
#else
NRF_UART_Type *dev; /**< UART device base register address */
#endif
gpio_t rx_pin; /**< RX pin */
gpio_t tx_pin; /**< TX pin */
#ifdef MODULE_PERIPH_UART_HW_FC
@ -339,8 +342,6 @@ typedef struct {
#define UART_TXBUF_SIZE (64)
#endif
#endif /* ndef CPU_MODEL_NRF52832XXAA && ndef CPU_FAM_NRF51 */
/**
* @brief USBDEV buffers must be word aligned because of DMA restrictions
*/
@ -407,9 +408,6 @@ typedef struct {
#define SPI_SCKSEL (dev(bus)->PSEL.SCK) /**< Macro for SPI clk */
#define SPI_MOSISEL (dev(bus)->PSEL.MOSI) /**< Macro for SPI mosi */
#define SPI_MISOSEL (dev(bus)->PSEL.MISO) /**< Macro for SPI miso */
#ifdef CPU_MODEL_NRF52832XXAA
#define UART_IRQN (UARTE0_UART0_IRQn)
#endif
/**
* @brief SPI configuration values

View File

@ -28,28 +28,32 @@
* @}
*/
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include "compiler_hints.h"
#include "cpu.h"
#include "periph/uart.h"
#include "periph/gpio.h"
#include "periph/uart.h"
#if !defined(CPU_MODEL_NRF52832XXAA) && !defined(CPU_FAM_NRF51)
#define UART_INVALID (uart >= UART_NUMOF)
#define REG_BAUDRATE dev(uart)->BAUDRATE
#define REG_CONFIG dev(uart)->CONFIG
#define PSEL_RXD dev(uart)->PSEL.RXD
#define PSEL_TXD dev(uart)->PSEL.TXD
#define UART_IRQN uart_config[uart].irqn
#define UART_PIN_RX uart_config[uart].rx_pin
#define UART_PIN_TX uart_config[uart].tx_pin
#ifdef MODULE_PERIPH_UART_HW_FC
#define UART_PIN_RTS uart_config[uart].rts_pin
#define UART_PIN_CTS uart_config[uart].cts_pin
#ifdef UARTE_PRESENT
# define PSEL_RXD PSEL.RXD
# define PSEL_TXD PSEL.TXD
# define PSEL_RTS PSEL.RTS
# define PSEL_CTS PSEL.CTS
# define ENABLE_ON UARTE_ENABLE_ENABLE_Enabled
# define ENABLE_OFF UARTE_ENABLE_ENABLE_Disabled
# define UART_TYPE NRF_UARTE_Type
#else
# define PSEL_RXD PSELRXD
# define PSEL_TXD PSELTXD
# define PSEL_RTS PSELRTS
# define PSEL_CTS PSELCTS
# define ENABLE_ON UART_ENABLE_ENABLE_Enabled
# define ENABLE_OFF UART_ENABLE_ENABLE_Disabled
# define UART_TYPE NRF_UART_Type
#endif
#define ISR_CTX isr_ctx[uart]
#define RAM_MASK (0x20000000)
/**
@ -63,7 +67,9 @@
* @brief Allocate memory for the interrupt context
*/
static uart_isr_ctx_t isr_ctx[UART_NUMOF];
#ifdef UARTE_PRESENT
static uint8_t rx_buf[UART_NUMOF];
#endif
#ifdef MODULE_PERIPH_UART_NONBLOCKING
@ -81,149 +87,126 @@ static uint8_t uart_tx_rb_buf[UART_NUMOF][UART_TXBUF_SIZE];
*/
void uart_isr_handler(void *arg);
static inline NRF_UARTE_Type *dev(uart_t uart)
{
return uart_config[uart].dev;
}
#else /* nrf51 and nrf52832 etc */
#define UART_INVALID (uart != 0)
#define REG_BAUDRATE NRF_UART0->BAUDRATE
#define REG_CONFIG NRF_UART0->CONFIG
#define PSEL_RXD NRF_UART0->PSELRXD
#define PSEL_TXD NRF_UART0->PSELTXD
#define UART_0_ISR isr_uart0
#define ISR_CTX isr_ctx
/**
* @brief Allocate memory for the interrupt context
*/
static uart_isr_ctx_t isr_ctx;
#endif /* !CPU_MODEL_NRF52832XXAA && !CPU_FAM_NRF51 */
/* use an enum to count the number of UART ISR macro names defined by the
* board */
enum {
#ifdef UART_0_ISR
UART_0_ISR_NUM,
#endif
#ifdef UART_1_ISR
UART_1_ISR_NUM,
#endif
UART_ISR_NUMOF,
};
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
{
if (UART_INVALID) {
/* ensure the ISR names have been defined as needed */
#if !defined(CPU_NRF53) && !defined(CPU_NRF9160)
static_assert(UART_NUMOF == UART_ISR_NUMOF, "Define(s) of UART ISR name(s) missing");
#endif
if ((unsigned)uart >= UART_NUMOF) {
return UART_NODEV;
}
/* remember callback addresses and argument */
ISR_CTX.rx_cb = rx_cb;
ISR_CTX.arg = arg;
UART_TYPE *dev = uart_config[uart].dev;
#ifdef CPU_FAM_NRF51
/* power on the UART device */
NRF_UART0->POWER = 1;
/* remember callback addresses and argument */
isr_ctx[uart].rx_cb = rx_cb;
isr_ctx[uart].arg = arg;
#ifndef UARTE_PRESENT
/* only the legacy non-EasyDMA UART needs to be powered on explicitly */
dev->POWER = 1;
#endif
/* reset configuration registers */
REG_CONFIG = 0;
dev->CONFIG = 0;
/* configure RX pin */
if (rx_cb) {
gpio_init(UART_PIN_RX, GPIO_IN);
PSEL_RXD = UART_PIN_RX;
gpio_init(uart_config[uart].rx_pin, GPIO_IN);
dev->PSEL_RXD = uart_config[uart].rx_pin;
}
/* configure TX pin */
gpio_init(UART_PIN_TX, GPIO_OUT);
PSEL_TXD = UART_PIN_TX;
gpio_init(uart_config[uart].tx_pin, GPIO_OUT);
dev->PSEL_TXD = uart_config[uart].tx_pin;
#if !defined(CPU_MODEL_NRF52832XXAA) && !defined(CPU_FAM_NRF51)
/* enable HW-flow control if defined */
#ifdef MODULE_PERIPH_UART_HW_FC
/* set pin mode for RTS and CTS pins */
if (UART_PIN_RTS != GPIO_UNDEF && UART_PIN_CTS != GPIO_UNDEF) {
gpio_init(UART_PIN_RTS, GPIO_OUT);
gpio_init(UART_PIN_CTS, GPIO_IN);
/* configure RTS and CTS pins to use */
dev(uart)->PSEL.RTS = UART_PIN_RTS;
dev(uart)->PSEL.CTS = UART_PIN_CTS;
REG_CONFIG |= UART_CONFIG_HWFC_Msk; /* enable HW flow control */
}
#else
dev(uart)->PSEL.RTS = 0xffffffff; /* pin disconnected */
dev(uart)->PSEL.CTS = 0xffffffff; /* pin disconnected */
#endif
#else
#ifdef MODULE_PERIPH_UART_HW_FC
/* set pin mode for RTS and CTS pins */
if (UART_PIN_RTS != GPIO_UNDEF && UART_PIN_CTS != GPIO_UNDEF) {
gpio_init(UART_PIN_RTS, GPIO_OUT);
gpio_init(UART_PIN_CTS, GPIO_IN);
if (uart_config[uart].rts_pin != GPIO_UNDEF && uart_config[uart].cts_pin != GPIO_UNDEF) {
gpio_init(uart_config[uart].rts_pin, GPIO_OUT);
gpio_init(uart_config[uart].cts_pin, GPIO_IN);
/* configure RTS and CTS pins to use */
NRF_UART0->PSELRTS = UART_PIN_RTS;
NRF_UART0->PSELCTS = UART_PIN_CTS;
REG_CONFIG |= UART_CONFIG_HWFC_Msk; /* enable HW flow control */
dev->PSEL_RTS = uart_config[uart].rts_pin;
dev->PSEL_CTS = uart_config[uart].cts_pin;
dev->CONFIG |= UART_CONFIG_HWFC_Msk; /* enable HW flow control */
}
#else
NRF_UART0->PSELRTS = 0xffffffff; /* pin disconnected */
NRF_UART0->PSELCTS = 0xffffffff; /* pin disconnected */
#endif /* MODULE_PERIPH_UART_HW_FC */
else
#endif
{
dev->PSEL_RTS = 0xffffffff; /* pin disconnected */
dev->PSEL_CTS = 0xffffffff; /* pin disconnected */
}
/* select baudrate */
switch (baudrate) {
case 1200:
REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud1200;
break;
case 2400:
REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud2400;
break;
case 4800:
REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud4800;
break;
case 9600:
REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud9600;
break;
case 14400:
REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud14400;
break;
case 19200:
REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud19200;
break;
case 28800:
REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud28800;
break;
case 38400:
REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud38400;
break;
case 57600:
REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud57600;
break;
case 76800:
REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud76800;
break;
case 115200:
REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud115200;
break;
case 230400:
REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud230400;
break;
case 250000:
REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud250000;
break;
case 460800:
REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud460800;
break;
case 921600:
REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud921600;
break;
case 1000000:
REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud1M;
break;
default:
return UART_NOBAUD;
case 1200:
dev->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud1200;
break;
case 2400:
dev->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud2400;
break;
case 4800:
dev->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud4800;
break;
case 9600:
dev->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud9600;
break;
case 14400:
dev->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud14400;
break;
case 19200:
dev->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud19200;
break;
case 28800:
dev->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud28800;
break;
case 38400:
dev->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud38400;
break;
case 57600:
dev->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud57600;
break;
case 76800:
dev->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud76800;
break;
case 115200:
dev->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud115200;
break;
case 230400:
dev->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud230400;
break;
case 250000:
dev->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud250000;
break;
case 460800:
dev->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud460800;
break;
case 921600:
dev->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud921600;
break;
case 1000000:
dev->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud1M;
break;
default:
return UART_NOBAUD;
}
/* enable the UART device */
#if !defined(CPU_MODEL_NRF52832XXAA) && !defined(CPU_FAM_NRF51)
dev(uart)->ENABLE = UARTE_ENABLE_ENABLE_Enabled;
#else
NRF_UART0->ENABLE = UART_ENABLE_ENABLE_Enabled;
#endif
dev->ENABLE = ENABLE_ON;
#ifdef MODULE_PERIPH_UART_NONBLOCKING
/* set up the TX buffer */
@ -231,60 +214,60 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
#endif
if (rx_cb) {
#if !defined(CPU_MODEL_NRF52832XXAA) && !defined(CPU_FAM_NRF51)
dev(uart)->RXD.MAXCNT = 1;
dev(uart)->RXD.PTR = (uint32_t)&rx_buf[uart];
dev(uart)->INTENSET = UARTE_INTENSET_ENDRX_Msk;
dev(uart)->SHORTS |= UARTE_SHORTS_ENDRX_STARTRX_Msk;
dev(uart)->TASKS_STARTRX = 1;
#ifdef UARTE_PRESENT
dev->RXD.MAXCNT = 1;
dev->RXD.PTR = (uint32_t)&rx_buf[uart];
dev->INTENSET = UARTE_INTENSET_ENDRX_Msk;
dev->SHORTS |= UARTE_SHORTS_ENDRX_STARTRX_Msk;
dev->TASKS_STARTRX = 1;
#else
NRF_UART0->INTENSET = UART_INTENSET_RXDRDY_Msk;
NRF_UART0->TASKS_STARTRX = 1;
dev->INTENSET = UART_INTENSET_RXDRDY_Msk;
dev->TASKS_STARTRX = 1;
#endif
}
if (rx_cb || IS_USED(MODULE_PERIPH_UART_NONBLOCKING)) {
#if defined(CPU_NRF53) || defined(CPU_NRF9160)
shared_irq_register_uart(dev(uart), uart_isr_handler, (void *)(uintptr_t)uart);
shared_irq_register_uart(dev, uart_isr_handler, (void *)(uintptr_t)uart);
#else
NVIC_EnableIRQ(UART_IRQN);
NVIC_EnableIRQ(uart_config[uart].irqn);
#endif
}
return UART_OK;
}
/* nrf52840 || nrf52811 (using EasyDMA) */
#if !defined(CPU_MODEL_NRF52832XXAA) && !defined(CPU_FAM_NRF51)
/* UART with EasyDMA */
#ifdef UARTE_PRESENT
static void _write_buf(uart_t uart, const uint8_t *data, size_t len)
{
dev(uart)->EVENTS_ENDTX = 0;
uart_config[uart].dev->EVENTS_ENDTX = 0;
if (IS_USED(MODULE_PERIPH_UART_NONBLOCKING)) {
dev(uart)->INTENSET = UARTE_INTENSET_ENDTX_Msk;
uart_config[uart].dev->INTENSET = UARTE_INTENSET_ENDTX_Msk;
}
/* set data to transfer to DMA TX pointer */
dev(uart)->TXD.PTR = (uint32_t)data;
dev(uart)->TXD.MAXCNT = len;
uart_config[uart].dev->TXD.PTR = (uint32_t)data;
uart_config[uart].dev->TXD.MAXCNT = len;
/* start transmission */
dev(uart)->TASKS_STARTTX = 1;
uart_config[uart].dev->TASKS_STARTTX = 1;
/* wait for the end of transmission */
if (!IS_USED(MODULE_PERIPH_UART_NONBLOCKING)) {
while (dev(uart)->EVENTS_ENDTX == 0) {}
dev(uart)->TASKS_STOPTX = 1;
while (uart_config[uart].dev->EVENTS_ENDTX == 0) {}
uart_config[uart].dev->TASKS_STOPTX = 1;
}
}
void uart_write(uart_t uart, const uint8_t *data, size_t len)
{
assert(uart < UART_NUMOF);
assume((unsigned)uart < UART_NUMOF);
#ifdef MODULE_PERIPH_UART_NONBLOCKING
for (size_t i = 0; i < len; i++) {
/* in IRQ or interrupts disabled */
if (irq_is_in() || __get_PRIMASK()) {
if (tsrb_full(&uart_tx_rb[uart])) {
/* wait for end of ongoing transmission */
if (dev(uart)->EVENTS_TXSTARTED) {
while (dev(uart)->EVENTS_ENDTX == 0) {}
dev(uart)->EVENTS_TXSTARTED = 0;
if (uart_config[uart].dev->EVENTS_TXSTARTED) {
while (uart_config[uart].dev->EVENTS_ENDTX == 0) {}
uart_config[uart].dev->EVENTS_TXSTARTED = 0;
}
/* free one spot in buffer */
tx_buf[uart] = tsrb_get_one(&uart_tx_rb[uart]);
@ -295,7 +278,7 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len)
else {
/* if no transmission is ongoing and ring buffer is full
free up a spot in the buffer by sending one byte */
if (!dev(uart)->EVENTS_TXSTARTED && tsrb_full(&uart_tx_rb[uart])) {
if (!uart_config[uart].dev->EVENTS_TXSTARTED && tsrb_full(&uart_tx_rb[uart])) {
tx_buf[uart] = tsrb_get_one(&uart_tx_rb[uart]);
_write_buf(uart, &tx_buf[uart], 1);
}
@ -304,7 +287,7 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len)
}
/* if no transmission is ongoing bootstrap the transmission process
by setting a single byte to be written */
if (!dev(uart)->EVENTS_TXSTARTED) {
if (!uart_config[uart].dev->EVENTS_TXSTARTED) {
if (!tsrb_empty(&uart_tx_rb[uart])) {
tx_buf[uart] = tsrb_get_one(&uart_tx_rb[uart]);
_write_buf(uart, &tx_buf[uart], 1);
@ -334,25 +317,33 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len)
void uart_poweron(uart_t uart)
{
assert(uart < UART_NUMOF);
assume((unsigned)uart < UART_NUMOF);
if (isr_ctx[uart].rx_cb) {
dev(uart)->TASKS_STARTRX = 1;
uart_config[uart].dev->TASKS_STARTRX = 1;
}
}
void uart_poweroff(uart_t uart)
{
assert(uart < UART_NUMOF);
assume((unsigned)uart < UART_NUMOF);
dev(uart)->TASKS_STOPRX = 1;
uart_config[uart].dev->TASKS_STOPRX = 1;
}
int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity,
uart_stop_bits_t stop_bits)
{
if (stop_bits != UART_STOP_BITS_1 && stop_bits != UART_STOP_BITS_2) {
assume((unsigned)uart < UART_NUMOF);
/* Not all nRF52 MCUs support 2 stop bits, but the vendor header files
* reflect the feature set. */
switch (stop_bits) {
case UART_STOP_BITS_1:
#ifdef UARTE_CONFIG_STOP_Msk
case UART_STOP_BITS_2:
#endif
break;
default:
return UART_NOMODE;
}
@ -364,43 +355,43 @@ int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity,
return UART_NOMODE;
}
/* Do not modify hardware flow control */
uint32_t conf = uart_config[uart].dev->CONFIG & UARTE_CONFIG_HWFC_Msk;
#ifdef UARTE_CONFIG_STOP_Msk
if (stop_bits == UART_STOP_BITS_2) {
dev(uart)->CONFIG |= UARTE_CONFIG_STOP_Msk;
}
else {
dev(uart)->CONFIG &= ~UARTE_CONFIG_STOP_Msk;
conf |= UARTE_CONFIG_STOP_Msk;
}
#endif
if (parity == UART_PARITY_EVEN) {
dev(uart)->CONFIG |= UARTE_CONFIG_PARITY_Msk;
}
else {
dev(uart)->CONFIG &= ~UARTE_CONFIG_PARITY_Msk;
conf |= UARTE_CONFIG_PARITY_Msk;
}
uart_config[uart].dev->CONFIG = conf;
return UART_OK;
}
static inline void irq_handler(uart_t uart)
static void irq_handler(uart_t uart)
{
if (dev(uart)->EVENTS_ENDRX) {
dev(uart)->EVENTS_ENDRX = 0;
if (uart_config[uart].dev->EVENTS_ENDRX) {
uart_config[uart].dev->EVENTS_ENDRX = 0;
/* make sure we actually received new data */
if (dev(uart)->RXD.AMOUNT != 0) {
if (uart_config[uart].dev->RXD.AMOUNT != 0) {
/* Process received byte */
isr_ctx[uart].rx_cb(isr_ctx[uart].arg, rx_buf[uart]);
}
}
#ifdef MODULE_PERIPH_UART_NONBLOCKING
if (dev(uart)->EVENTS_ENDTX) {
if (uart_config[uart].dev->EVENTS_ENDTX) {
/* reset flags and idsable ISR on EVENTS_ENDTX */
dev(uart)->EVENTS_ENDTX = 0;
dev(uart)->EVENTS_TXSTARTED = 0;
dev(uart)->INTENCLR = UARTE_INTENSET_ENDTX_Msk;
uart_config[uart].dev->EVENTS_ENDTX = 0;
uart_config[uart].dev->EVENTS_TXSTARTED = 0;
uart_config[uart].dev->INTENCLR = UARTE_INTENSET_ENDTX_Msk;
if (tsrb_empty(&uart_tx_rb[uart])) {
dev(uart)->TASKS_STOPTX = 1;
uart_config[uart].dev->TASKS_STOPTX = 1;
} else {
tx_buf[uart] = tsrb_get_one(&uart_tx_rb[uart]);
_write_buf(uart, &tx_buf[uart], 1);
@ -411,13 +402,13 @@ static inline void irq_handler(uart_t uart)
cortexm_isr_end();
}
#else /* nrf51 and nrf52832 etc */
#else /* UART without EasyDMA*/
void uart_write(uart_t uart, const uint8_t *data, size_t len)
{
(void)uart;
assume((unsigned)uart < UART_NUMOF);
NRF_UART0->TASKS_STARTTX = 1;
uart_config[uart].dev->TASKS_STARTTX = 1;
for (size_t i = 0; i < len; i++) {
/* This section of the function is not thread safe:
@ -430,36 +421,36 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len)
while loop.
*/
/* reset ready flag */
NRF_UART0->EVENTS_TXDRDY = 0;
uart_config[uart].dev->EVENTS_TXDRDY = 0;
/* write data into transmit register */
NRF_UART0->TXD = data[i];
uart_config[uart].dev->TXD = data[i];
/* wait for any transmission to be done */
while (NRF_UART0->EVENTS_TXDRDY == 0) {}
while (uart_config[uart].dev->EVENTS_TXDRDY == 0) {}
}
NRF_UART0->TASKS_STOPTX = 1;
uart_config[uart].dev->TASKS_STOPTX = 1;
}
void uart_poweron(uart_t uart)
{
(void)uart;
assume((unsigned)uart < UART_NUMOF);
if (isr_ctx.rx_cb) {
NRF_UART0->TASKS_STARTRX = 1;
if (isr_ctx[uart].rx_cb) {
uart_config[uart].dev->TASKS_STARTRX = 1;
}
}
void uart_poweroff(uart_t uart)
{
(void)uart;
assume((unsigned)uart < UART_NUMOF);
NRF_UART0->TASKS_STOPRX = 1;
uart_config[uart].dev->TASKS_STOPRX = 1;
}
int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity,
uart_stop_bits_t stop_bits)
{
(void)uart;
assume((unsigned)uart < UART_NUMOF);
if (stop_bits != UART_STOP_BITS_1) {
return UART_NOMODE;
@ -474,29 +465,27 @@ int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity,
}
if (parity == UART_PARITY_EVEN) {
NRF_UART0->CONFIG |= UART_CONFIG_PARITY_Msk;
uart_config[uart].dev->CONFIG |= UART_CONFIG_PARITY_Msk;
}
else {
NRF_UART0->CONFIG &= ~UART_CONFIG_PARITY_Msk;
uart_config[uart].dev->CONFIG &= ~UART_CONFIG_PARITY_Msk;
}
return UART_OK;
}
static inline void irq_handler(uart_t uart)
static void irq_handler(uart_t uart)
{
(void)uart;
if (NRF_UART0->EVENTS_RXDRDY == 1) {
NRF_UART0->EVENTS_RXDRDY = 0;
uint8_t byte = (uint8_t)(NRF_UART0->RXD & 0xff);
isr_ctx.rx_cb(isr_ctx.arg, byte);
if (uart_config[uart].dev->EVENTS_RXDRDY == 1) {
uart_config[uart].dev->EVENTS_RXDRDY = 0;
uint8_t byte = (uint8_t)(uart_config[uart].dev->RXD & 0xff);
isr_ctx[uart].rx_cb(isr_ctx[uart].arg, byte);
}
cortexm_isr_end();
}
#endif /* !CPU_MODEL_NRF52832XXAA && !CPU_FAM_NRF51 */
#endif
#if defined(CPU_NRF53) || defined(CPU_NRF9160)
void uart_isr_handler(void *arg)
@ -519,4 +508,5 @@ void UART_1_ISR(void)
irq_handler(UART_DEV(1));
}
#endif
#endif /* def CPU_NRF53 || CPU_NRF9160 */

View File

@ -8,6 +8,7 @@
config CPU_COMMON_SAM0
bool
select HAS_PERIPH_CPUID
select HAS_PERIPH_ADC_CONTINUOUS
select HAS_PERIPH_FLASHPAGE
select HAS_PERIPH_FLASHPAGE_IN_ADDRESS_SPACE
select HAS_PERIPH_FLASHPAGE_PAGEWISE

View File

@ -7,6 +7,7 @@ ifeq (,$(filter $(CPU_MODELS_WITHOUT_DMA),$(CPU_MODEL)))
FEATURES_PROVIDED += periph_dma
endif
FEATURES_PROVIDED += periph_adc_continuous
FEATURES_PROVIDED += periph_flashpage
FEATURES_PROVIDED += periph_flashpage_in_address_space
FEATURES_PROVIDED += periph_flashpage_pagewise

View File

@ -945,6 +945,14 @@ typedef struct {
*/
#define WDT_HAS_INIT (1)
/**
* @brief Frequency meter configuration
*/
typedef struct {
gpio_t pin; /**< GPIO at which the frequency is to be measured */
uint8_t gclk_src; /**< GCLK source select for reference */
} freqm_config_t;
#if defined(REV_DMAC) || DOXYGEN
/**
* @name sam0 DMA peripheral

View File

@ -49,16 +49,6 @@ static int _adc_configure(Adc *dev, adc_res_t res);
static mutex_t _lock = MUTEX_INIT;
static inline void _prep(void)
{
mutex_lock(&_lock);
}
static inline void _done(void)
{
mutex_unlock(&_lock);
}
static inline void _wait_syncbusy(Adc *dev)
{
#ifdef ADC_STATUS_SYNCBUSY
@ -263,7 +253,7 @@ int adc_init(adc_t line)
const uint8_t adc = 0;
#endif
_prep();
mutex_lock(&_lock);
uint8_t muxpos = (adc_channels[line].inputctrl & ADC_INPUTCTRL_MUXPOS_Msk)
>> ADC_INPUTCTRL_MUXPOS_Pos;
@ -284,34 +274,44 @@ int adc_init(adc_t line)
gpio_init_mux(sam0_adc_pins[adc][muxneg], GPIO_MUX_B);
}
_done();
mutex_unlock(&_lock);
return 0;
}
int32_t adc_sample(adc_t line, adc_res_t res)
static Adc *_dev(adc_t line)
{
if (line >= ADC_NUMOF) {
DEBUG("adc: line arg not applicable\n");
return -1;
}
/* The SAMD5x/SAME5x family has two ADCs: ADC0 and ADC1. */
#ifdef ADC0
Adc *dev = adc_channels[line].dev;
return adc_channels[line].dev;
#else
Adc *dev = ADC;
(void)line;
return ADC;
#endif
}
bool diffmode = adc_channels[line].inputctrl & ADC_INPUTCTRL_DIFFMODE;
_prep();
if (_adc_configure(dev, res) != 0) {
_done();
DEBUG("adc: configuration failed\n");
return -1;
static Adc *_adc(uint8_t dev)
{
/* The SAMD5x/SAME5x family has two ADCs: ADC0 and ADC1. */
#ifdef ADC0
switch (dev) {
case 0:
return ADC0;
case 1:
return ADC1;
default:
return NULL;
}
#else
(void)dev;
return ADC;
#endif
}
static int32_t _sample(adc_t line)
{
Adc *dev = _dev(line);
bool diffmode = adc_channels[line].inputctrl & ADC_INPUTCTRL_DIFFMODE;
dev->INPUTCTRL.reg = ADC_GAIN_FACTOR_DEFAULT
| adc_channels[line].inputctrl
@ -319,7 +319,6 @@ int32_t adc_sample(adc_t line, adc_res_t res)
#ifdef ADC_CTRLB_DIFFMODE
dev->CTRLB.bit.DIFFMODE = diffmode;
#endif
_wait_syncbusy(dev);
/* Start the conversion */
@ -331,9 +330,6 @@ int32_t adc_sample(adc_t line, adc_res_t res)
uint16_t sample = dev->RESULT.reg;
int result;
_adc_poweroff(dev);
_done();
/* in differential mode we lose one bit for the sign */
if (diffmode) {
result = 2 * (int16_t)sample;
@ -341,11 +337,104 @@ int32_t adc_sample(adc_t line, adc_res_t res)
result = sample;
}
return result;
}
static uint8_t _shift_from_res(adc_res_t res)
{
/* 16 bit mode is implemented as oversampling */
if ((res & 0x3) == 1) {
/* ADC does automatic right shifts beyond 16 samples */
result <<= (4 - MIN(4, res >> 2));
return 4 - MIN(4, res >> 2);
}
return 0;
}
static void _get_adcs(bool *adc0, bool *adc1)
{
#ifndef ADC1
*adc0 = true;
*adc1 = false;
return;
#else
*adc0 = false;
*adc1 = false;
for (unsigned i = 0; i < ADC_NUMOF; ++i) {
if (adc_channels[i].dev == ADC0) {
*adc0 = true;
} else if (adc_channels[i].dev == ADC1) {
*adc1 = true;
}
}
#endif
}
static uint8_t _shift;
void adc_continuous_begin(adc_res_t res)
{
bool adc0, adc1;
_get_adcs(&adc0, &adc1);
mutex_lock(&_lock);
if (adc0) {
_adc_configure(_adc(0), res);
}
if (adc1) {
_adc_configure(_adc(1), res);
}
return result;
_shift = _shift_from_res(res);
}
int32_t adc_continuous_sample(adc_t line)
{
int val;
assert(line < ADC_NUMOF);
mutex_lock(&_lock);
val = _sample(line) << _shift;
mutex_unlock(&_lock);
return val;
}
void adc_continuous_stop(void)
{
bool adc0, adc1;
_get_adcs(&adc0, &adc1);
if (adc0) {
_adc_poweroff(_adc(0));
}
if (adc1) {
_adc_poweroff(_adc(1));
}
mutex_unlock(&_lock);
}
int32_t adc_sample(adc_t line, adc_res_t res)
{
if (line >= ADC_NUMOF) {
DEBUG("adc: line arg not applicable\n");
return -1;
}
mutex_lock(&_lock);
Adc *dev = _dev(line);
if (_adc_configure(dev, res) != 0) {
DEBUG("adc: configuration failed\n");
mutex_unlock(&_lock);
return -1;
}
int val = _sample(line) << _shift_from_res(res);
_adc_poweroff(dev);
mutex_unlock(&_lock);
return val;
}

View File

@ -0,0 +1,259 @@
/*
* Copyright (C) 2023 ML!PA Consulting GmbH
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_sam0_common
* @ingroup drivers_periph_freqm
* @{
*
* @file freqm.c
* @brief Frequency meter driver implementation
*
* @author Urs Gompper <urs.gompper@ml-pa.com>
*
* @}
*/
#include "periph/freqm.h"
/* TODO: Remove defines when Microchip vendor files (which include these
* defines) get updated.
*/
/* FREQM_GCLK_ID_REF is defined in newer versions of vendor header files */
#ifndef FREQM_GCLK_ID_REF
#define FREQM_GCLK_ID_REF (FREQM_GCLK_ID_MSR + 1)
#endif
/* Channel Enable Mask */
#define GCLK_PCHCTRL_CHEN_Msk (_U_(0x1) << GCLK_PCHCTRL_CHEN_Pos)
/* Enable Mask */
#define FREQM_CTRLA_ENABLE_Msk (_U_(0x1) << FREQM_CTRLA_ENABLE_Pos)
/* Start Measurement Mask */
#define FREQM_CTRLB_START_Msk (_U_(0x1) << FREQM_CTRLB_START_Pos)
/* Measurement Done Interrupt Enable Mask */
#define FREQM_INTENSET_DONE_Msk (_U_(0x1) << FREQM_INTENSET_DONE_Pos)
/* Measurement Done Mask */
#define FREQM_INTFLAG_DONE_Msk (_U_(0x1) << FREQM_INTFLAG_DONE_Pos)
/* FREQM Status Mask */
#define FREQM_STATUS_BUSY_Msk (_U_(0x1) << FREQM_STATUS_BUSY_Pos)
/* Sticky Count Value Overflow Mask */
#define FREQM_STATUS_OVF_Msk (_U_(0x1) << FREQM_STATUS_OVF_Pos)
/* check if pin has peripheral function GCLK */
static int _freqm_pin(gpio_t pin)
{
for (unsigned i = 0; i < ARRAY_SIZE(gclk_io_pins); ++i) {
if (gclk_io_pins[i] == pin) {
return i;
}
}
return -1;
}
static void _gclk_connect(uint8_t id, uint8_t src, uint32_t flags)
{
GCLK->GENCTRL[id].reg = GCLK_GENCTRL_SRC(src) | GCLK_GENCTRL_GENEN | flags | GCLK_GENCTRL_IDC;
while (GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL(id)) {}
}
static int _freqm_gpio_init(gpio_t msr_gpio_src, uint8_t *gclk_io_id)
{
/* Check if selected pin has peripheral function GCLK */
int index = _freqm_pin(msr_gpio_src);
/* Fail assertion if pin has no peripheral function GCLK */
assert(index > 0);
/* Lookup which GCLK_IO[x] must be used */
*gclk_io_id = gclk_io_ids[index];
/* GCLK_IO[0] and GCLK_IO[1] can't be used here. They are associated with
GCLKGEN[0] and GCLKGEN[1] respectively. These in turn are used by
SAM0_GCLK_MAIN and SAM0_GCLK_32KHZ respectively */
assert(*gclk_io_id > 1);
/* Initialize GPIO as input */
gpio_init(msr_gpio_src, GPIO_IN);
/* Enable peripheral function GCLK/IO on GPIO */
gpio_init_mux(msr_gpio_src, GPIO_MUX_M);
/* Connect GCLK_IO[*gclk_io_id] with input pin */
_gclk_connect(*gclk_io_id, GCLK_SOURCE_GCLKIN, 0);
return 0;
}
static void _freqm_clock_init(uint8_t pin, uint8_t gclk_src)
{
/* Selection of the Generator and write Lock for FREQM_MSR */
GCLK->PCHCTRL[FREQM_GCLK_ID_MSR].reg = GCLK_PCHCTRL_GEN(pin) | GCLK_PCHCTRL_CHEN_Msk;
/* Wait for synchronization */
while ((GCLK->PCHCTRL[FREQM_GCLK_ID_MSR].reg & GCLK_PCHCTRL_CHEN_Msk) !=
GCLK_PCHCTRL_CHEN_Msk) {}
/* Selection of the Generator and write Lock for FREQM_REF */
GCLK->PCHCTRL[FREQM_GCLK_ID_REF].reg = GCLK_PCHCTRL_GEN(gclk_src) | GCLK_PCHCTRL_CHEN_Msk;
/* Wait for synchronization */
while ((GCLK->PCHCTRL[FREQM_GCLK_ID_REF].reg & GCLK_PCHCTRL_CHEN_Msk) !=
GCLK_PCHCTRL_CHEN_Msk) {}
}
static struct {
freqm_cb_t callback;
void *context;
freqm_t idx;
uint8_t period_cnt;
} freqm_obj;
struct _sync_ctx {
mutex_t lock; /**< Mutex for blocking till measurement is done */
uint32_t hz; /**< Measured frequency in Hz */
bool overflow; /**< Overflow in FREQM counter */
};
/**
* @brief Mutex for locking the FREQM device
*/
static mutex_t msr_lock = MUTEX_INIT;
static void _freqm_enable(uint8_t refnum)
{
mutex_lock(&msr_lock);
/* Save refnum for frequency calculation */
freqm_obj.period_cnt = refnum;
FREQM->CFGA.reg = (uint16_t)(FREQM_CFGA_REFNUM(refnum));
/* Enable DONE Interrupt */
FREQM->INTENSET.reg = FREQM_INTENSET_DONE_Msk;
/* Enable FREQM */
FREQM->CTRLA.reg = FREQM_CTRLA_ENABLE_Msk;
/* Wait for Sync */
while ((FREQM->SYNCBUSY.reg) != 0U) {}
}
static void _freqm_disable(void)
{
/* Disable DONE Interrupt */
FREQM->INTENCLR.reg = FREQM_INTENCLR_MASK;
/* Disable FREQM */
FREQM->CTRLA.reg &= ~FREQM_CTRLA_ENABLE_Msk;
/* Wait for Sync */
while ((FREQM->SYNCBUSY.reg) != 0U) {}
mutex_unlock(&msr_lock);
}
bool _freqm_get_measurement(uint32_t *result)
{
const freqm_config_t *config = &freqm_config[freqm_obj.idx];
/* Calculate measured frequency */
uint64_t result_tmp = FREQM->VALUE.reg * (uint64_t)(sam0_gclk_freq(config->gclk_src));
result_tmp = result_tmp / freqm_obj.period_cnt;
*result = (uint32_t)result_tmp;
/* Read overflow status */
bool overflow_condition = ((int)FREQM->STATUS.reg & FREQM_STATUS_OVF_Msk);
/* Clear overflow status */
FREQM->STATUS.reg = FREQM_STATUS_OVF_Msk;
return overflow_condition;
}
uint32_t _us_to_ref_clock_counts(uint32_t period_us, uint8_t clock_id)
{
uint64_t clk_cnt = (uint64_t)period_us * sam0_gclk_freq(clock_id) / US_PER_SEC;
if (clk_cnt > UINT8_MAX) {
return UINT8_MAX;
}
else if (clk_cnt == 0) {
return 1;
}
else {
return clk_cnt;
}
}
static void _sync_cb(uint32_t res, bool overflow, void *_ctx)
{
struct _sync_ctx *ctx = _ctx;
ctx->hz = res;
ctx->overflow = overflow;
mutex_unlock(&ctx->lock);
}
int freqm_frequency_get(freqm_t idx, uint32_t *result, uint32_t period_us)
{
struct _sync_ctx ctx = { .lock = MUTEX_INIT_LOCKED };
/* Invoke non-blocking FREQM measure function */
freqm_frequency_get_async(idx, _sync_cb, &ctx, period_us);
/* Block until measurement is done */
mutex_lock(&ctx.lock);
*result = ctx.hz;
return ctx.overflow ? -EOVERFLOW : 0;
}
void freqm_frequency_get_async(freqm_t idx, freqm_cb_t freqm_cb, void *context, uint32_t period_us)
{
const freqm_config_t *config = &freqm_config[idx];
uint8_t refnum = _us_to_ref_clock_counts(period_us, config->gclk_src);
_freqm_enable(refnum);
/* Register callback function */
freqm_obj.callback = freqm_cb;
freqm_obj.context = context;
freqm_obj.idx = idx;
/* Clear the Done Interrupt flag */
FREQM->INTFLAG.reg = FREQM_INTFLAG_DONE_Msk;
/* Start measurement */
FREQM->CTRLB.reg = FREQM_CTRLB_START_Msk;
}
void irq_freqm(void)
{
/* Clear the Done Interrupt flag */
FREQM->INTFLAG.reg = FREQM_INTFLAG_DONE_Msk;
uint32_t result = 0;
bool overflow_condition = _freqm_get_measurement(&result);
/* Invoke the callback function */
freqm_obj.callback(result, overflow_condition, freqm_obj.context);
_freqm_disable();
}
void freqm_init(freqm_t idx)
{
uint8_t gclk_io_id = 0;
const freqm_config_t *config = &freqm_config[idx];
/* Sanity check configuration */
assert(config->gclk_src <= GCLK_GEN_NUM_MSB);
_freqm_gpio_init(config->pin, &gclk_io_id);
_freqm_clock_init(gclk_io_id, config->gclk_src);
/* Enable interrupt */
NVIC_EnableIRQ(FREQM_IRQn);
}

View File

@ -325,6 +325,9 @@ void cpu_init(void)
#ifdef MODULE_PERIPH_PM
| MCLK_APBAMASK_PM
#endif
#ifdef MODULE_PERIPH_FREQM
| MCLK_APBAMASK_FREQM
#endif
#ifdef MODULE_PERIPH_GPIO_IRQ
| MCLK_APBAMASK_EIC
#endif

View File

@ -70,13 +70,19 @@ enum {
* @name SAMD5x GCLK definitions
* @{
*/
enum {
SAM0_GCLK_MAIN = 0, /**< 120 MHz main clock */
SAM0_GCLK_32KHZ, /**< 32 kHz clock */
SAM0_GCLK_TIMER, /**< 4-8 MHz clock for xTimer */
SAM0_GCLK_PERIPH, /**< 12-48 MHz (DFLL) clock */
SAM0_GCLK_100MHZ, /**< 100MHz FDPLL clock */
};
#define SAM0_GCLK_MAIN 0 /**< 120 MHz main clock */
#ifndef SAM0_GCLK_32KHZ
#define SAM0_GCLK_32KHZ 1 /**< 32 kHz clock */
#endif
#ifndef SAM0_GCLK_TIMER
#define SAM0_GCLK_TIMER 2 /**< 4-8 MHz clock for xTimer */
#endif
#ifndef SAM0_GCLK_PERIPH
#define SAM0_GCLK_PERIPH 3 /**< 12-48 MHz (DFLL) clock */
#endif
#ifndef SAM0_GCLK_100MHZ
#define SAM0_GCLK_100MHZ 4 /**< 100MHz FDPLL clock */
#endif
/** @} */
/**
@ -198,6 +204,28 @@ static const gpio_t rtc_tamper_pins[RTC_NUM_OF_TAMPERS] = {
GPIO_PIN(PC, 0), GPIO_PIN(PC, 1)
};
/**
* @brief Pins that have peripheral function GCLK
*/
static const gpio_t gclk_io_pins[] = {
GPIO_PIN(PA, 10), GPIO_PIN(PA, 11), GPIO_PIN(PA, 14),
GPIO_PIN(PA, 15), GPIO_PIN(PA, 16), GPIO_PIN(PA, 17),
GPIO_PIN(PA, 27), GPIO_PIN(PA, 30), GPIO_PIN(PB, 10),
GPIO_PIN(PB, 11), GPIO_PIN(PB, 12), GPIO_PIN(PB, 13),
GPIO_PIN(PB, 14), GPIO_PIN(PB, 15), GPIO_PIN(PB, 16),
GPIO_PIN(PB, 17), GPIO_PIN(PB, 18), GPIO_PIN(PB, 19),
GPIO_PIN(PB, 20), GPIO_PIN(PB, 21), GPIO_PIN(PB, 22),
GPIO_PIN(PB, 23)
};
/**
* @brief GCLK IDs of pins that have peripheral function GCLK - This maps
* directly to gclk_io_pins.
*/
static const uint8_t gclk_io_ids[] = {
4, 5, 0, 1, 2, 3, 1, 0, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1
};
/**
* @brief NVM User Page Mapping - Dedicated Entries
* Config values will be applied at power-on.

View File

@ -333,6 +333,26 @@ void _wlx5xx_init_subghz_debug_pins(void)
#endif
}
static void swj_init(void)
{
#if defined(CPU_FAM_STM32F1)
/* Only if the selected SWJ config differs from the reset value, we
* actually need to do something. Since both sides are compile time
* constants, this hole code gets optimized out by default */
if (CONFIG_AFIO_MAPR_SWJ_CFG != SWJ_CFG_FULL_SWJ) {
/* The remapping periph clock must first be enabled */
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
/* Handling of the MAPR register is a bit involved due to the
* write-only nature of the SWJ_CFG field, which returns undefined
* garbage on read. `afio_mapr_read()` will read the current MAPR
* value, but clear the SWF_CFG vield. `afio_mapr_wriote()` will then
* write the value read back, but apply the `SWF_CFG` configuration
* from `CONFIG_AFIO_MAPR_SWJ_CFG` first.*/
afio_mapr_write(afio_mapr_read());
}
#endif
}
void cpu_init(void)
{
/* initialize the Cortex-M core */
@ -362,10 +382,7 @@ void cpu_init(void)
/* initialize stdio prior to periph_init() to allow use of DEBUG() there */
early_init();
#ifdef STM32F1_DISABLE_JTAG
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_JTAGDISABLE;
#endif
swj_init();
/* trigger static peripheral initialization */
periph_init();

View File

@ -107,6 +107,67 @@ enum {
};
/** @} */
/**
* @brief Possible values of the `SWJ_CFG` field in the AFIO->MAPR register
*
* @details This wraps the vendor header file preprocessor macros into a
* C language `enum`.
*/
typedef enum {
/**
* @brief Both JTAG-DP and SW-DP enabled, reset state
*/
SWJ_CFG_FULL_SWJ = 0,
/**
* @brief Both JTAG-DP and SW-DP enabled, but NJTRST disabled and pin
* usable as GPIO
*/
SWJ_CFG_NO_NJTRST = AFIO_MAPR_SWJ_CFG_NOJNTRST,
/**
* @brief Only SW-DP enabled, JTAG pins usable as GPIOS
*/
SWJ_CFG_NO_JTAG_DP = AFIO_MAPR_SWJ_CFG_JTAGDISABLE,
/**
* @brief Neither JTAG-DP nor SW-DP enabled, JTAG and SWD pins usable as
* GPIOS
*/
SWJ_CFG_DISABLED = AFIO_MAPR_SWJ_CFG_DISABLE,
} afio_mapr_swj_cfg_t;
#ifndef CONFIG_AFIO_MAPR_SWJ_CFG
/**
* @brief By default, disable JTAG and keep only SWD
*
* This frees the JTAG pins for use as regular GPIOs. We do not support flashing
* or debugging via JTAG anyway, so there is nothing lost except for a few bytes
* of ROM to initialize the `SWJ_CFG` register.
*/
#define CONFIG_AFIO_MAPR_SWJ_CFG SWJ_CFG_NO_JTAG_DP
#endif
/**
* @brief Read the current value of the AFIO->MAPR register reproducibly
*
* This will explicitly clear the write-only `SWJ_CFG` field [26:24], as the
* values read back are undefined.
*/
static inline uint32_t afio_mapr_read(void)
{
return AFIO->MAPR & (~(AFIO_MAPR_SWJ_CFG_Msk));
}
/**
* @brief Write to the AFIO->MAPR register apply the SWJ configuration
* specified via @ref CONFIG_AFIO_MAPR_SWJ_CFG
*
* @pre @p new_value has all bits in the range [26:24] cleared (the
* `SWJ_CFG` field).
*/
static inline void afio_mapr_write(uint32_t new_value)
{
AFIO->MAPR = CONFIG_AFIO_MAPR_SWJ_CFG | new_value;
}
#ifdef __cplusplus
}
#endif

View File

@ -170,6 +170,36 @@ typedef struct {
#define USBDEV_NUM_ENDPOINTS 8
#endif
/* unify names across STM32 families */
#ifdef SPI_CR1_CPHA_Msk
# define STM32_SPI_CPHA_Msk SPI_CR1_CPHA_Msk
#endif
#ifdef SPI_CFG2_CPHA_Msk
# define STM32_SPI_CPHA_Msk SPI_CFG2_CPHA_Msk
#endif
#ifdef SPI_CR1_CPOL_Msk
# define STM32_SPI_CPOL_Msk SPI_CR1_CPOL_Msk
#endif
#ifdef SPI_CFG2_CPOL_Msk
# define STM32_SPI_CPOL_Msk SPI_CFG2_CPOL_Msk
#endif
/**
* @name Override the SPI mode values
*
* As the mode is set in bit 3 and 2 of the configuration register, we put the
* correct configuration there
* @{
*/
#define HAVE_SPI_MODE_T
typedef enum {
SPI_MODE_0 = 0, /**< CPOL=0, CPHA=0 */
SPI_MODE_1 = STM32_SPI_CPHA_Msk, /**< CPOL=0, CPHA=1 */
SPI_MODE_2 = STM32_SPI_CPOL_Msk, /**< CPOL=1, CPHA=0 */
SPI_MODE_3 = STM32_SPI_CPOL_Msk | STM32_SPI_CPHA_Msk, /**< CPOL=1, CPHA=0 */
} spi_mode_t;
/** @} */
#endif /* !DOXYGEN */
#ifdef __cplusplus

View File

@ -120,7 +120,7 @@ static void _init_pins(i2c_t dev)
/* The remapping periph clock must first be enabled */
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
/* Then the remap can occur */
AFIO->MAPR |= AFIO_MAPR_I2C1_REMAP;
afio_mapr_write(afio_mapr_read() | AFIO_MAPR_I2C1_REMAP);
}
gpio_init_af(i2c_config[dev].scl_pin, GPIO_AF_OUT_OD);
gpio_init_af(i2c_config[dev].sda_pin, GPIO_AF_OUT_OD);

View File

@ -28,8 +28,6 @@
#include <assert.h>
#include "bitarithm.h"
#include "cpu.h"
#include "mutex.h"
#include "periph/gpio.h"
#include "periph/spi.h"
@ -65,9 +63,9 @@ static mutex_t locks[SPI_NUMOF];
static uint32_t clocks[SPI_NUMOF];
/**
* @brief Clock divider cache
* @brief Clock prescaler cache
*/
static uint8_t dividers[SPI_NUMOF];
static uint8_t prescalers[SPI_NUMOF];
static inline SPI_TypeDef *dev(spi_t bus)
{
@ -81,33 +79,24 @@ static inline bool _use_dma(const spi_conf_t *conf)
}
#endif
/**
* @brief Multiplier for clock divider calculations
*
* Makes the divider calculation fixed point
*/
#define SPI_APB_CLOCK_SHIFT (4U)
#define SPI_APB_CLOCK_MULT (1U << SPI_APB_CLOCK_SHIFT)
static uint8_t _get_clkdiv(const spi_conf_t *conf, uint32_t clock)
static uint8_t _get_prescaler(const spi_conf_t *conf, uint32_t clock)
{
uint32_t bus_clock = periph_apb_clk(conf->apbbus);
/* Shift bus_clock with SPI_APB_CLOCK_SHIFT to create a fixed point int */
uint32_t div = (bus_clock << SPI_APB_CLOCK_SHIFT) / (2 * clock);
DEBUG("[spi] clock: divider: %"PRIu32"\n", div);
/* Test if the divider is 2 or smaller, keeping the fixed point in mind */
if (div <= SPI_APB_CLOCK_MULT) {
return 0;
uint8_t prescaler = 0;
uint32_t prescaled_clock = bus_clock >> 1;
const uint8_t prescaler_max = SPI_CR1_BR_Msk >> SPI_CR1_BR_Pos;
for (; (prescaled_clock > clock) && (prescaler < prescaler_max); prescaler++) {
prescaled_clock >>= 1;
}
/* determine MSB and compensate back for the fixed point int shift */
uint8_t rounded_div = bitarithm_msb(div) - SPI_APB_CLOCK_SHIFT;
/* Determine if rounded_div is not a power of 2 */
if ((div & (div - 1)) != 0) {
/* increment by 1 to ensure that the clock speed at most the
* requested clock speed */
rounded_div++;
}
return rounded_div > BR_MAX ? BR_MAX : rounded_div;
/* If the callers asks for an SPI frequency of at most x, bad things will
* happen if this cannot be met. So let's have a blown assertion
* rather than runtime failures that require a logic analyzer to
* debug. */
assert(prescaled_clock <= clock);
return prescaler;
}
void spi_init(spi_t bus)
@ -235,30 +224,30 @@ void spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask);
/* enable device */
if (clk != clocks[bus]) {
dividers[bus] = _get_clkdiv(&spi_config[bus], clk);
prescalers[bus] = _get_prescaler(&spi_config[bus], clk);
clocks[bus] = clk;
}
uint8_t br = dividers[bus];
uint8_t br = prescalers[bus];
DEBUG("[spi] acquire: requested clock: %"PRIu32", resulting clock: %"PRIu32
" BR divider: %u\n",
DEBUG("[spi] acquire: requested clock: %" PRIu32
" Hz, resulting clock: %" PRIu32 " Hz, BR prescaler: %u\n",
clk,
periph_apb_clk(spi_config[bus].apbbus)/(1 << (br + 1)),
br);
periph_apb_clk(spi_config[bus].apbbus) >> (br + 1),
(unsigned)br);
uint16_t cr1_settings = ((br << BR_SHIFT) | mode | SPI_CR1_MSTR);
uint16_t cr1 = ((br << BR_SHIFT) | mode | SPI_CR1_MSTR | SPI_CR1_SPE);
/* Settings to add to CR2 in addition to SPI_CR2_SETTINGS */
uint16_t cr2_extra_settings = 0;
uint16_t cr2 = SPI_CR2_SETTINGS;
if (cs != SPI_HWCS_MASK) {
cr1_settings |= (SPI_CR1_SSM | SPI_CR1_SSI);
cr1 |= (SPI_CR1_SSM | SPI_CR1_SSI);
}
else {
cr2_extra_settings = (SPI_CR2_SSOE);
cr2 = (SPI_CR2_SSOE);
}
#ifdef MODULE_PERIPH_DMA
if (_use_dma(&spi_config[bus])) {
cr2_extra_settings |= SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN;
cr2 |= SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN;
dma_acquire(spi_config[bus].tx_dma);
dma_setup(spi_config[bus].tx_dma,
@ -277,11 +266,8 @@ void spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
0);
}
#endif
dev(bus)->CR1 = cr1_settings;
/* Only modify CR2 if needed */
if (cr2_extra_settings) {
dev(bus)->CR2 = (SPI_CR2_SETTINGS | cr2_extra_settings);
}
dev(bus)->CR1 = cr1;
dev(bus)->CR2 = cr2;
}
void spi_release(spi_t bus)
@ -396,10 +382,12 @@ void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
assert(out || in);
/* active the given chip select line */
dev(bus)->CR1 |= (SPI_CR1_SPE); /* this pulls the HW CS line low */
if ((cs != SPI_HWCS_MASK) && gpio_is_valid(cs)) {
gpio_clear((gpio_t)cs);
}
else {
dev(bus)->CR2 |= SPI_CR2_SSOE;
}
#ifdef MODULE_PERIPH_DMA
if (_use_dma(&spi_config[bus])) {
@ -414,9 +402,11 @@ void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
/* release the chip select if not specified differently */
if ((!cont) && gpio_is_valid(cs)) {
dev(bus)->CR1 &= ~(SPI_CR1_SPE); /* pull HW CS line high */
if (cs != SPI_HWCS_MASK) {
gpio_set((gpio_t)cs);
}
else {
dev(bus)->CR2 &= ~(SPI_CR2_SSOE);
}
}
}

View File

@ -20,6 +20,7 @@ warning: Member EPD_BW_SPI_DISPLAY_UPDATE_OPTION_[A-Z0-9_]* \(macro definition\)
warning: Member EPD_BW_SPI_WAIT_[A-Z0-9_]* \(macro definition\) of
warning: Member F_CPU \(macro definition\) of
warning: Member F_RC_OSCILLATOR \(macro definition\) of
warning: Member freqm_config\[\] \(variable\) of
warning: Member FXOS8700_PARAM_ADDR \(macro definition\) of
warning: Member FXOS8700_PARAM_I2C \(macro definition\) of
warning: Member FXOS8700_PARAM_RENEW_INTERVAL \(macro definition\) of

View File

@ -1 +1,2 @@
uf2conv.py
uf2families.json

View File

@ -5,8 +5,11 @@ PKG_LICENSE=MIT
include $(RIOTBASE)/pkg/pkg.mk
all: $(CURDIR)/uf2conv.py
all: $(CURDIR)/uf2conv.py $(CURDIR)/uf2families.json
$(CURDIR)/uf2conv.py:
cp $(PKG_SOURCE_DIR)/utils/uf2conv.py .
chmod a+x uf2conv.py
$(CURDIR)/uf2families.json:
cp $(PKG_SOURCE_DIR)/utils/uf2families.json .

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

@ -6,6 +6,39 @@
* directory for more details.
*/
/* A note on URCs (Unsolicited Result Codes), regardless of whether URC handling
* is enabled or not.
*
* Some DCEs (Data Circuit-terminating Equipment, aka modem), like the LTE
* modules from uBlox define a grace period where URCs are guaranteed NOT to be
* sent as the time span between:
* - the command EOL character reception AND command being internally accepted
* - the EOL character of the last response line
*
* As follows, there is an indeterminate amount of time between:
* - the command EOL character being sent
* - the command EOL character reception AND command being internally accepted,
* i.e. the begin of the grace period
*
* In other words, we can get a URC (or more?) just after issuing the command
* and before the first line of response. The net effect is that such URCs will
* appear to be the first line of response to the last issued command.
*
* The current solution is to skip characters that don't match the expected
* response, at the expense of losing these URCs. Note, we may already lose URCs
* when calling at_drain() just before any at_send_cmd(). Success partially
* depends on whether command echoing is enabled or not:
* 1. echo enabled: by observation, it seems that the grace period begins
* BEFORE the echoed command. This has the advantage that we ALWAYS know what
* the first line of response must look like and so if it doesn't, then it's a
* URC. Thus, any procedure that calls at_send_cmd() will catch and discard
* these URCs.
* 2. echo disabled: commands that expect a response (e.g. at_send_cmd_get_resp_wait_ok())
* will catch and discard any URC (or, if MODULE_AT_URC enabled, hand it over
* to the URC callbacks). For the rest, it is the application's responsibility
* to handle it.
*/
#include <assert.h>
#include <errno.h>
#include <string.h>
@ -32,6 +65,10 @@
#define AT_EVENT_PRIO EVENT_PRIO_HIGHEST
#endif
#if defined(MODULE_AT_URC)
static int _check_urc(clist_node_t *node, void *arg);
#endif
#if defined(MODULE_AT_URC_ISR)
static void _event_process_urc(event_t *_event)
{
@ -62,8 +99,7 @@ int at_dev_init(at_dev_t *dev, uart_t uart, uint32_t baudrate, char *buf, size_t
isrpipe_init(&dev->isrpipe, (uint8_t *)buf, bufsize);
return uart_init(uart, baudrate, _isrpipe_write_one_wrapper,
dev);
return uart_init(uart, baudrate, _isrpipe_write_one_wrapper, dev);
}
int at_expect_bytes(at_dev_t *dev, const char *bytes, uint32_t timeout)
@ -99,6 +135,15 @@ out:
return res;
}
int at_wait_bytes(at_dev_t *dev, const char *bytes, uint32_t timeout)
{
int res;
do {
res = at_expect_bytes(dev, bytes, timeout);
} while (res != 0 && res != -ETIMEDOUT);
return res;
}
void at_send_bytes(at_dev_t *dev, const char *bytes, size_t len)
{
uart_write(dev->uart, (const uint8_t *)bytes, len);
@ -175,11 +220,12 @@ int at_send_cmd(at_dev_t *dev, const char *command, uint32_t timeout)
uart_write(dev->uart, (const uint8_t *)CONFIG_AT_SEND_EOL, AT_SEND_EOL_LEN);
if (!IS_ACTIVE(CONFIG_AT_SEND_SKIP_ECHO)) {
if (at_expect_bytes(dev, command, timeout)) {
if (at_wait_bytes(dev, command, timeout)) {
return -1;
}
if (at_expect_bytes(dev, CONFIG_AT_SEND_EOL AT_RECV_EOL_1 AT_RECV_EOL_2, timeout)) {
if (at_expect_bytes(dev, CONFIG_AT_SEND_EOL AT_RECV_EOL_1 AT_RECV_EOL_2,
timeout)) {
return -2;
}
}
@ -218,11 +264,7 @@ ssize_t at_send_cmd_get_resp(at_dev_t *dev, const char *command,
goto out;
}
res = at_readline(dev, resp_buf, len, false, timeout);
if (res == 0) {
/* skip possible empty line */
res = at_readline(dev, resp_buf, len, false, timeout);
}
res = at_readline_skip_empty(dev, resp_buf, len, false, timeout);
out:
return res;
@ -242,35 +284,35 @@ ssize_t at_send_cmd_get_resp_wait_ok(at_dev_t *dev, const char *command, const c
goto out;
}
res = at_readline(dev, resp_buf, len, false, timeout);
if (res == 0) {
/* skip possible empty line */
res = at_readline(dev, resp_buf, len, false, timeout);
}
/* URCs may occur right after the command has been sent and before the
* expected response */
do {
res = at_readline_skip_empty(dev, resp_buf, len, false, timeout);
/* Strip the expected prefix */
if (res > 0 && resp_prefix && *resp_prefix) {
size_t prefix_len = strlen(resp_prefix);
if (strncmp(resp_buf, resp_prefix, prefix_len) == 0) {
size_t remaining_len = strlen(resp_buf) - prefix_len;
/* The one extra byte in the copy is the terminating nul byte */
memmove(resp_buf, resp_buf + prefix_len, remaining_len + 1);
res -= prefix_len;
/* Strip the expected prefix */
if (res > 0 && resp_prefix && *resp_prefix) {
size_t prefix_len = strlen(resp_prefix);
if (strncmp(resp_buf, resp_prefix, prefix_len) == 0) {
size_t remaining_len = strlen(resp_buf) - prefix_len;
/* The one extra byte in the copy is the terminating nul byte */
memmove(resp_buf, resp_buf + prefix_len, remaining_len + 1);
res -= prefix_len;
break;
}
}
}
} while (res >= 0);
/* wait for OK */
if (res >= 0) {
res_ok = at_readline(dev, ok_buf, sizeof(ok_buf), false, timeout);
if (res_ok == 0) {
/* skip possible empty line */
res_ok = at_readline(dev, ok_buf, sizeof(ok_buf), false, timeout);
res_ok = at_readline_skip_empty(dev, ok_buf, sizeof(ok_buf), false, timeout);
if (res_ok < 0) {
return -1;
}
ssize_t len_ok = sizeof(CONFIG_AT_RECV_OK) - 1;
if ((len_ok != 0) && (strcmp(ok_buf, CONFIG_AT_RECV_OK) == 0)) {
}
else {
/* Something else then OK */
/* Something else than OK */
res = -1;
}
}
@ -295,8 +337,6 @@ ssize_t at_send_cmd_get_lines(at_dev_t *dev, const char *command,
goto out;
}
/* only clear the response buffer after sending the command,
* so the same buffer can be used for command and response */
memset(resp_buf, '\0', len);
while (1) {
@ -358,19 +398,16 @@ int at_send_cmd_wait_prompt(at_dev_t *dev, const char *command, uint32_t timeout
uart_write(dev->uart, (const uint8_t *)command, cmdlen);
uart_write(dev->uart, (const uint8_t *)CONFIG_AT_SEND_EOL, AT_SEND_EOL_LEN);
if (at_expect_bytes(dev, command, timeout)) {
return -1;
if (!IS_ACTIVE(CONFIG_AT_SEND_SKIP_ECHO)) {
if (at_wait_bytes(dev, command, timeout)) {
return -1;
}
if (at_expect_bytes(dev, CONFIG_AT_SEND_EOL, timeout)) {
return -2;
}
}
if (at_expect_bytes(dev, CONFIG_AT_SEND_EOL AT_RECV_EOL_2, timeout)) {
return -2;
}
if (at_expect_bytes(dev, ">", timeout)) {
return -3;
}
return 0;
return at_wait_bytes(dev, ">", timeout);
}
int at_send_cmd_wait_ok(at_dev_t *dev, const char *command, uint32_t timeout)
@ -378,16 +415,31 @@ int at_send_cmd_wait_ok(at_dev_t *dev, const char *command, uint32_t timeout)
int res;
char resp_buf[64];
res = at_send_cmd_get_resp(dev, command, resp_buf, sizeof(resp_buf), timeout);
res = at_send_cmd_get_resp(dev, command, resp_buf, sizeof(resp_buf),
timeout);
if (res > 0) {
ssize_t len_ok = sizeof(CONFIG_AT_RECV_OK) - 1;
if ((len_ok != 0) && (strcmp(resp_buf, CONFIG_AT_RECV_OK) == 0)) {
res = 0;
size_t const len_ok = sizeof(CONFIG_AT_RECV_OK) - 1;
size_t const len_err = sizeof(CONFIG_AT_RECV_ERROR) - 1;
size_t const len_cme_cms = sizeof("+CME ERROR:") - 1;
while (res >= 0) {
if (strncmp(resp_buf, CONFIG_AT_RECV_OK, len_ok) == 0) {
return 0;
}
else {
res = -1;
else if (strncmp(resp_buf, CONFIG_AT_RECV_ERROR, len_err) == 0) {
return -1;
}
else if (strncmp(resp_buf, "+CME ERROR:", len_cme_cms) == 0) {
return -2;
}
else if (strncmp(resp_buf, "+CMS ERROR:", len_cme_cms) == 0) {
return -2;
}
/* probably a sneaky URC */
#ifdef MODULE_AT_URC
clist_foreach(&dev->urc_list, _check_urc, resp_buf);
#endif
res = at_readline_skip_empty(dev, resp_buf, sizeof(resp_buf), false, timeout);
}
return res;
@ -445,6 +497,17 @@ out:
return res;
}
ssize_t at_readline_skip_empty(at_dev_t *dev, char *resp_buf, size_t len,
bool keep_eol, uint32_t timeout)
{
ssize_t res = at_readline(dev, resp_buf, len, keep_eol, timeout);
if (res == 0) {
/* skip possible empty line */
res = at_readline(dev, resp_buf, len, keep_eol, timeout);
}
return res;
}
#ifdef MODULE_AT_URC
void at_add_urc(at_dev_t *dev, at_urc_t *urc)
{

View File

@ -275,6 +275,52 @@ extern "C" {
/ AT24CXXX_POLL_DELAY_US))
/** @} */
/**
* @name AT24CS04 constants
* @{
*/
/**
* @brief 512 Byte memory
*/
#define AT24CS04_EEPROM_SIZE (512U)
/**
* @brief 32 pages of 16 bytes each
*/
#define AT24CS04_PAGE_SIZE (16U)
/**
* @brief Delay to complete write operation
*/
#define AT24CS04_PAGE_WRITE_DELAY_US (5000U)
/**
* @brief Number of poll attempts
*/
#define AT24CS04_MAX_POLLS (1 + (AT24CS04_PAGE_WRITE_DELAY_US \
/ AT24CXXX_POLL_DELAY_US))
/** @} */
/**
* @name AT24CS08 constants
* @{
*/
/**
* @brief 1 kiB memory
*/
#define AT24CS08_EEPROM_SIZE (1024U)
/**
* @brief 64 pages of 16 bytes each
*/
#define AT24CS08_PAGE_SIZE (16U)
/**
* @brief Delay to complete write operation
*/
#define AT24CS08_PAGE_WRITE_DELAY_US (5000U)
/**
* @brief Number of poll attempts
*/
#define AT24CS08_MAX_POLLS (1 + (AT24CS08_PAGE_WRITE_DELAY_US \
/ AT24CXXX_POLL_DELAY_US))
/** @} */
/**
* @name AT24C1024 constants
* @{
@ -369,6 +415,14 @@ extern "C" {
#define AT24CXXX_EEPROM_SIZE (AT24C01A_EEPROM_SIZE)
#define AT24CXXX_PAGE_SIZE (AT24C01A_PAGE_SIZE)
#define AT24CXXX_MAX_POLLS (AT24C01A_MAX_POLLS)
#elif IS_USED(MODULE_AT24CS04)
#define AT24CXXX_EEPROM_SIZE (AT24CS04_EEPROM_SIZE)
#define AT24CXXX_PAGE_SIZE (AT24CS04_PAGE_SIZE)
#define AT24CXXX_MAX_POLLS (AT24CS04_MAX_POLLS)
#elif IS_USED(MODULE_AT24CS08)
#define AT24CXXX_EEPROM_SIZE (AT24CS08_EEPROM_SIZE)
#define AT24CXXX_PAGE_SIZE (AT24CS08_PAGE_SIZE)
#define AT24CXXX_MAX_POLLS (AT24CS08_MAX_POLLS)
#elif IS_USED(MODULE_AT24MAC)
#define AT24CXXX_EEPROM_SIZE (AT24MAC_EEPROM_SIZE)
#define AT24CXXX_PAGE_SIZE (AT24MAC_PAGE_SIZE)

View File

@ -195,8 +195,8 @@ typedef struct {
* @param[in] buf input buffer
* @param[in] bufsize size of @p buf
*
* @returns success code UART_OK on success
* @returns error code UART_NODEV or UART_NOBAUD otherwise
* @retval success code UART_OK on success
* @retval error code UART_NODEV or UART_NOBAUD otherwise
*/
int at_dev_init(at_dev_t *dev, uart_t uart, uint32_t baudrate, char *buf, size_t bufsize);
@ -209,8 +209,8 @@ int at_dev_init(at_dev_t *dev, uart_t uart, uint32_t baudrate, char *buf, size_t
* @param[in] command command string to send
* @param[in] timeout timeout (in usec)
*
* @returns 0 when device answers "OK"
* @returns <0 otherwise
* @retval 0 when device answers "OK"
* @retval <0 otherwise
*/
int at_send_cmd_wait_ok(at_dev_t *dev, const char *command, uint32_t timeout);
@ -224,8 +224,8 @@ int at_send_cmd_wait_ok(at_dev_t *dev, const char *command, uint32_t timeout);
* @param[in] command command string to send
* @param[in] timeout timeout (in usec)
*
* @return 0 when prompt is received
* @return <0 otherwise
* @retval 0 when prompt is received
* @retval <0 otherwise
*/
int at_send_cmd_wait_prompt(at_dev_t *dev, const char *command, uint32_t timeout);
@ -243,8 +243,8 @@ int at_send_cmd_wait_prompt(at_dev_t *dev, const char *command, uint32_t timeout
* @param[in] len len of @p buffer
* @param[in] timeout timeout (in usec)
*
* @returns length of response on success
* @returns <0 on error
* @retval n length of response on success
* @retval <0 on error
*/
ssize_t at_send_cmd_get_resp(at_dev_t *dev, const char *command, char *resp_buf, size_t len, uint32_t timeout);
@ -263,8 +263,8 @@ ssize_t at_send_cmd_get_resp(at_dev_t *dev, const char *command, char *resp_buf,
* @param[in] len len of @p buffer
* @param[in] timeout timeout (in usec)
*
* @returns length of response on success
* @returns <0 on error
* @retval n length of response on success
* @retval <0 on error
*/
ssize_t at_send_cmd_get_resp_wait_ok(at_dev_t *dev, const char *command, const char *resp_prefix,
char *resp_buf, size_t len, uint32_t timeout);
@ -286,9 +286,9 @@ ssize_t at_send_cmd_get_resp_wait_ok(at_dev_t *dev, const char *command, const c
* @param[in] keep_eol true to keep the CR character in the response
* @param[in] timeout timeout (in usec)
*
* @returns length of response on success
* @returns -1 on error
* @returns -2 on CMS or CME error
* @retval n length of response on success
* @retval -1 on error
* @retval -2 on CMS or CME error
*/
ssize_t at_send_cmd_get_lines(at_dev_t *dev, const char *command, char *resp_buf,
size_t len, bool keep_eol, uint32_t timeout);
@ -300,11 +300,23 @@ ssize_t at_send_cmd_get_lines(at_dev_t *dev, const char *command, char *resp_buf
* @param[in] bytes buffer containing bytes to expect (NULL-terminated)
* @param[in] timeout timeout (in usec)
*
* @returns 0 on success
* @returns <0 otherwise
* @retval 0 on success
* @retval <0 otherwise
*/
int at_expect_bytes(at_dev_t *dev, const char *bytes, uint32_t timeout);
/**
* @brief Repeatedly calls at_expect_bytes() until a match or timeout occurs
*
* @param[in] dev device to operate on
* @param[in] bytes buffer containing bytes to expect (NULL-terminated)
* @param[in] timeout timeout (in usec)
*
* @retval 0 on success
* @retval <0 otherwise
*/
int at_wait_bytes(at_dev_t *dev, const char *bytes, uint32_t timeout);
/**
* @brief Receives bytes into @p bytes buffer until the string pattern
* @p string is received or the buffer is full.
@ -317,8 +329,8 @@ int at_expect_bytes(at_dev_t *dev, const char *bytes, uint32_t timeout);
* bytes.
* @param[in] timeout timeout (in usec) of inactivity to finish read
*
* @returns 0 on success
* @returns <0 on error
* @retval 0 on success
* @retval <0 on error
*/
int at_recv_bytes_until_string(at_dev_t *dev, const char *string,
char *bytes, size_t *bytes_len,
@ -341,7 +353,7 @@ void at_send_bytes(at_dev_t *dev, const char *bytes, size_t len);
* @param[in] len maximum number of bytes to receive
* @param[in] timeout timeout (in usec) of inactivity to finish read
*
* @returns Number of bytes read, eventually zero if no bytes available
* @retval n Number of bytes read, eventually zero if no bytes available
*/
ssize_t at_recv_bytes(at_dev_t *dev, char *bytes, size_t len, uint32_t timeout);
@ -352,8 +364,8 @@ ssize_t at_recv_bytes(at_dev_t *dev, char *bytes, size_t len, uint32_t timeout);
* @param[in] command command to send
* @param[in] timeout timeout (in usec)
*
* @returns 0 on success
* @returns <0 otherwise
* @retval 0 on success
* @retval <0 otherwise
*/
int at_send_cmd(at_dev_t *dev, const char *command, uint32_t timeout);
@ -366,11 +378,26 @@ int at_send_cmd(at_dev_t *dev, const char *command, uint32_t timeout);
* @param[in] keep_eol true to keep the CR character in the response
* @param[in] timeout timeout (in usec)
*
* @returns line length on success
* @returns <0 on error
* @retval n line length on success
* @retval <0 on error
*/
ssize_t at_readline(at_dev_t *dev, char *resp_buf, size_t len, bool keep_eol, uint32_t timeout);
/**
* @brief Read a line from device, skipping a possibly empty line.
*
* @param[in] dev device to operate on
* @param[in] resp_buf buffer to store line
* @param[in] len size of @p resp_buf
* @param[in] keep_eol true to keep the CR character in the response
* @param[in] timeout timeout (in usec)
*
* @retval n line length on success
* @retval <0 on error
*/
ssize_t at_readline_skip_empty(at_dev_t *dev, char *resp_buf, size_t len,
bool keep_eol, uint32_t timeout);
/**
* @brief Drain device input buffer
*

View File

@ -73,6 +73,7 @@
#ifndef MTD_H
#define MTD_H
#include <stddef.h>
#include <stdint.h>
#include "xfa.h"
@ -517,6 +518,19 @@ int mtd_erase_sector(mtd_dev_t *mtd, uint32_t sector, uint32_t num);
*/
int mtd_power(mtd_dev_t *mtd, enum mtd_power_state power);
/**
* @brief Get an MTD device by index
*
* @param[in] idx Index of the MTD device
*
* @return MTD_0 for @p idx 0 and so on
* NULL if no MTD device exists for the given index
*/
static inline mtd_dev_t *mtd_dev_get(unsigned idx)
{
return ((MTD_NUMOF != 0) && (idx < MTD_NUMOF)) ? mtd_dev_xfa[idx] : NULL;
}
#ifdef __cplusplus
}
#endif

View File

@ -69,6 +69,8 @@ extern mtd_emulated_t mtd_emulated_dev0;
/**
* @brief Get the default MTD device by index
*
* @deprecated Use @ref mtd_dev_get instead
*
* @param[in] idx Index of the MTD device
*
* @return MTD_0 for @p idx 0 and so on

View File

@ -245,10 +245,10 @@ extern "C"
{
#endif
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include "kernel_defines.h"
#include "periph/gpio.h"
#include "periph/i2c.h"
@ -326,14 +326,18 @@ typedef uint8_t pcf857x_data_t; /**< type that can mask all expander pins */
#endif /* MODULE_PCF8575 || DOXYGEN */
/** @} */
/** Definition of PCF857X driver error codes */
/**
* @brief Definition of PCF857X driver error codes
*
* @deprecated These are aliases for errno error codes now, use them directly
*/
typedef enum {
PCF857X_OK, /**< success */
PCF857X_ERROR_I2C, /**< I2C communication error */
PCF857X_ERROR_INV_EXP, /**< invalid expander variant */
PCF857X_ERROR_INV_MODE, /**< invalid pin mode */
PCF857X_ERROR_INV_FLANK, /**< invalid interrupt flank */
PCF857X_ERROR_INT_PIN, /**< interrupt pin initialization failed */
PCF857X_OK = 0, /**< success */
PCF857X_ERROR_I2C = ENXIO, /**< I2C communication error */
PCF857X_ERROR_INV_EXP = ENOTSUP, /**< invalid expander variant */
PCF857X_ERROR_INV_MODE = EINVAL, /**< invalid pin mode */
PCF857X_ERROR_INV_FLANK = EINVAL, /**< invalid interrupt flank */
PCF857X_ERROR_INT_PIN = ENOSYS, /**< interrupt pin initialization failed */
} pcf857x_error_codes_t;
/**
@ -453,9 +457,8 @@ typedef struct {
* has to be defined by the default configuration parameter
* #PCF857X_PARAM_INT_PIN (pcf857x_params_t::int_pin).
*
* @retval PCF857X_OK on success
* @retval PCF857X_ERROR_* a negative error code on error,
* see #pcf857x_error_codes_t
* @retval 0 on success
* @retval <0 a negative errno error code on error
*/
int pcf857x_init(pcf857x_t *dev, const pcf857x_params_t *params);
@ -472,13 +475,12 @@ int pcf857x_init(pcf857x_t *dev, const pcf857x_params_t *params);
* the driver physically supports only the modes #GPIO_IN_PU and
* #GPIO_OD_PU. The other logically identical modes #GPIO_IN, #GPIO_OUT
* and #GPIO_OD are emulated. For the #GPIO_IN_PU mode the function returns
* with #PCF857X_ERROR_INV_MODE.
* with `-EINVAL`.
* - After initialization in #GPIO_OUT mode the pin is actively driven LOW,
* after initialization in all other modes the pin is pulled-up to HIGH.
*
* @retval PCF857X_OK on success
* @retval PCF857X_ERROR_* a negative error code on error,
* see #pcf857x_error_codes_t
* @retval 0 on success
* @retval <0 a negative errno error code on error
*/
int pcf857x_gpio_init(pcf857x_t *dev, gpio_t pin, gpio_mode_t mode);
@ -504,7 +506,7 @@ int pcf857x_gpio_init(pcf857x_t *dev, gpio_t pin, gpio_mode_t mode);
* the driver physically supports only the modes #GPIO_IN_PU and
* #GPIO_OD_PU. The other logically identical modes #GPIO_IN, #GPIO_OUT
* and #GPIO_OD are emulated. For the #GPIO_IN_PU mode the function returns
* with #PCF857X_ERROR_INV_MODE.
* with `-EINVAL`.
* - After initialization in #GPIO_OUT mode the pin is actively driven LOW,
* after initialization in all other modes the pin is pulled-up to HIGH.
*
@ -515,9 +517,8 @@ int pcf857x_gpio_init(pcf857x_t *dev, gpio_t pin, gpio_mode_t mode);
* @param[in] isr ISR that is called back from interrupt context
* @param[in] arg optional argument passed to the callback
*
* @retval PCF857X_OK on success
* @retval PCF857X_ERROR_* a negative error code on error,
* see #pcf857x_error_codes_t
* @retval 0 on success
* @retval <0 a negative errno error code on error
*/
int pcf857x_gpio_init_int(pcf857x_t *dev, gpio_t pin,
gpio_mode_t mode,

View File

@ -128,6 +128,33 @@ int adc_init(adc_t line);
*/
int32_t adc_sample(adc_t line, adc_res_t res);
/**
* @brief Configure the ADC with a given resolution for continuous sampling
*
* @note requires the `periph_adc_continuous` feature
*
* @param[in] res resolution to use for conversion
*/
void adc_continuous_begin(adc_res_t res);
/**
* @brief Sample an ADC line without powering off the ADC afterward
*
* @note requires the `periph_adc_continuous` feature
*
* @brief Sample a value from the given ADC line
*
* @return the sampled value on success
*/
int32_t adc_continuous_sample(adc_t line);
/**
* @brief Disable the ADC to save power
*
* @note requires the `periph_adc_continuous` feature
*/
void adc_continuous_stop(void);
#ifdef __cplusplus
}
#endif

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