[core] Refactor Wiring, use PinData for parameters

This commit is contained in:
Kuba Szczodrzyński
2023-05-24 18:20:22 +02:00
parent bc74c21599
commit e5f98ff41f
22 changed files with 397 additions and 394 deletions

View File

@@ -1,22 +1,11 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */ /* Copyright (c) Kuba Szczodrzyński 2022-06-19. */
#include <Arduino.h> #include "wiring_private.h"
#include <include.h>
#include <arm_arch.h>
#include <bk_timer.h>
#include <bk_timer_pub.h>
#include <rtos_pub.h>
#include <sys_rtos.h>
#define TICKS_PER_US (CFG_XTAL_FREQUENCE / 1000 / 1000) #define TICKS_PER_US (CFG_XTAL_FREQUENCE / 1000 / 1000)
#define US_PER_OVERFLOW (portTICK_PERIOD_MS * 1000) #define US_PER_OVERFLOW (portTICK_PERIOD_MS * 1000)
#define TICKS_PER_OVERFLOW (TICKS_PER_US * US_PER_OVERFLOW) #define TICKS_PER_OVERFLOW (TICKS_PER_US * US_PER_OVERFLOW)
void delayMilliseconds(unsigned long ms) {
rtos_delay_milliseconds(ms);
}
static uint32_t getTicksCount() { static uint32_t getTicksCount() {
// copied from bk_timer_ctrl(), for speeds // copied from bk_timer_ctrl(), for speeds
uint32_t timeout = 0; uint32_t timeout = 0;
@@ -104,8 +93,22 @@ unsigned long micros() {
#endif #endif
} }
void yield() { void pinRemoveMode(PinInfo *pin, uint32_t mask) {
runPeriodicTasks(); PinData *data = pinData(pin);
vTaskDelay(1); if ((mask & PIN_GPIO) && (pin->enabled & PIN_GPIO)) {
taskYIELD(); gpio_config(pin->gpio, GMODE_INPUT_PULLDOWN);
pinDisable(pin, PIN_GPIO);
}
if ((mask & PIN_IRQ) && (pin->enabled & PIN_IRQ)) {
data->irqHandler = NULL;
gpio_int_disable(pin->gpio);
pinDisable(pin, PIN_IRQ);
}
if ((mask & PIN_PWM) && (pin->enabled & PIN_PWM)) {
data->pwm->cfg.bits.en = PWM_DISABLE;
__wrap_bk_printf_disable();
sddev_control(PWM_DEV_NAME, CMD_PWM_DEINIT_PARAM, data->pwm);
__wrap_bk_printf_enable();
pinDisable(pin, PIN_PWM);
}
} }

View File

@@ -1,10 +1,6 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-20. */ /* Copyright (c) Kuba Szczodrzyński 2022-06-20. */
#include <Arduino.h> #include "wiring_private.h"
#include <gpio_pub.h>
#include <pwm_pub.h>
#include <saradc_pub.h>
static GPIO_INDEX pwmToGpio[] = { static GPIO_INDEX pwmToGpio[] = {
GPIO6, // PWM0 GPIO6, // PWM0
@@ -59,11 +55,7 @@ static pwm_param_t pwm;
static uint16_t adcData[1]; static uint16_t adcData[1];
uint16_t analogReadVoltage(pin_size_t pinNumber) { uint16_t analogReadVoltage(pin_size_t pinNumber) {
PinInfo *pin = pinInfo(pinNumber); pinCheckGetInfo(pinNumber, PIN_ADC, 0);
if (!pin)
return 0;
if (!pinSupported(pin, PIN_ADC))
return 0;
UINT32 status; UINT32 status;
saradc_desc_t adc; saradc_desc_t adc;
@@ -90,11 +82,10 @@ uint16_t analogReadMaxVoltage(pin_size_t pinNumber) {
} }
void analogWrite(pin_size_t pinNumber, int value) { void analogWrite(pin_size_t pinNumber, int value) {
PinInfo *pin = pinInfo(pinNumber); pinCheckGetData(pinNumber, PIN_PWM, );
if (!pin)
return; // GPIO can't be used together with PWM
if (!pinSupported(pin, PIN_PWM)) pinRemoveMode(pin, PIN_GPIO | PIN_IRQ);
return;
float percent = value * 1.0 / ((1 << _analogWriteResolution) - 1); float percent = value * 1.0 / ((1 << _analogWriteResolution) - 1);
uint32_t frequency = 26 * _analogWritePeriod - 1; uint32_t frequency = 26 * _analogWritePeriod - 1;
@@ -122,8 +113,9 @@ void analogWrite(pin_size_t pinNumber, int value) {
sddev_control(PWM_DEV_NAME, CMD_PWM_INIT_LEVL_SET_HIGH, &pwm.channel); sddev_control(PWM_DEV_NAME, CMD_PWM_INIT_LEVL_SET_HIGH, &pwm.channel);
sddev_control(PWM_DEV_NAME, CMD_PWM_UNIT_ENABLE, &pwm.channel); sddev_control(PWM_DEV_NAME, CMD_PWM_UNIT_ENABLE, &pwm.channel);
__wrap_bk_printf_enable(); __wrap_bk_printf_enable();
pin->enabled &= ~PIN_GPIO; // pass global PWM object pointer
pin->enabled |= PIN_PWM; data->pwm = &pwm;
pinEnable(pin, PIN_PWM);
} else { } else {
// update duty cycle // update duty cycle
sddev_control(PWM_DEV_NAME, CMD_PWM_SET_DUTY_CYCLE, &pwm); sddev_control(PWM_DEV_NAME, CMD_PWM_SET_DUTY_CYCLE, &pwm);
@@ -131,11 +123,7 @@ void analogWrite(pin_size_t pinNumber, int value) {
} else { } else {
if (pinEnabled(pin, PIN_PWM)) { if (pinEnabled(pin, PIN_PWM)) {
// disable PWM // disable PWM
pwm.cfg.bits.en = PWM_DISABLE; pinRemoveMode(pin, PIN_PWM);
__wrap_bk_printf_disable();
sddev_control(PWM_DEV_NAME, CMD_PWM_DEINIT_PARAM, &pwm);
__wrap_bk_printf_enable();
pin->enabled &= ~PIN_PWM;
} }
// force level as LOW // force level as LOW
pinMode(pinNumber, OUTPUT); pinMode(pinNumber, OUTPUT);

View File

@@ -0,0 +1,23 @@
/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */
#pragma once
#include <Arduino.h>
#include <sdk_private.h>
#ifdef __cplusplus
extern "C" {
#endif
struct PinData_s {
pwm_param_t *pwm;
PinMode gpioMode;
PinStatus irqMode;
void *irqHandler;
void *irqParam;
bool irqChange;
};
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -1,20 +1,16 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-20. */ /* Copyright (c) Kuba Szczodrzyński 2022-06-20. */
#include <Arduino.h> #include "wiring_private.h"
#include <gpio_pub.h>
void pinMode(pin_size_t pinNumber, PinMode pinMode) { void pinMode(pin_size_t pinNumber, PinMode pinMode) {
PinInfo *pin = pinInfo(pinNumber); pinCheckGetData(pinNumber, PIN_GPIO, );
if (!pin)
return; if (pinEnabled(pin, PIN_GPIO) && data->gpioMode == pinMode)
if (!pinSupported(pin, PIN_GPIO))
return;
if (pinEnabled(pin, PIN_PWM))
// disable PWM before using the pin
analogWrite(pinNumber, 0);
if (pinEnabled(pin, PIN_GPIO) && pin->mode == pinMode)
return; return;
// GPIO can't be used together with PWM
pinRemoveMode(pin, PIN_PWM);
switch (pinMode) { switch (pinMode) {
case INPUT: case INPUT:
gpio_config(pin->gpio, GMODE_INPUT); gpio_config(pin->gpio, GMODE_INPUT);
@@ -31,34 +27,21 @@ void pinMode(pin_size_t pinNumber, PinMode pinMode) {
case OUTPUT_OPENDRAIN: case OUTPUT_OPENDRAIN:
gpio_config(pin->gpio, GMODE_SET_HIGH_IMPENDANCE); gpio_config(pin->gpio, GMODE_SET_HIGH_IMPENDANCE);
break; break;
default:
return;
} }
pin->enabled |= PIN_GPIO; pinEnable(pin, PIN_GPIO);
pin->mode = pinMode; data->gpioMode = pinMode;
} }
void digitalWrite(pin_size_t pinNumber, PinStatus status) { void digitalWrite(pin_size_t pinNumber, PinStatus status) {
// verify level is 0 or 1 pinCheckGetData(pinNumber, PIN_GPIO, );
if (status > HIGH) pinSetOutputPull(pin, data, pinNumber, status);
return; gpio_output(pin->gpio, !!status);
PinInfo *pin = pinInfo(pinNumber);
if (!pin)
return;
// pin is not GPIO yet or not OUTPUT; enable or disable input pullup
if (!pinEnabled(pin, PIN_GPIO) || !pinIsOutput(pin)) {
pinMode(pinNumber, status * INPUT_PULLUP);
return;
}
// write the new state
gpio_output(pin->gpio, status);
} }
PinStatus digitalRead(pin_size_t pinNumber) { PinStatus digitalRead(pin_size_t pinNumber) {
PinInfo *pin = pinInfo(pinNumber); pinCheckGetData(pinNumber, PIN_GPIO, LOW);
if (!pin) pinSetInputMode(pin, data, pinNumber);
return 0;
// pin is not GPIO yet or not INPUT; change the mode
if (!pinEnabled(pin, PIN_GPIO) || !pinIsInput(pin))
pinMode(pinNumber, INPUT);
// read the value
return gpio_input(pin->gpio); return gpio_input(pin->gpio);
} }

View File

@@ -1,98 +1,70 @@
/* Copyright (c) Kuba Szczodrzyński 2022-07-31. */ /* Copyright (c) Kuba Szczodrzyński 2022-07-31. */
#include <Arduino.h> #include "wiring_private.h"
#include <gpio_pub.h>
static void *irqHandlerList[PINS_COUNT] = {NULL};
static void *irqHandlerArgs[PINS_COUNT] = {NULL};
static bool irqChangeList[PINS_COUNT];
static void irqHandler(unsigned char gpio) { static void irqHandler(unsigned char gpio) {
PinInfo *pin = pinByGpio(gpio); PinInfo *pin = pinByGpio(gpio);
if (pin == NULL) if (pin == NULL)
return; return;
uint32_t index = pinIndex(pin); PinData *data = pinData(pin);
if (!irqHandlerList[index]) if (!data->irqHandler)
return; return;
if (irqChangeList[index]) { if (data->irqChange) {
if (pin->mode == INPUT_PULLDOWN) { if (data->gpioMode == INPUT_PULLDOWN) {
pin->mode = INPUT_PULLUP; data->gpioMode = INPUT_PULLUP;
gpio_int_enable(pin->gpio, GPIO_INT_LEVEL_FALLING, irqHandler); gpio_int_enable(pin->gpio, GPIO_INT_LEVEL_FALLING, irqHandler);
} else if (pin->mode == INPUT_PULLUP) { } else if (data->gpioMode == INPUT_PULLUP) {
pin->mode = INPUT_PULLDOWN; data->gpioMode = INPUT_PULLDOWN;
gpio_int_enable(pin->gpio, GPIO_INT_LEVEL_RISING, irqHandler); gpio_int_enable(pin->gpio, GPIO_INT_LEVEL_RISING, irqHandler);
} }
} }
if (irqHandlerArgs[index] == NULL) { if (!data->irqParam)
((voidFuncPtr)irqHandlerList[index])(); ((voidFuncPtr)data->irqHandler)();
} else { else
((voidFuncPtrParam)irqHandlerList[index])(irqHandlerArgs[index]); ((voidFuncPtrParam)data->irqHandler)(data->irqParam);
}
}
void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode) {
attachInterruptParam(interruptNumber, (voidFuncPtrParam)callback, mode, NULL);
} }
void attachInterruptParam(pin_size_t interruptNumber, voidFuncPtrParam callback, PinStatus mode, void *param) { void attachInterruptParam(pin_size_t interruptNumber, voidFuncPtrParam callback, PinStatus mode, void *param) {
PinInfo *pin = pinInfo(interruptNumber); pinCheckGetData(interruptNumber, PIN_IRQ, );
if (!pin)
return;
if (!pinSupported(pin, PIN_IRQ))
return;
uint32_t index = pinIndex(pin);
uint32_t event = 0;
PinMode modeNew = 0;
bool change = 0;
data->irqHandler = callback;
data->irqParam = param;
if (pinEnabled(pin, PIN_IRQ) && data->irqMode == mode)
return;
// GPIO can't be used together with PWM
pinRemoveMode(pin, PIN_PWM);
uint32_t event = 0;
bool change = false;
switch (mode) { switch (mode) {
case LOW: case LOW:
event = GPIO_INT_LEVEL_LOW; event = GPIO_INT_LEVEL_LOW;
modeNew = INPUT_PULLUP;
change = false;
break; break;
case HIGH: case HIGH:
event = GPIO_INT_LEVEL_HIGH; event = GPIO_INT_LEVEL_HIGH;
modeNew = INPUT_PULLDOWN;
change = false;
break; break;
case FALLING: case FALLING:
event = GPIO_INT_LEVEL_FALLING; event = GPIO_INT_LEVEL_FALLING;
modeNew = INPUT_PULLUP;
change = false;
break; break;
case RISING: case RISING:
event = GPIO_INT_LEVEL_RISING; event = GPIO_INT_LEVEL_RISING;
modeNew = INPUT_PULLDOWN;
change = false;
break; break;
case CHANGE: case CHANGE:
event = GPIO_INT_LEVEL_FALLING; event = GPIO_INT_LEVEL_FALLING;
modeNew = INPUT_PULLUP; change = true;
change = true;
break; break;
default: default:
return; return;
} }
irqHandlerList[index] = callback; pinEnable(pin, PIN_IRQ);
irqHandlerArgs[index] = param; data->irqMode = mode;
irqChangeList[index] = change; data->irqChange = change;
gpio_int_enable(pin->gpio, event, irqHandler); gpio_int_enable(pin->gpio, event, irqHandler);
pin->enabled |= PIN_IRQ | PIN_GPIO;
pin->mode = modeNew;
} }
void detachInterrupt(pin_size_t interruptNumber) { void detachInterrupt(pin_size_t interruptNumber) {
PinInfo *pin = pinInfo(interruptNumber); pinModeRemove(interruptNumber, PIN_IRQ);
if (!pin)
return;
if (!pinSupported(pin, PIN_IRQ))
return;
uint32_t index = pinIndex(pin);
irqHandlerList[index] = NULL;
irqHandlerArgs[index] = NULL;
irqChangeList[index] = false;
gpio_int_disable(pin->gpio);
pin->enabled &= ~PIN_IRQ;
} }

View File

@@ -6,12 +6,18 @@
extern "C" { extern "C" {
#endif // __cplusplus #endif // __cplusplus
// most stuff is here // most stuff is here - this has to be before other includes!
#include <include.h> #include <include.h>
// other includes // other includes
#include <arm_arch.h>
#include <bk_timer.h>
#include <bk_timer_pub.h>
#include <flash_pub.h> #include <flash_pub.h>
#include <gpio_pub.h> #include <gpio_pub.h>
#include <param_config.h> #include <param_config.h>
#include <pwm_pub.h>
#include <rtos_pub.h>
#include <saradc_pub.h>
#include <start_type_pub.h> #include <start_type_pub.h>
#include <sys_ctrl.h> #include <sys_ctrl.h>
#include <sys_rtos.h> #include <sys_rtos.h>

View File

@@ -0,0 +1,17 @@
/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */
#include <Arduino.h>
#if LT_HAS_FREERTOS
__attribute__((weak)) void delay(uint32_t ms) {
vTaskDelay(pdMS_TO_TICKS(ms));
}
__attribute__((weak)) void yield() {
runPeriodicTasks();
vTaskDelay(1);
taskYIELD();
}
#endif

View File

@@ -1,6 +1,6 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-20. */ /* Copyright (c) Kuba Szczodrzyński 2022-06-20. */
#include "wiring_custom.h" #include "wiring_private.h"
#if LT_HAS_FREERTOS #if LT_HAS_FREERTOS
#include <FreeRTOS.h> #include <FreeRTOS.h>
@@ -32,6 +32,18 @@ void runPeriodicTasks() {
#endif #endif
} }
/**
* @brief Disable modes specified by 'mask'.
*/
void pinModeRemove(pin_size_t pinNumber, uint32_t mask) {
PinInfo *pin = pinInfo(pinNumber);
if (!pin)
return;
pinRemoveMode(pin, mask);
if (pin->enabled == PIN_NONE && mask == PIN_MODE_ALL)
pinRemoveData(pin);
}
/** /**
* @brief Get PinInfo struct for the specified number. * @brief Get PinInfo struct for the specified number.
* Returns NULL if pin number is invalid. * Returns NULL if pin number is invalid.
@@ -85,20 +97,6 @@ bool pinEnabled(PinInfo *pin, uint32_t mask) {
return (pin->enabled & mask) == mask; return (pin->enabled & mask) == mask;
} }
/**
* @brief Check if GPIO pin is configured as output.
*/
bool pinIsOutput(PinInfo *pin) {
return pin->mode == OUTPUT || pin->mode == OUTPUT_OPENDRAIN;
}
/**
* @brief Check if GPIO pin is configured as output.
*/
bool pinIsInput(PinInfo *pin) {
return pin->mode == INPUT || pin->mode == INPUT_PULLUP || pin->mode == INPUT_PULLDOWN;
}
/** /**
* @brief Read voltage from ADC and return a value between 0 and * @brief Read voltage from ADC and return a value between 0 and
* the current reading resolution. * the current reading resolution.

View File

@@ -21,7 +21,10 @@ extern "C" {
#define PIN_SWD (1 << 10) #define PIN_SWD (1 << 10)
#define PIN_UART (1 << 11) #define PIN_UART (1 << 11)
#define PIN_INVALID 255 #define PIN_MODE_ALL 0xFFFFFFFF
#define PIN_INVALID 255
typedef struct PinData_s PinData;
typedef struct { typedef struct {
/** /**
@@ -37,9 +40,9 @@ typedef struct {
*/ */
uint32_t enabled; uint32_t enabled;
/** /**
* @brief Pin mode (direction, IRQ level, etc.). * @brief Pin data (direction, IRQ level, etc.). The structure is family-specific.
*/ */
uint32_t mode; PinData *data;
} PinInfo; } PinInfo;
extern PinInfo lt_arduino_pin_info_list[PINS_COUNT]; extern PinInfo lt_arduino_pin_info_list[PINS_COUNT];
@@ -57,14 +60,21 @@ bool startMainTask(void);
void mainTask(const void *arg); // implemented in main.cpp void mainTask(const void *arg); // implemented in main.cpp
void runPeriodicTasks(); // implemented in wiring_custom.c void runPeriodicTasks(); // implemented in wiring_custom.c
void pinModeRemove(pin_size_t pinNumber, uint32_t mask);
PinInfo *pinInfo(pin_size_t pinNumber); PinInfo *pinInfo(pin_size_t pinNumber);
PinInfo *pinByIndex(uint32_t index); PinInfo *pinByIndex(uint32_t index);
PinInfo *pinByGpio(uint32_t gpio); PinInfo *pinByGpio(uint32_t gpio);
uint32_t pinIndex(PinInfo *pin); uint32_t pinIndex(PinInfo *pin);
bool pinSupported(PinInfo *pin, uint32_t mask); bool pinSupported(PinInfo *pin, uint32_t mask);
bool pinEnabled(PinInfo *pin, uint32_t mask); bool pinEnabled(PinInfo *pin, uint32_t mask);
bool pinIsOutput(PinInfo *pin); void pinRemoveMode(PinInfo *pin, uint32_t mask);
bool pinIsInput(PinInfo *pin);
/**
* @brief Deinitialize the pin, by removing all enabled modes.
*/
inline void pinModeNone(pin_size_t pinNumber) {
pinModeRemove(pinNumber, PIN_MODE_ALL);
}
int analogRead(pin_size_t pinNumber); int analogRead(pin_size_t pinNumber);
void analogReadResolution(int res); void analogReadResolution(int res);

View File

@@ -0,0 +1,7 @@
/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */
#include <Arduino.h>
void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode) {
attachInterruptParam(interruptNumber, (voidFuncPtrParam)callback, mode, NULL);
}

View File

@@ -0,0 +1,25 @@
/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */
#include "wiring_private.h"
#if __has_include(<wiring_data.h>)
/**
* @brief Allocate and return a PinData structure (family-specific).
*/
PinData *pinData(PinInfo *pin) {
if (pin->data == NULL) {
pin->data = calloc(1, sizeof(PinData));
}
return (PinData *)pin->data;
}
/**
* @brief Deallocate the PinData structure.
*/
void pinRemoveData(PinInfo *pin) {
if (pin->data != NULL) {
free(pin->data);
}
pin->data = NULL;
}
#endif

View File

@@ -0,0 +1,64 @@
/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */
#pragma once
#include <Arduino.h>
#if __has_include(<sdk_private.h>)
#include <sdk_private.h>
#endif
#if __has_include(<wiring_data.h>)
#include <wiring_data.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
PinData *pinData(PinInfo *pin);
void pinRemoveData(PinInfo *pin);
inline void pinEnable(PinInfo *pin, uint32_t mask) {
pin->enabled |= mask;
}
inline void pinDisable(PinInfo *pin, uint32_t mask) {
pin->enabled &= ~mask;
}
#define pinCheckGetInfo(pinNumber, mask, ret) \
PinInfo *pin = pinInfo(pinNumber); \
if (!pin) \
return ret; \
if (!pinSupported(pin, mask)) \
return ret;
#define pinCheckGetData(pinNumber, mask, ret) \
PinInfo *pin = pinInfo(pinNumber); \
if (!pin) \
return ret; \
if (!pinSupported(pin, mask)) \
return ret; \
PinData *data = pinData(pin);
#define pinIsOutput(pin, data) (pinEnabled(pin, PIN_GPIO) && (data->gpioMode ^ 0b101) < 5)
#define pinIsInput(pin, data) (pinEnabled(pin, PIN_GPIO) && (data->gpioMode ^ 0b101) > 4)
#define pinSetOutputPull(pin, data, pinNumber, status) \
do { \
if (!pinIsOutput(pin, data)) { \
pinMode(pinNumber, INPUT_PULLDOWN ^ !!status); \
return; \
} \
} while (0);
#define pinSetInputMode(pin, data, pinNumber) \
do { \
if (!pinIsInput(pin, data)) \
pinMode(pinNumber, INPUT); \
} while (0);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -1,12 +0,0 @@
#include <Arduino.h>
extern void pinRemoveMode(pin_size_t pinNumber);
extern void _tone(uint32_t ulPin, unsigned int frequency, unsigned long duration);
void tone(uint32_t ulPin, unsigned int frequency, unsigned long duration) {
_tone(ulPin, frequency, duration);
}
void noTone(uint32_t ulPin) {
pinRemoveMode(ulPin);
}

View File

@@ -1,48 +1,11 @@
/* /* Copyright (c) Kuba Szczodrzyński 2022-04-23. */
Copyright (c) 2011 Arduino. All right reserved.
This library is free software; you can redistribute it and/or #include "wiring_private.h"
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <Arduino.h>
#include <cmsis_os.h>
#ifndef portNVIC_SYSTICK_CURRENT_VALUE_REG #ifndef portNVIC_SYSTICK_CURRENT_VALUE_REG
#define portNVIC_SYSTICK_CURRENT_VALUE_REG (*((volatile uint32_t *)0xe000e018)) #define portNVIC_SYSTICK_CURRENT_VALUE_REG (*((volatile uint32_t *)0xe000e018))
#endif #endif
extern uint32_t xTaskGetTickCount();
extern uint32_t xTaskGetTickCountFromISR();
static __inline uint32_t __get_ipsr__(void) {
volatile uint32_t __regIPSR __asm("ipsr");
return (__regIPSR);
}
void *gpio_pin_struct[PINS_COUNT] = {NULL};
void delay(uint32_t ms) {
/* osStatus ret; */
/* ret = */ osDelay(ms);
/* if ((ret != osEventTimeout) && (ret != osOK)) {
printf("delay : ERROR : 0x%x \n", ret);
} */
}
void delayMicroseconds(unsigned int us) { void delayMicroseconds(unsigned int us) {
int i; int i;
uint32_t t0, tn; uint32_t t0, tn;
@@ -61,7 +24,7 @@ void delayMicroseconds(unsigned int us) {
} }
unsigned long millis(void) { unsigned long millis(void) {
return (__get_ipsr__() == 0) ? xTaskGetTickCount() : xTaskGetTickCountFromISR(); return (__get_IPSR() == 0) ? xTaskGetTickCount() : xTaskGetTickCountFromISR();
} }
unsigned long micros(void) { unsigned long micros(void) {
@@ -69,7 +32,7 @@ unsigned long micros(void) {
uint32_t us; uint32_t us;
uint32_t tick_per_us = F_CPU / 1000; uint32_t tick_per_us = F_CPU / 1000;
if (__get_ipsr__() == 0) { if (__get_IPSR() == 0) {
tick1 = xTaskGetTickCount(); tick1 = xTaskGetTickCount();
us = portNVIC_SYSTICK_CURRENT_VALUE_REG; us = portNVIC_SYSTICK_CURRENT_VALUE_REG;
tick2 = xTaskGetTickCount(); tick2 = xTaskGetTickCount();
@@ -88,8 +51,22 @@ unsigned long micros(void) {
} }
} }
void yield(void) { void pinRemoveMode(PinInfo *pin, uint32_t mask) {
runPeriodicTasks(); PinData *data = pinData(pin);
vTaskDelay(1); if ((mask & PIN_GPIO) && (pin->enabled & PIN_GPIO)) {
taskYIELD(); gpio_deinit(data->gpio);
free(data->gpio);
pinDisable(pin, PIN_GPIO);
}
if ((mask & PIN_IRQ) && (pin->enabled & PIN_IRQ)) {
data->irqHandler = NULL;
gpio_irq_free(data->irq);
free(data->irq);
pinDisable(pin, PIN_IRQ);
}
if ((mask & PIN_PWM) && (pin->enabled & PIN_PWM)) {
pwmout_free(data->pwm);
free(data->pwm);
pinDisable(pin, PIN_PWM);
}
} }

View File

@@ -1,23 +1,6 @@
/* /* Copyright (c) Kuba Szczodrzyński 2022-06-20. */
Copyright (c) 2011 Arduino. All right reserved.
This library is free software; you can redistribute it and/or #include "wiring_private.h"
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <Arduino.h>
#include <sdk_private.h>
/* ADC */ /* ADC */
static analogin_t adc1; static analogin_t adc1;
@@ -28,17 +11,13 @@ static bool g_adc_enabled[] = {false, false, false};
// from realtek_amebaz_va0_example/example_sources/adc_vbat/src/main.c // from realtek_amebaz_va0_example/example_sources/adc_vbat/src/main.c
#define AD2MV(ad, offset, gain) (((ad >> 4) - offset) * 1000 / gain) #define AD2MV(ad, offset, gain) (((ad >> 4) - offset) * 1000 / gain)
extern void *gpio_pin_struct[];
extern void pinRemoveMode(pin_size_t pinNumber);
// TODO implement custom ADC calibration // TODO implement custom ADC calibration
uint16_t analogReadVoltage(pin_size_t pinNumber) { uint16_t analogReadVoltage(pin_size_t pinNumber) {
uint16_t ret = 0; uint16_t ret = 0;
switch (pinNumber) { switch (pinNumber) {
#ifdef PIN_A1 #ifdef PIN_ADC2
case PIN_A1: case PIN_ADC2:
if (g_adc_enabled[1] == false) { if (g_adc_enabled[1] == false) {
analogin_init(&adc2, AD_2); analogin_init(&adc2, AD_2);
g_adc_enabled[1] = true; g_adc_enabled[1] = true;
@@ -47,8 +26,8 @@ uint16_t analogReadVoltage(pin_size_t pinNumber) {
// AD_1 - 0.0V-5.0V // AD_1 - 0.0V-5.0V
return AD2MV(ret, 0x496, 0xBA); return AD2MV(ret, 0x496, 0xBA);
#endif #endif
#ifdef PIN_A0 #ifdef PIN_ADC1
case PIN_A0: case PIN_ADC1:
if (g_adc_enabled[0] == false) { if (g_adc_enabled[0] == false) {
analogin_init(&adc1, AD_1); analogin_init(&adc1, AD_1);
g_adc_enabled[0] = true; g_adc_enabled[0] = true;
@@ -56,8 +35,8 @@ uint16_t analogReadVoltage(pin_size_t pinNumber) {
ret = analogin_read_u16(&adc1); ret = analogin_read_u16(&adc1);
break; break;
#endif #endif
#ifdef PIN_A2 #ifdef PIN_ADC3
case PIN_A2: case PIN_ADC3:
if (g_adc_enabled[2] == false) { if (g_adc_enabled[2] == false) {
analogin_init(&adc3, AD_3); analogin_init(&adc3, AD_3);
g_adc_enabled[2] = true; g_adc_enabled[2] = true;
@@ -82,27 +61,20 @@ uint16_t analogReadMaxVoltage(pin_size_t pinNumber) {
} }
void analogWrite(pin_size_t pinNumber, int value) { void analogWrite(pin_size_t pinNumber, int value) {
PinInfo *pin = pinInfo(pinNumber); pinCheckGetData(pinNumber, PIN_PWM, );
if (!pin)
return;
pwmout_t *obj;
if (pinSupported(pin, PIN_PWM)) { // GPIO can't be used together with PWM
float percent = value * 1.0 / (1 << _analogWriteResolution); pinRemoveMode(pin, PIN_GPIO | PIN_IRQ);
if (pin->enabled != PIN_PWM) {
if ((pin->enabled == PIN_GPIO) || (pin->enabled == PIN_IRQ)) { pwmout_t *pwm = data->pwm;
pinRemoveMode(pinNumber); if (!pwm) {
} // allocate memory if pin not used before
gpio_pin_struct[pinNumber] = malloc(sizeof(pwmout_t)); data->pwm = pwm = malloc(sizeof(pwmout_t));
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber]; pwmout_init(pwm, pin->gpio);
pwmout_init(obj, pin->gpio); pwmout_period_us(pwm, _analogWritePeriod);
pwmout_period_us(obj, _analogWritePeriod); pinEnable(pin, PIN_PWM);
pwmout_write(obj, percent);
pin->enabled = PIN_PWM;
} else {
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber];
// pwmout_period_us(obj, _writePeriod);
pwmout_write(obj, percent);
}
} }
float percent = value * 1.0 / (1 << _analogWriteResolution);
pwmout_write(pwm, percent);
} }

View File

@@ -0,0 +1,24 @@
/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */
#pragma once
#include <Arduino.h>
#include <sdk_private.h>
#ifdef __cplusplus
extern "C" {
#endif
struct PinData_s {
gpio_t *gpio;
gpio_irq_t *irq;
pwmout_t *pwm;
PinMode gpioMode;
PinStatus irqMode;
void *irqHandler;
void *irqParam;
};
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -1,68 +1,32 @@
#include <Arduino.h> /* Copyright (c) Kuba Szczodrzyński 2022-04-23. */
#include <sdk_private.h>
extern void *gpio_pin_struct[PINS_COUNT]; #include "wiring_private.h"
void pinRemoveMode(pin_size_t pinNumber) {
PinInfo *pin = pinInfo(pinNumber);
if (!pin)
return;
if (pinEnabled(pin, PIN_PWM)) {
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber];
pwmout_free(obj);
}
if (pinEnabled(pin, PIN_GPIO)) {
gpio_t *obj = (gpio_t *)gpio_pin_struct[pinNumber];
gpio_deinit(obj);
free(obj);
}
if (pinEnabled(pin, PIN_IRQ)) {
gpio_irq_t *obj = (gpio_irq_t *)gpio_pin_struct[pinNumber];
gpio_irq_deinit(obj);
free(obj);
}
gpio_pin_struct[pinNumber] = NULL;
pin->enabled = PIN_NONE;
}
void pinMode(pin_size_t pinNumber, PinMode pinMode) { void pinMode(pin_size_t pinNumber, PinMode pinMode) {
PinInfo *pin = pinInfo(pinNumber); pinCheckGetData(pinNumber, PIN_GPIO, );
if (!pin)
if (pinEnabled(pin, PIN_GPIO) && data->gpioMode == pinMode)
return; return;
if (pinEnabled(pin, PIN_GPIO) && pin->mode == pinMode) #if LT_RTL8720C
// Nothing changes in pin mode // apparently IRQ can't be used with any kind of pull-up/down
return; // TODO verify if it can be used on AmebaZ
pinRemoveMode(pin, PIN_PWM | PIN_IRQ);
#else
// GPIO can't be used together with PWM
pinRemoveMode(pin, PIN_PWM);
#endif
if (!pinSupported(pin, PIN_GPIO)) gpio_t *gpio = data->gpio;
// cannot set ADC as I/O if (!gpio) {
return;
/* if (pin->enabled == PIN_PWM) {
// If this pin has been configured as PWM, then it cannot change to another mode
return;
} */
if (pin->enabled != PIN_GPIO)
// pin mode changes; deinit gpio and free memory
pinRemoveMode(pinNumber);
gpio_t *gpio;
if (pin->enabled == PIN_NONE) {
// allocate memory if pin not used before // allocate memory if pin not used before
gpio = malloc(sizeof(gpio_t)); data->gpio = gpio = malloc(sizeof(gpio_t));
gpio_pin_struct[pinNumber] = gpio;
gpio_init(gpio, pin->gpio); gpio_init(gpio, pin->gpio);
pin->enabled = PIN_GPIO; pinEnable(pin, PIN_GPIO);
} else {
// pin already used as gpio
gpio = (gpio_t *)gpio_pin_struct[pinNumber];
} }
pin->mode = pinMode;
PinDirection dir; PinDirection dir;
PinMode mode; PinModeRTL mode;
switch (pinMode) { switch (pinMode) {
case INPUT: case INPUT:
@@ -88,29 +52,20 @@ void pinMode(pin_size_t pinNumber, PinMode pinMode) {
default: default:
return; return;
} }
data->gpioMode = pinMode;
gpio_dir(gpio, dir); gpio_dir(gpio, dir);
gpio_mode(gpio, mode); gpio_mode(gpio, mode);
} }
void digitalWrite(pin_size_t pinNumber, PinStatus status) { void digitalWrite(pin_size_t pinNumber, PinStatus status) {
PinInfo *pin = pinInfo(pinNumber); pinCheckGetData(pinNumber, PIN_GPIO, );
if (!pin) pinSetOutputPull(pin, data, pinNumber, status);
return; gpio_write(data->gpio, !!status);
if (pin->enabled != PIN_GPIO)
return;
gpio_t *gpio = (gpio_t *)gpio_pin_struct[pinNumber];
gpio_write(gpio, status);
} }
PinStatus digitalRead(pin_size_t pinNumber) { PinStatus digitalRead(pin_size_t pinNumber) {
PinInfo *pin = pinInfo(pinNumber); pinCheckGetData(pinNumber, PIN_GPIO, LOW);
if (!pin) pinSetInputMode(pin, data, pinNumber);
return LOW; return gpio_read(data->gpio);
if (pin->enabled != PIN_GPIO)
return LOW;
gpio_t *gpio = (gpio_t *)gpio_pin_struct[pinNumber];
return gpio_read(gpio);
} }

View File

@@ -1,59 +1,50 @@
#include <Arduino.h> /* Copyright (c) Kuba Szczodrzyński 2022-04-23. */
#include <sdk_private.h>
extern void *gpio_pin_struct[PINS_COUNT]; #include "wiring_private.h"
static void *gpio_irq_handler_list[PINS_COUNT] = {NULL};
static void *gpio_irq_handler_args[PINS_COUNT] = {NULL};
extern void pinRemoveMode(pin_size_t pinNumber);
static void gpioIrqHandler(uint32_t id, gpio_irq_event event) { static void gpioIrqHandler(uint32_t id, gpio_irq_event event) {
// id is pin index // id is pin data
if (gpio_irq_handler_list[id] != NULL) { PinData *data = (PinData *)id;
if (gpio_irq_handler_args[id] == NULL) if (!data->irqHandler)
((voidFuncPtr)gpio_irq_handler_list[id])(); return;
else if (!data->irqParam)
((voidFuncPtrParam)gpio_irq_handler_list[id])(gpio_irq_handler_args[id]); ((voidFuncPtr)data->irqHandler)();
} else
} ((voidFuncPtrParam)data->irqHandler)(data->irqParam);
void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode) {
attachInterruptParam(interruptNumber, (voidFuncPtrParam)callback, mode, NULL);
} }
void attachInterruptParam(pin_size_t interruptNumber, voidFuncPtrParam callback, PinStatus mode, void *param) { void attachInterruptParam(pin_size_t interruptNumber, voidFuncPtrParam callback, PinStatus mode, void *param) {
PinInfo *pin = pinInfo(interruptNumber); pinCheckGetData(interruptNumber, PIN_IRQ, );
if (pin == NULL)
return;
uint32_t index = pinIndex(pin);
gpio_irq_handler_list[index] = callback; data->irqHandler = callback;
gpio_irq_handler_args[index] = param; data->irqParam = param;
if (pin->enabled == PIN_IRQ && pin->mode == mode) if (pinEnabled(pin, PIN_IRQ) && data->irqMode == mode)
// Nothing changes in pin mode
return; return;
if (pin->enabled != PIN_IRQ) #if LT_RTL8720C
// pin mode changes; deinit gpio and free memory // apparently IRQ can't be used with any kind of pull-up/down
pinRemoveMode(interruptNumber); // TODO verify if it can be used on AmebaZ
pinRemoveMode(pin, PIN_PWM | PIN_GPIO);
#else
// GPIO can't be used together with PWM
pinRemoveMode(pin, PIN_PWM);
#endif
gpio_irq_t *gpio; gpio_irq_t *irq = data->irq;
if (!irq) {
if (pin->enabled == PIN_NONE) {
// allocate memory if pin not used before // allocate memory if pin not used before
gpio = malloc(sizeof(gpio_irq_t)); data->irq = irq = malloc(sizeof(gpio_irq_t));
gpio_pin_struct[index] = gpio; if (gpio_irq_init(irq, pin->gpio, gpioIrqHandler, (uint32_t)data) != 0) {
gpio_irq_init(gpio, pin->gpio, gpioIrqHandler, index); LT_W("IRQ init failed");
pin->enabled = PIN_IRQ; free(data->irq);
} else { data->irq = NULL;
// pin already used as irq return;
gpio = (gpio_irq_t *)gpio_pin_struct[index]; }
pinEnable(pin, PIN_IRQ);
} }
pin->mode = mode;
gpio_irq_event event; gpio_irq_event event;
switch (mode) { switch (mode) {
case LOW: case LOW:
event = IRQ_LOW; event = IRQ_LOW;
@@ -67,22 +58,22 @@ void attachInterruptParam(pin_size_t interruptNumber, voidFuncPtrParam callback,
case RISING: case RISING:
event = IRQ_RISE; event = IRQ_RISE;
break; break;
case CHANGE:
#if LT_RTL8720C
event = IRQ_FALL_RISE;
#else
LT_W("CHANGE interrupts not supported");
#endif
break;
default: default:
return; return;
} }
data->irqMode = mode;
gpio_irq_set(gpio, event, 1); gpio_irq_set(irq, event, 1);
gpio_irq_enable(gpio); gpio_irq_enable(irq);
} }
void detachInterrupt(pin_size_t interruptNumber) { void detachInterrupt(pin_size_t interruptNumber) {
PinInfo *pin = pinInfo(interruptNumber); pinModeRemove(interruptNumber, PIN_IRQ);
if (pin == NULL)
return;
uint32_t index = pinIndex(pin);
if (pin->enabled == PIN_IRQ) {
pinRemoveMode(interruptNumber);
}
gpio_irq_handler_list[index] = NULL;
} }

View File

@@ -16,10 +16,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <Arduino.h> #include "wiring_private.h"
#include <sdk_private.h>
extern void *gpio_pin_struct[];
/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH /* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds * or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
@@ -34,19 +31,17 @@ extern unsigned long pulseIn(uint8_t pinNumber, uint8_t state, unsigned long tim
return 0; return 0;
uint32_t index = pinIndex(pin); uint32_t index = pinIndex(pin);
gpio_t *pGpio_t;
uint32_t start_ticks, cur_ticks; uint32_t start_ticks, cur_ticks;
if (pin->gpio == NC) if (pin->gpio == NC)
return 0; return 0;
/* Handle */ /* Handle */
if (pin->enabled != PIN_GPIO) { if (!pinEnabled(pin, PIN_GPIO)) {
return 0; return 0;
} }
PinData *data = pinData(pin);
pGpio_t = (gpio_t *)gpio_pin_struct[index]; gpio_t *pGpio_t = data->gpio;
// wait for any previous pulse to end // wait for any previous pulse to end
start_ticks = us_ticker_read(); start_ticks = us_ticker_read();

View File

@@ -27,6 +27,9 @@ extern "C" {
#endif #endif
#include <cmsis_os.h> #include <cmsis_os.h>
#undef malloc
#undef free
#undef calloc
// mbed APIs // mbed APIs
#include <gpio_api.h> #include <gpio_api.h>

View File

@@ -78,6 +78,7 @@ lt_reboot_reason_t lt_get_reboot_reason() {
void lt_gpio_recover() { void lt_gpio_recover() {
sys_jtag_off(); sys_jtag_off();
sys_swd_off();
} }
/*__ __ /*__ __

View File

@@ -11,6 +11,7 @@ extern "C" {
// SDK // SDK
void software_reset(); void software_reset();
void sys_swd_off();
void sys_uart_download_mode(); void sys_uart_download_mode();
void sys_download_mode(uint8_t mode); void sys_download_mode(uint8_t mode);