I’m trying to port this OneWire library to the Photon. The main things that need to be changed are the methods of fast digital writes, digital reads, and pinmode changes.
The PJRC’s Arduino library uses a set of defines like this to do the fast reads, writes, and pinmode changes:
#if defined(__AVR__)
#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin)))
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
#define IO_REG_TYPE uint8_t
#define IO_REG_ASM asm("r30")
#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) &= ~(mask))
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+1)) |= (mask))
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+2)) &= ~(mask))
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+2)) |= (mask))
There is a port to the Spark Core by @tidwelltimj that replaces the defines with functions (and modifies the rest of the library to use these functions rather than the defines above):
void DIRECT_WRITE_LOW(void);
void DIRECT_MODE_OUTPUT(void);
void DIRECT_WRITE_HIGH(void);
void DIRECT_MODE_INPUT(void);
uint8_t DIRECT_READ(void);
These functions basically copy the internals of the Core’s wiring digital write/read and pin mode functions, but remove some of the checks to speed it up a little. They look like this:
// tidwelltimj's direct functions for the Core
void OneWire::DIRECT_WRITE_LOW(void)
{
PIN_MAP[_pin].gpio_peripheral->BRR = PIN_MAP[_pin].gpio_pin;
}
void OneWire::DIRECT_MODE_OUTPUT(void)
{
GPIO_TypeDef *gpio_port = PIN_MAP[_pin].gpio_peripheral;
uint16_t gpio_pin = PIN_MAP[_pin].gpio_pin;
GPIO_InitTypeDef GPIO_InitStructure;
if (gpio_port == GPIOA )
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
}
else if (gpio_port == GPIOB )
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
}
GPIO_InitStructure.GPIO_Pin = gpio_pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
PIN_MAP[_pin].pin_mode = OUTPUT;
GPIO_Init(gpio_port, &GPIO_InitStructure);
}
// ...etc.
I did a really naive port of this to the Photon by replacing @tidwelltimj’s functions with:
// My naive "direct" functions for the Photon.
void OneWire::DIRECT_WRITE_LOW(void){
HAL_GPIO_Write(_pin, LOW);
}
void OneWire::DIRECT_MODE_OUTPUT(void){
HAL_Pin_Mode(_pin, OUTPUT);
}
void OneWire::DIRECT_WRITE_HIGH(void){
HAL_GPIO_Write(_pin, HIGH);
}
void OneWire::DIRECT_MODE_INPUT(void){
HAL_Pin_Mode(_pin, INPUT);
}
uint8_t OneWire::DIRECT_READ(void){
return HAL_GPIO_Read(_pin);
}
This seems to work ok, but I was worried that it wasn’t going to be as reliable as the more direct methods.
In the port of the NeoPixel library, the following code is used to support fast writes on both the Core and the Photon:
#if PLATFORM_ID == 0 // Core
#define pinLO(_pin) (PIN_MAP[_pin].gpio_peripheral->BRR = PIN_MAP[_pin].gpio_pin)
#define pinHI(_pin) (PIN_MAP[_pin].gpio_peripheral->BSRR = PIN_MAP[_pin].gpio_pin)
#elif PLATFORM_ID == 6 // Photon
#include "pinmap_impl.h"
STM32_Pin_Info* PIN_MAP = HAL_Pin_Map(); // Pointer required for highest access speed
#define pinLO(_pin) (PIN_MAP[_pin].gpio_peripheral->BSRRH = PIN_MAP[_pin].gpio_pin)
#define pinHI(_pin) (PIN_MAP[_pin].gpio_peripheral->BSRRL = PIN_MAP[_pin].gpio_pin)
#else
#error "*** PLATFORM_ID not supported by this library. PLATFORM should be Core or Photon ***"
#endif
// fast pin access
#define pinSet(_pin, _hilo) (_hilo ? pinHI(_pin) : pinLO(_pin))
This seems like it’s what I’m looking for, but it only does digital write. Is there an equivalently simple set of defines that get a fast digital read and pin mode for both the core and the photon?
Am I write to worry about using the various HAL_xxx functions not being “direct” enough? Using the HAL_ functions worked for reading a DS18B20 temperature sensor, but I wasn’t sure if it was a complete solution.