diff --git a/src/PAL/Include/CPU_GPIO_decl.h b/src/PAL/Include/CPU_GPIO_decl.h index 8d485ce2b6..b0be99d11d 100644 --- a/src/PAL/Include/CPU_GPIO_decl.h +++ b/src/PAL/Include/CPU_GPIO_decl.h @@ -7,19 +7,18 @@ #ifndef _DRIVERS_GPIO_DECL_H_ #define _DRIVERS_GPIO_DECL_H_ 1 -#if defined (__GNUC__) +#if defined(__GNUC__) #define __int64 long long #endif typedef unsigned __int64 CLR_UINT64; -#define GPIO_PIN_NONE 0xFFFFFFFF - -#define GPIO_ATTRIBUTE_NONE 0x00 -#define GPIO_ATTRIBUTE_INPUT 0x01 -#define GPIO_ATTRIBUTE_OUTPUT 0x02 -#define GPIO_ATTRIBUTE_ALTERNATE_A 0x04 -#define GPIO_ATTRIBUTE_ALTERNATE_B 0x08 +#define GPIO_PIN_NONE 0xFFFFFFFF +#define GPIO_ATTRIBUTE_NONE 0x00 +#define GPIO_ATTRIBUTE_INPUT 0x01 +#define GPIO_ATTRIBUTE_OUTPUT 0x02 +#define GPIO_ATTRIBUTE_ALTERNATE_A 0x04 +#define GPIO_ATTRIBUTE_ALTERNATE_B 0x08 // from declaration at src\Windows.Devices.Gpio\win_dev_gpio_native.h typedef enum __nfpack GpioPinDriveMode @@ -43,12 +42,12 @@ typedef enum __nfpack GpioPinValue enum GPIO_INT_EDGE { - GPIO_INT_NONE = 0, - GPIO_INT_EDGE_LOW = 1, - GPIO_INT_EDGE_HIGH = 2, - GPIO_INT_EDGE_BOTH = 3, + GPIO_INT_NONE = 0, + GPIO_INT_EDGE_LOW = 1, + GPIO_INT_EDGE_HIGH = 2, + GPIO_INT_EDGE_BOTH = 3, GPIO_INT_LEVEL_HIGH = 4, - GPIO_INT_LEVEL_LOW = 5 + GPIO_INT_LEVEL_LOW = 5 }; // struct GPIO_FLAG_RESISTOR @@ -58,21 +57,19 @@ enum GPIO_INT_EDGE // GPIO_RESISTOR Resistor; // }; +typedef void (*GPIO_INTERRUPT_SERVICE_ROUTINE)(GPIO_PIN pin, bool pinState); -typedef void (*GPIO_INTERRUPT_SERVICE_ROUTINE)( GPIO_PIN Pin, bool PinState, void* Param ); - -bool CPU_GPIO_Initialize (); -bool CPU_GPIO_Uninitialize (); - +bool CPU_GPIO_Initialize(); +bool CPU_GPIO_Uninitialize(); -void CPU_GPIO_DisablePin ( GPIO_PIN Pin, GpioPinDriveMode driveMode, uint32_t alternateFunction); +void CPU_GPIO_DisablePin(GPIO_PIN Pin, GpioPinDriveMode driveMode, uint32_t alternateFunction); // // CPU_GPIO_EnableOutputPin // // Parameters :- // -// Pin +// Pin // The number of the input pin to be enabled. // InitialState // Inial value of pin @@ -82,14 +79,14 @@ void CPU_GPIO_DisablePin ( GPIO_PIN Pin, GpioPinDriveMode driveMode, uint3 // Return Value // true if the specified pin was successfully enabled as output; otherwise, false. // -bool CPU_GPIO_EnableOutputPin( GPIO_PIN Pin, GpioPinValue InitialState, GpioPinDriveMode driveMode ); +bool CPU_GPIO_EnableOutputPin(GPIO_PIN Pin, GpioPinValue InitialState, GpioPinDriveMode driveMode); // // CPU_GPIO_EnableInputPin // // Parameters :- // -// pinNumber +// pinNumber // The number of the input pin to be enabled. // Debounce milisecs // A value you can set to greater than 0 to enable glitch filtering (debouncing) for the number of millissecs @@ -104,32 +101,35 @@ bool CPU_GPIO_EnableOutputPin( GPIO_PIN Pin, GpioPinValue InitialState, GpioPi // Return Value // true if the specified pin was successfully enabled; otherwise, false. // -bool CPU_GPIO_EnableInputPin( GPIO_PIN pinNumber, CLR_UINT64 debounceTimeMilliseconds, GPIO_INTERRUPT_SERVICE_ROUTINE pin_ISR, void* isr_Param, GPIO_INT_EDGE intEdge, GpioPinDriveMode driveMode ); +bool CPU_GPIO_EnableInputPin( + GPIO_PIN pinNumber, + CLR_UINT64 debounceTimeMilliseconds, + GPIO_INTERRUPT_SERVICE_ROUTINE pin_ISR, + void *isr_Param, + GPIO_INT_EDGE intEdge, + GpioPinDriveMode driveMode); // Return current gpio pin state -GpioPinValue CPU_GPIO_GetPinState ( GPIO_PIN Pin ); +GpioPinValue CPU_GPIO_GetPinState(GPIO_PIN Pin); // Set state of output gpio pin -void CPU_GPIO_SetPinState ( GPIO_PIN Pin, GpioPinValue PinState ); +void CPU_GPIO_SetPinState(GPIO_PIN Pin, GpioPinValue PinState); // Check if pin is already reserved // Returns true if pin is already reserved -bool CPU_GPIO_PinIsBusy ( GPIO_PIN Pin ); +bool CPU_GPIO_PinIsBusy(GPIO_PIN Pin); // Reserved or Unreserve gpio pin // if clearing reserve always return true -// If reserving pin then return false if already reserved -bool CPU_GPIO_ReservePin ( GPIO_PIN Pin, bool fReserve ); - +// If reserving pin then return false if already reserved +bool CPU_GPIO_ReservePin(GPIO_PIN Pin, bool fReserve); // Return count of gpio pins avaiable -int32_t CPU_GPIO_GetPinCount (); - +int32_t CPU_GPIO_GetPinCount(); // Get / Set the pin debounce time in millisecs uint32_t CPU_GPIO_GetPinDebounce(GPIO_PIN Pin); -bool CPU_GPIO_SetPinDebounce(GPIO_PIN pinNumber, CLR_UINT64 debounceTimeMilliseconds); - +bool CPU_GPIO_SetPinDebounce(GPIO_PIN pinNumber, CLR_UINT64 debounceTimeMilliseconds); // Validate pin and set drive mode // return true if pin ok @@ -139,20 +139,17 @@ bool CPU_GPIO_SetDriveMode(GPIO_PIN pinNumber, GpioPinDriveMode driveMode); // return true if drive mode supported bool CPU_GPIO_DriveModeSupported(GPIO_PIN pinNumber, GpioPinDriveMode driveMode); - // ==== Not implemented/used ==== -// Retrieves an array containing the attributes of all the GPIO pins. +// Retrieves an array containing the attributes of all the GPIO pins. // void CPU_GPIO_GetPinsMap(uint8_t* pins, size_t size); -// Retrieves the resistor modes supported by a designated GPIO pin. -//uint8_t CPU_GPIO_GetSupportedResistorModes(GPIO_PIN pin); +// Retrieves the resistor modes supported by a designated GPIO pin. +// uint8_t CPU_GPIO_GetSupportedResistorModes(GPIO_PIN pin); -// Retrieves the interrupt edge modes supported by a designated GPIO pin. -//uint8_t CPU_GPIO_GetSupportedInterruptModes(GPIO_PIN pin); - -//Retrieves the GPIO attributes of a specified pin. ( none=0, input=1, output=2, altA=4, altB=8 etc ) -//uint32_t CPU_GPIO_Attributes(GPIO_PIN Pin); +// Retrieves the interrupt edge modes supported by a designated GPIO pin. +// uint8_t CPU_GPIO_GetSupportedInterruptModes(GPIO_PIN pin); +// Retrieves the GPIO attributes of a specified pin. ( none=0, input=1, output=2, altA=4, altB=8 etc ) +// uint32_t CPU_GPIO_Attributes(GPIO_PIN Pin); #endif // _DRIVERS_GPIO_DECL_H_ - diff --git a/src/Windows.Devices.Gpio/win_dev_gpio_native_Windows_Devices_Gpio_GpioPin.cpp b/src/Windows.Devices.Gpio/win_dev_gpio_native_Windows_Devices_Gpio_GpioPin.cpp index b2e5c8e167..7008680553 100644 --- a/src/Windows.Devices.Gpio/win_dev_gpio_native_Windows_Devices_Gpio_GpioPin.cpp +++ b/src/Windows.Devices.Gpio/win_dev_gpio_native_Windows_Devices_Gpio_GpioPin.cpp @@ -12,247 +12,266 @@ /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// -void Gpio_Interupt_ISR(GPIO_PIN pinNumber, bool pinState, void* param ) +void Gpio_Interupt_ISR(GPIO_PIN pinNumber, bool pinState) { - NATIVE_INTERRUPT_START - - CLR_RT_HeapBlock *pThis = (CLR_RT_HeapBlock *)param; - if (pThis != NULL) - { - // check if object has been disposed - if (pThis[Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::FIELD___disposedValue].NumericByRef().u1 == 0) - { - // flag to determine if there are any callbacks registered in managed code - bool callbacksRegistered = (pThis[Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::FIELD___callbacks].Dereference() != NULL); - if (callbacksRegistered) - { - // if handle registered then post a managed event with the current pin reading - PostManagedEvent(EVENT_GPIO, 0, (uint16_t)pinNumber, (uint32_t)pinState); - } - } - } - - NATIVE_INTERRUPT_END + // if handle registered then post a managed event with the current pin reading + PostManagedEvent(EVENT_GPIO, 0, (uint16_t)pinNumber, (uint32_t)pinState); } -HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::Read___WindowsDevicesGpioGpioPinValue( CLR_RT_StackFrame& stack ) +HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::Read___WindowsDevicesGpioGpioPinValue( + CLR_RT_StackFrame &stack) { - NANOCLR_HEADER(); - { - CLR_RT_HeapBlock* pThis = stack.This(); FAULT_ON_NULL(pThis); + NANOCLR_HEADER(); + { + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); - if(pThis[ Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::FIELD___disposedValue ].NumericByRef().u1 != 0) - { - NANOCLR_SET_AND_LEAVE(CLR_E_OBJECT_DISPOSED); - } + if (pThis[Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::FIELD___disposedValue].NumericByRef().u1 != + 0) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OBJECT_DISPOSED); + } - GPIO_PIN pinNumber = (GPIO_PIN)pThis[ FIELD___pinNumber ].NumericByRefConst().s4; + GPIO_PIN pinNumber = (GPIO_PIN)pThis[FIELD___pinNumber].NumericByRefConst().s4; - stack.SetResult_I4( CPU_GPIO_GetPinState(pinNumber) ); - } - NANOCLR_NOCLEANUP(); + stack.SetResult_I4(CPU_GPIO_GetPinState(pinNumber)); + } + NANOCLR_NOCLEANUP(); } -HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::Toggle___VOID( CLR_RT_StackFrame& stack ) +HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::Toggle___VOID(CLR_RT_StackFrame &stack) { - NANOCLR_HEADER(); - { - CLR_RT_HeapBlock* pThis = stack.This(); FAULT_ON_NULL(pThis); - - // check if object has been disposed - if(pThis[ Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::FIELD___disposedValue ].NumericByRef().u1 != 0) - { - NANOCLR_SET_AND_LEAVE(CLR_E_OBJECT_DISPOSED); - } - - GPIO_PIN pinNumber = (GPIO_PIN)pThis[ FIELD___pinNumber ].NumericByRefConst().s4; - GpioPinDriveMode driveMode = (GpioPinDriveMode)pThis[ FIELD___driveMode ].NumericByRefConst().s4; - - // sanity check for drive mode set to output so we don't mess up writing to an input pin - if (driveMode >= GpioPinDriveMode_Output) - { - // Not all lower level API offer a 'toggle', so need to rely on the last output value field and toggle that one - GpioPinValue newState = (GpioPinValue)(GpioPinValue_High ^ (GpioPinValue)pThis[ FIELD___lastOutputValue ].NumericByRef().s4); - - // ...write back to the GPIO... - CPU_GPIO_SetPinState(pinNumber, newState ); - - // ... and finally store it - pThis[ FIELD___lastOutputValue ].NumericByRef().s4 = newState; - } - } - NANOCLR_NOCLEANUP(); + NANOCLR_HEADER(); + { + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + // check if object has been disposed + if (pThis[Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::FIELD___disposedValue].NumericByRef().u1 != + 0) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OBJECT_DISPOSED); + } + + GPIO_PIN pinNumber = (GPIO_PIN)pThis[FIELD___pinNumber].NumericByRefConst().s4; + GpioPinDriveMode driveMode = (GpioPinDriveMode)pThis[FIELD___driveMode].NumericByRefConst().s4; + + // sanity check for drive mode set to output so we don't mess up writing to an input pin + if (driveMode >= GpioPinDriveMode_Output) + { + // Not all lower level API offer a 'toggle', so need to rely on the last output value field and toggle that + // one + GpioPinValue newState = + (GpioPinValue)(GpioPinValue_High ^ (GpioPinValue)pThis[FIELD___lastOutputValue].NumericByRef().s4); + + // ...write back to the GPIO... + CPU_GPIO_SetPinState(pinNumber, newState); + + // ... and finally store it + pThis[FIELD___lastOutputValue].NumericByRef().s4 = newState; + } + } + NANOCLR_NOCLEANUP(); } -HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::DisposeNative___VOID( CLR_RT_StackFrame& stack ) +HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::DisposeNative___VOID(CLR_RT_StackFrame &stack) { - NANOCLR_HEADER(); - { - CLR_RT_HeapBlock* pThis = stack.This(); FAULT_ON_NULL(pThis); - - // set pin to input to save power - // clear interrupts - // releases the pin - GPIO_PIN pinNumber = (GPIO_PIN)pThis[ FIELD___pinNumber ].NumericByRefConst().s4; - - CPU_GPIO_DisablePin(pinNumber, GpioPinDriveMode_Input, 0) ; - } - NANOCLR_NOCLEANUP(); + NANOCLR_HEADER(); + { + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + // set pin to input to save power + // clear interrupts + // releases the pin + GPIO_PIN pinNumber = (GPIO_PIN)pThis[FIELD___pinNumber].NumericByRefConst().s4; + + CPU_GPIO_DisablePin(pinNumber, GpioPinDriveMode_Input, 0); + } + NANOCLR_NOCLEANUP(); } -HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::NativeIsDriveModeSupported___BOOLEAN__WindowsDevicesGpioGpioPinDriveMode( CLR_RT_StackFrame& stack ) +HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin:: + NativeIsDriveModeSupported___BOOLEAN__WindowsDevicesGpioGpioPinDriveMode(CLR_RT_StackFrame &stack) { - NANOCLR_HEADER(); - { - CLR_RT_HeapBlock* pThis = stack.This(); FAULT_ON_NULL(pThis); + NANOCLR_HEADER(); + { + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); - GPIO_PIN pinNumber = (GPIO_PIN)pThis[ FIELD___pinNumber ].NumericByRefConst().s4; + GPIO_PIN pinNumber = (GPIO_PIN)pThis[FIELD___pinNumber].NumericByRefConst().s4; - GpioPinDriveMode driveMode = (GpioPinDriveMode)stack.Arg1().NumericByRef().s4; + GpioPinDriveMode driveMode = (GpioPinDriveMode)stack.Arg1().NumericByRef().s4; - // Return value to the managed application - stack.SetResult_Boolean(CPU_GPIO_DriveModeSupported(pinNumber, driveMode)) ; - } - NANOCLR_NOCLEANUP(); + // Return value to the managed application + stack.SetResult_Boolean(CPU_GPIO_DriveModeSupported(pinNumber, driveMode)); + } + NANOCLR_NOCLEANUP(); } -HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::NativeSetDriveMode___VOID__WindowsDevicesGpioGpioPinDriveMode( CLR_RT_StackFrame& stack ) +HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin:: + NativeSetDriveMode___VOID__WindowsDevicesGpioGpioPinDriveMode(CLR_RT_StackFrame &stack) { - NANOCLR_HEADER(); - { - bool validPin; - CLR_UINT64 debounceTimeoutMilsec; - - CLR_RT_HeapBlock* pThis = stack.This(); FAULT_ON_NULL(pThis); - - if(pThis[ Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::FIELD___disposedValue ].NumericByRef().u1 != 0) - { - NANOCLR_SET_AND_LEAVE(CLR_E_OBJECT_DISPOSED); - } - - GPIO_PIN pinNumber = (GPIO_PIN)pThis[ FIELD___pinNumber ].NumericByRefConst().s4; - GpioPinDriveMode driveMode = (GpioPinDriveMode)stack.Arg1().NumericByRef().s4; - - if (driveMode >= (int)GpioPinDriveMode_Output) - { - validPin = CPU_GPIO_EnableOutputPin(pinNumber, GpioPinValue_Low, driveMode); - } - else - { - NANOCLR_CHECK_HRESULT( ExtractDebounceTimeSpanValue(pThis[ FIELD___debounceTimeout ], debounceTimeoutMilsec ) ); - - validPin = CPU_GPIO_EnableInputPin(pinNumber, debounceTimeoutMilsec, Gpio_Interupt_ISR, (void*)pThis, GPIO_INT_EDGE_BOTH, driveMode); - } - - if (!validPin) - { - NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); - } - - // protect this from GC so that the callback is where it's supposed to - CLR_RT_ProtectFromGC gc( *pThis ); - - - } - NANOCLR_NOCLEANUP(); + NANOCLR_HEADER(); + { + bool validPin; + CLR_UINT64 debounceTimeoutMilsec; + bool callbacksRegistered = false; + + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + if (pThis[Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::FIELD___disposedValue].NumericByRef().u1 != + 0) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OBJECT_DISPOSED); + } + + GPIO_PIN pinNumber = (GPIO_PIN)pThis[FIELD___pinNumber].NumericByRefConst().s4; + GpioPinDriveMode driveMode = (GpioPinDriveMode)stack.Arg1().NumericByRef().s4; + + if (driveMode >= (int)GpioPinDriveMode_Output) + { + validPin = CPU_GPIO_EnableOutputPin(pinNumber, GpioPinValue_Low, driveMode); + } + else + { + NANOCLR_CHECK_HRESULT(ExtractDebounceTimeSpanValue(pThis[FIELD___debounceTimeout], debounceTimeoutMilsec)); + + // flag to determine if there are any callbacks registered in managed code + // this is use to determine if there is any need to setup and process INT handler + callbacksRegistered = + (pThis[Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::FIELD___callbacks].Dereference() != + NULL); + + validPin = CPU_GPIO_EnableInputPin( + pinNumber, + debounceTimeoutMilsec, + callbacksRegistered ? Gpio_Interupt_ISR : NULL, + NULL, + GPIO_INT_EDGE_BOTH, + driveMode); + } + + if (!validPin) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } + + // protect this from GC so that the callback is where it's supposed to + CLR_RT_ProtectFromGC gc(*pThis); + } + NANOCLR_NOCLEANUP(); } -HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::NativeInit___BOOLEAN__I4( CLR_RT_StackFrame& stack ) +HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::NativeInit___BOOLEAN__I4(CLR_RT_StackFrame &stack) { - NANOCLR_HEADER(); - { - GPIO_PIN pinNumber = (GPIO_PIN)stack.Arg1().NumericByRef().s4; - - // Return value to the managed application - stack.SetResult_Boolean(CPU_GPIO_ReservePin(pinNumber, true)); - } - NANOCLR_NOCLEANUP_NOLABEL(); + NANOCLR_HEADER(); + { + GPIO_PIN pinNumber = (GPIO_PIN)stack.Arg1().NumericByRef().s4; + + // Return value to the managed application + stack.SetResult_Boolean(CPU_GPIO_ReservePin(pinNumber, true)); + } + NANOCLR_NOCLEANUP_NOLABEL(); } -HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::NativeSetDebounceTimeout___VOID( CLR_RT_StackFrame& stack ) +HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::NativeSetDebounceTimeout___VOID( + CLR_RT_StackFrame &stack) { - NANOCLR_HEADER(); - { - CLR_UINT64 debounceTimeoutMilsec; + NANOCLR_HEADER(); + { + CLR_UINT64 debounceTimeoutMilsec; - CLR_RT_HeapBlock* pThis = stack.This(); FAULT_ON_NULL(pThis); + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); - GPIO_PIN pinNumber = (GPIO_PIN)pThis[ FIELD___pinNumber ].NumericByRefConst().s4; + GPIO_PIN pinNumber = (GPIO_PIN)pThis[FIELD___pinNumber].NumericByRefConst().s4; - NANOCLR_CHECK_HRESULT( ExtractDebounceTimeSpanValue(pThis[ FIELD___debounceTimeout ], debounceTimeoutMilsec ) ); + NANOCLR_CHECK_HRESULT(ExtractDebounceTimeSpanValue(pThis[FIELD___debounceTimeout], debounceTimeoutMilsec)); - // developer note: - // the following call will FAIL if the pin hasn't been previously setup as input - // that's OK because the debounce timeout will be eventually set when the pin is configured - CPU_GPIO_SetPinDebounce( pinNumber, debounceTimeoutMilsec ); - } - NANOCLR_NOCLEANUP(); + // developer note: + // the following call will FAIL if the pin hasn't been previously setup as input + // that's OK because the debounce timeout will be eventually set when the pin is configured + CPU_GPIO_SetPinDebounce(pinNumber, debounceTimeoutMilsec); + } + NANOCLR_NOCLEANUP(); } -HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::WriteNative___VOID__WindowsDevicesGpioGpioPinValue( CLR_RT_StackFrame& stack ) +HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::WriteNative___VOID__WindowsDevicesGpioGpioPinValue( + CLR_RT_StackFrame &stack) { - NANOCLR_HEADER(); - { - CLR_RT_HeapBlock* pThis = stack.This(); FAULT_ON_NULL(pThis); - - // check if object has been disposed - if(pThis[ Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::FIELD___disposedValue ].NumericByRef().u1 != 0) - { - NANOCLR_SET_AND_LEAVE(CLR_E_OBJECT_DISPOSED); - } - - GPIO_PIN pinNumber = (GPIO_PIN)pThis[ FIELD___pinNumber ].NumericByRefConst().s4; - GpioPinDriveMode driveMode = (GpioPinDriveMode)pThis[ FIELD___driveMode ].NumericByRefConst().s4; - - GpioPinValue state = (GpioPinValue)stack.Arg1().NumericByRef().s4; - - // sanity check for drive mode set to output so we don't mess up writing to an input pin - if ((driveMode >= GpioPinDriveMode_Output) ) - { - CPU_GPIO_SetPinState(pinNumber, state ); - - // store the output value in the field - pThis[ FIELD___lastOutputValue ].NumericByRef().s4 = state; - } - else - { - NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); - } - } - NANOCLR_NOCLEANUP(); + NANOCLR_HEADER(); + { + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + // check if object has been disposed + if (pThis[Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::FIELD___disposedValue].NumericByRef().u1 != + 0) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OBJECT_DISPOSED); + } + + GPIO_PIN pinNumber = (GPIO_PIN)pThis[FIELD___pinNumber].NumericByRefConst().s4; + GpioPinDriveMode driveMode = (GpioPinDriveMode)pThis[FIELD___driveMode].NumericByRefConst().s4; + + GpioPinValue state = (GpioPinValue)stack.Arg1().NumericByRef().s4; + + // sanity check for drive mode set to output so we don't mess up writing to an input pin + if ((driveMode >= GpioPinDriveMode_Output)) + { + CPU_GPIO_SetPinState(pinNumber, state); + + // store the output value in the field + pThis[FIELD___lastOutputValue].NumericByRef().s4 = state; + } + else + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } + } + NANOCLR_NOCLEANUP(); } -HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::NativeSetAlternateFunction___VOID__I4( CLR_RT_StackFrame& stack ) +HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::NativeSetAlternateFunction___VOID__I4( + CLR_RT_StackFrame &stack) { - NANOCLR_HEADER(); - { - CLR_RT_HeapBlock* pThis = stack.This(); FAULT_ON_NULL(pThis); - - // check if object has been disposed - if(pThis[ Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::FIELD___disposedValue ].NumericByRef().u1 != 0) - { - NANOCLR_SET_AND_LEAVE(CLR_E_OBJECT_DISPOSED); - } - - // get pin number and take the port and pad references from that one - int16_t pinNumber = pThis[ FIELD___pinNumber ].NumericByRefConst().s4; - - // get alternate function argument - int32_t alternateFunction = stack.Arg1().NumericByRef().s4; - - CPU_GPIO_DisablePin( pinNumber, GpioPinDriveMode_Input, alternateFunction); - } - NANOCLR_NOCLEANUP(); + NANOCLR_HEADER(); + { + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + // check if object has been disposed + if (pThis[Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::FIELD___disposedValue].NumericByRef().u1 != + 0) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OBJECT_DISPOSED); + } + + // get pin number and take the port and pad references from that one + int16_t pinNumber = pThis[FIELD___pinNumber].NumericByRefConst().s4; + + // get alternate function argument + int32_t alternateFunction = stack.Arg1().NumericByRef().s4; + + CPU_GPIO_DisablePin(pinNumber, GpioPinDriveMode_Input, alternateFunction); + } + NANOCLR_NOCLEANUP(); } -HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::ExtractDebounceTimeSpanValue( CLR_RT_HeapBlock& timeSpanValue, CLR_UINT64& value ) +HRESULT Library_win_dev_gpio_native_Windows_Devices_Gpio_GpioPin::ExtractDebounceTimeSpanValue( + CLR_RT_HeapBlock &timeSpanValue, + CLR_UINT64 &value) { NANOCLR_HEADER(); - { - // debounceTimeout field its a TimeSpan, which is a primitive type stored as an heap block, therefore needs to be accessed indirectly - CLR_INT64* debounceValue = Library_corlib_native_System_TimeSpan::GetValuePtr( timeSpanValue ); FAULT_ON_NULL(debounceValue); - - value = *(CLR_UINT64*)debounceValue / TIME_CONVERSION__TO_MILLISECONDS; - } - NANOCLR_NOCLEANUP(); + { + // debounceTimeout field its a TimeSpan, which is a primitive type stored as an heap block, therefore needs to + // be accessed indirectly + CLR_INT64 *debounceValue = Library_corlib_native_System_TimeSpan::GetValuePtr(timeSpanValue); + FAULT_ON_NULL(debounceValue); + + value = *(CLR_UINT64 *)debounceValue / TIME_CONVERSION__TO_MILLISECONDS; + } + NANOCLR_NOCLEANUP(); } diff --git a/targets/CMSIS-OS/ChibiOS/nanoCLR/Windows.Devices.Gpio/cpu_gpio.cpp b/targets/CMSIS-OS/ChibiOS/nanoCLR/Windows.Devices.Gpio/cpu_gpio.cpp index 1236fcfa6e..76e44b1ee0 100644 --- a/targets/CMSIS-OS/ChibiOS/nanoCLR/Windows.Devices.Gpio/cpu_gpio.cpp +++ b/targets/CMSIS-OS/ChibiOS/nanoCLR/Windows.Devices.Gpio/cpu_gpio.cpp @@ -10,305 +10,319 @@ #include #include "win_dev_gpio_native_target.h" - -//volatile uint16_t lastPadValue; - - -#define GPIO_MAX_PIN 256 -#define TOTAL_GPIO_PORTS ((GPIO_MAX_PIN + 15) / 16) +#define GPIO_MAX_PIN 256 +#define TOTAL_GPIO_PORTS ((GPIO_MAX_PIN + 15) / 16) // Double linkedlist to hold the state of each Input pin struct gpio_input_state : public HAL_DblLinkedNode { - GPIO_PIN pinNumber; // Pin number - virtual_timer_t debounceTimer; // debounce timer for this Pin - GPIO_INTERRUPT_SERVICE_ROUTINE isrPtr; // Ptr to user ISR or null - uint32_t debounceMs; // debounce Millsecs, no debonce=0 - uint8_t mode; // Interrupt mode - void * param; // Param to user isr call - bool expected; // Expected state for debounce handler - bool waitingDebounce; // True if waiting for debounce timer to complete + GPIO_PIN pinNumber; // Pin number + virtual_timer_t debounceTimer; // debounce timer for this Pin + GPIO_INTERRUPT_SERVICE_ROUTINE isrPtr; // Ptr to user ISR or null + uint32_t debounceMs; // debounce Millsecs, no debonce=0 + uint8_t mode; // Interrupt mode + void *param; // Param to user isr call + bool expected; // Expected state for debounce handler + bool waitingDebounce; // True if waiting for debounce timer to complete }; -static HAL_DblLinkedList gpioInputList; // Double Linked list for GPIO input status -static uint16_t pinReserved[TOTAL_GPIO_PORTS]; // reserved - 1 bit per pin - +static HAL_DblLinkedList gpioInputList; // Double Linked list for GPIO input status +static uint16_t pinReserved[TOTAL_GPIO_PORTS]; // reserved - 1 bit per pin // this is an utility function to get a ChibiOS PAL IoLine from our "encoded" pin number static ioline_t GetIoLine(int16_t pinNumber) { - stm32_gpio_t* port = GPIO_PORT(pinNumber); - int16_t pad = pinNumber % 16; - - return PAL_LINE(port, pad); + stm32_gpio_t *port = GPIO_PORT(pinNumber); + int16_t pad = pinNumber % 16; + return PAL_LINE(port, pad); } -bool IsValidGpioPin(GPIO_PIN pinNumber) +bool IsValidGpioPin(GPIO_PIN pinNumber) { - return (pinNumber <= GPIO_MAX_PIN); + return (pinNumber <= GPIO_MAX_PIN); } -static void debounceTimer_Callback(void* arg) +static void DebounceTimerCallback(void *arg) { - gpio_input_state* pState = (gpio_input_state*)arg; - if (pState->isrPtr) - { - // get current pin state - bool actual = palReadLine(GetIoLine(pState->pinNumber)); - if (actual == pState->expected) - { - pState->isrPtr(pState->pinNumber, actual, pState->param); - if (pState->mode == GPIO_INT_EDGE_BOTH) - { - // both edges - pState->expected ^= 1; // update expected state - } - } - } - - pState->waitingDebounce = false; + gpio_input_state *pState = (gpio_input_state *)arg; + + // get current pin state + bool actual = palReadLine(GetIoLine(pState->pinNumber)); + if (actual == pState->expected) + { + pState->isrPtr(pState->pinNumber, actual); + if (pState->mode == GPIO_INT_EDGE_BOTH) + { + // both edges + pState->expected ^= 1; // update expected state + } + } + + pState->waitingDebounce = false; } - static void GpioEventCallback(void *arg) { - NATIVE_INTERRUPT_START + NATIVE_INTERRUPT_START - chSysLockFromISR(); + chSysLockFromISR(); - gpio_input_state * pGpio = (gpio_input_state *)arg; + gpio_input_state *pGpio = (gpio_input_state *)arg; - // Ignore any pin changes during debounce - if (pGpio->waitingDebounce) - { - chSysUnlockFromISR(); - return; - } + // Ignore any pin changes during debounce + if (pGpio->waitingDebounce) + { + chSysUnlockFromISR(); + return; + } - // check if there is a debounce time set - if (pGpio->debounceMs > 0) - { - // Set flag we are waiting for debounce on this pin - pGpio->waitingDebounce = true; + // check if there is a debounce time set + if (pGpio->debounceMs > 0) + { + // Set flag we are waiting for debounce on this pin + pGpio->waitingDebounce = true; - // setup timer - chVTSetI(&pGpio->debounceTimer, TIME_MS2I(pGpio->debounceMs), debounceTimer_Callback, pGpio); - } - else - { - // get IoLine from pin number - ioline_t ioLine = GetIoLine(pGpio->pinNumber); + // setup timer + chVTSetI(&pGpio->debounceTimer, TIME_MS2I(pGpio->debounceMs), DebounceTimerCallback, pGpio); + } + else + { + // get IoLine from pin number + ioline_t ioLine = GetIoLine(pGpio->pinNumber); - chSysUnlockFromISR(); - pGpio->isrPtr(pGpio->pinNumber, palReadLine(ioLine), pGpio->param); - chSysLockFromISR(); - } + chSysUnlockFromISR(); + pGpio->isrPtr(pGpio->pinNumber, palReadLine(ioLine)); + chSysLockFromISR(); + } - chSysUnlockFromISR(); + chSysUnlockFromISR(); - NATIVE_INTERRUPT_END + NATIVE_INTERRUPT_END } - - // Get pointer to gpio_input_state for Gpio pin // return NULL if not found -gpio_input_state * GetInputState(GPIO_PIN pinNumber) +gpio_input_state *GetInputState(GPIO_PIN pinNumber) { - gpio_input_state * ptr = gpioInputList.FirstNode(); - while (ptr->Next() != NULL) - { - if (ptr->pinNumber == pinNumber) return ptr; - ptr = ptr->Next(); - } - return NULL; + gpio_input_state *ptr = gpioInputList.FirstNode(); + while (ptr->Next() != NULL) + { + if (ptr->pinNumber == pinNumber) + return ptr; + ptr = ptr->Next(); + } + return NULL; } // Allocate a new gpio_input_state and add to end of list // if already exist then just return current ptr -gpio_input_state * AllocateGpioInputState(GPIO_PIN pinNumber) +gpio_input_state *AllocateGpioInputState(GPIO_PIN pinNumber) { - gpio_input_state * ptr = GetInputState(pinNumber); - - if (ptr == NULL) - { - ptr = (gpio_input_state *)platform_malloc(sizeof(gpio_input_state)); + gpio_input_state *ptr = GetInputState(pinNumber); - // sanity check - if(ptr != NULL) - { - memset(ptr, 0, sizeof(gpio_input_state)); - ptr->pinNumber = pinNumber; + if (ptr == NULL) + { + ptr = (gpio_input_state *)platform_malloc(sizeof(gpio_input_state)); - chVTObjectInit(&ptr->debounceTimer); + // sanity check + if (ptr != NULL) + { + memset(ptr, 0, sizeof(gpio_input_state)); + ptr->pinNumber = pinNumber; - gpioInputList.LinkAtBack(ptr); - } - } + chVTObjectInit(&ptr->debounceTimer); - return ptr; + gpioInputList.LinkAtBack(ptr); + } + } + + return ptr; } -void UnlinkInputState(gpio_input_state * pState) +void UnlinkInputState(gpio_input_state *pState) { - chVTReset(&pState->debounceTimer); + chVTReset(&pState->debounceTimer); - // disable the EXT interrupt channel - // it's OK to do always this, no matter if it's enabled or not - palDisableLineEvent(GetIoLine(pState->pinNumber)); + // disable the EXT interrupt channel + // it's OK to do always this, no matter if it's enabled or not + palDisableLineEvent(GetIoLine(pState->pinNumber)); - pState->Unlink(); - platform_free(pState); + pState->Unlink(); + platform_free(pState); } // Delete gpio_input_state from List and tidy up ( Timer & ISR handler ) void DeleteInputState(GPIO_PIN pinNumber) { - gpio_input_state * pState = GetInputState(pinNumber); - if (pState) - { - UnlinkInputState(pState); - } + gpio_input_state *pState = GetInputState(pinNumber); + if (pState) + { + UnlinkInputState(pState); + } } -bool CPU_GPIO_Initialize() +bool CPU_GPIO_Initialize() { - // Initialise Double linked list for input pin states - gpioInputList.Initialize(); + // Initialise Double linked list for input pin states + gpioInputList.Initialize(); - // Make sure all pins are not reserved - memset(pinReserved, 0, sizeof(pinReserved)); + // Make sure all pins are not reserved + memset(pinReserved, 0, sizeof(pinReserved)); - return true; + return true; } -bool CPU_GPIO_Uninitialize() +bool CPU_GPIO_Uninitialize() { - NANOCLR_FOREACH_NODE(gpio_input_state, pGpio, gpioInputList) - { - UnlinkInputState(pGpio); - } - NANOCLR_FOREACH_NODE_END(); + NANOCLR_FOREACH_NODE(gpio_input_state, pGpio, gpioInputList) + { + UnlinkInputState(pGpio); + } + NANOCLR_FOREACH_NODE_END(); - return true; + return true; } // Set/reset reserved state of pin -bool CPU_GPIO_ReservePin(GPIO_PIN pinNumber, bool fReserve) +bool CPU_GPIO_ReservePin(GPIO_PIN pinNumber, bool fReserve) { - // Check if valid pin number - if (!IsValidGpioPin(pinNumber)) return false; - - int port = pinNumber >> 4, bit = 1 << (pinNumber & 0x0F); - bool ret = true; - GLOBAL_LOCK(); - - if (fReserve) - { - if (pinReserved[port] & bit) - { - ret = false; // already reserved - } - else - { - pinReserved[port] |= bit; - } - } - else - { - pinReserved[port] &= ~bit; - } - - GLOBAL_UNLOCK(); - return ret; + // Check if valid pin number + if (!IsValidGpioPin(pinNumber)) + return false; + + int port = pinNumber >> 4, bit = 1 << (pinNumber & 0x0F); + bool ret = true; + GLOBAL_LOCK(); + + if (fReserve) + { + if (pinReserved[port] & bit) + { + ret = false; // already reserved + } + else + { + pinReserved[port] |= bit; + } + } + else + { + pinReserved[port] &= ~bit; + } + + GLOBAL_UNLOCK(); + return ret; } // Return if Pin is reserved bool CPU_GPIO_PinIsBusy(GPIO_PIN pinNumber) { - // Check if valid pin number - if (!IsValidGpioPin(pinNumber)) return false; + // Check if valid pin number + if (!IsValidGpioPin(pinNumber)) + return false; - int port = pinNumber >> 4, sh = pinNumber & 0x0F; - return (pinReserved[port] >> sh) & 1; + int port = pinNumber >> 4, sh = pinNumber & 0x0F; + return (pinReserved[port] >> sh) & 1; } // Return maximum number of pins int32_t CPU_GPIO_GetPinCount() { - return GPIO_MAX_PIN; + return GPIO_MAX_PIN; } // Get current state of pin GpioPinValue CPU_GPIO_GetPinState(GPIO_PIN pin) { - return (GpioPinValue)palReadLine(GetIoLine(pin)); + return (GpioPinValue)palReadLine(GetIoLine(pin)); } // Set Pin state void CPU_GPIO_SetPinState(GPIO_PIN pin, GpioPinValue PinState) { - palWriteLine(GetIoLine(pin), (int)PinState); + palWriteLine(GetIoLine(pin), (int)PinState); } -bool CPU_GPIO_EnableInputPin(GPIO_PIN pinNumber, CLR_UINT64 debounceTimeMilliseconds, GPIO_INTERRUPT_SERVICE_ROUTINE pin_ISR, void* isr_Param, GPIO_INT_EDGE intEdge, GpioPinDriveMode driveMode) +bool CPU_GPIO_EnableInputPin( + GPIO_PIN pinNumber, + CLR_UINT64 debounceTimeMilliseconds, + GPIO_INTERRUPT_SERVICE_ROUTINE pinISR, + void *isrParam, + GPIO_INT_EDGE intEdge, + GpioPinDriveMode driveMode) { - gpio_input_state * pState; - - // Check Input drive mode - if (driveMode >= (int)GpioPinDriveMode_Output) - { - return false; - } - - // Set as Input GPIO_INT_EDGE intEdge, GPIO_RESISTOR ResistorState - if (!CPU_GPIO_SetDriveMode(pinNumber, driveMode)) - { - return false; - } - pState = AllocateGpioInputState(pinNumber); - - // Link ISR ptr supplied and not already set up - // CPU_GPIO_EnableInputPin could be called a 2nd time with changed parameters - if ((pin_ISR != NULL) && (pState->isrPtr == NULL)) - { - // there are callbacks registered and... - // the drive mode is input so need to setup the interrupt - - // get IoLine from pin number - ioline_t ioLine = GetIoLine(pinNumber); - - palEnableLineEvent(ioLine, PAL_EVENT_MODE_BOTH_EDGES); - palSetLineCallback(ioLine, GpioEventCallback, pState); - } - - pState->isrPtr = pin_ISR; - pState->mode = intEdge; - pState->param = (void *)isr_Param; - pState->debounceMs = (uint32_t)(debounceTimeMilliseconds); - - switch (intEdge) - { - case GPIO_INT_EDGE_LOW: - case GPIO_INT_LEVEL_LOW: - pState->expected = PAL_LOW; - break; - - case GPIO_INT_EDGE_HIGH: - case GPIO_INT_LEVEL_HIGH: - pState->expected = PAL_HIGH; - break; - - case GPIO_INT_EDGE_BOTH: - pState->expected = !CPU_GPIO_GetPinState(pinNumber); // expected NOT current state - break; - - default: - break; - } - - return true; + gpio_input_state *pState; + + // Check Input drive mode + if (driveMode >= (int)GpioPinDriveMode_Output) + { + return false; + } + + // Set as Input GPIO_INT_EDGE intEdge, GPIO_RESISTOR ResistorState + if (!CPU_GPIO_SetDriveMode(pinNumber, driveMode)) + { + return false; + } + + pState = AllocateGpioInputState(pinNumber); + + // Link ISR ptr supplied and not already set up + // CPU_GPIO_EnableInputPin could be called a 2nd time with changed parameters + if (pinISR != NULL && (pState->isrPtr == NULL)) + { + // there are callbacks registered and... + // the drive mode is input so need to setup the interrupt + + // get IoLine from pin number + ioline_t ioLine = GetIoLine(pinNumber); + + palEnableLineEvent(ioLine, PAL_EVENT_MODE_BOTH_EDGES); + palSetLineCallback(ioLine, GpioEventCallback, pState); + + // store parameters & configs + pState->isrPtr = pinISR; + pState->mode = intEdge; + pState->param = (void *)isrParam; + pState->debounceMs = (uint32_t)(debounceTimeMilliseconds); + + switch (intEdge) + { + case GPIO_INT_EDGE_LOW: + case GPIO_INT_LEVEL_LOW: + pState->expected = PAL_LOW; + break; + + case GPIO_INT_EDGE_HIGH: + case GPIO_INT_LEVEL_HIGH: + pState->expected = PAL_HIGH; + break; + + case GPIO_INT_EDGE_BOTH: + pState->expected = !CPU_GPIO_GetPinState(pinNumber); // expected NOT current state + break; + + default: + break; + } + } + else if (pinISR == NULL && (pState->isrPtr != NULL)) + { + // there is no managed handler setup anymore + + // disable the EXT interrupt channel + // it's OK to do always this, no matter if it's enabled or not + palDisableLineEvent(GetIoLine(pState->pinNumber)); + + // clear parameters & configs + pState->isrPtr = NULL; + pState->mode = GPIO_INT_NONE; + pState->param = NULL; + pState->debounceMs = 0; + } + + return true; } // Enable an output pin @@ -318,113 +332,112 @@ bool CPU_GPIO_EnableInputPin(GPIO_PIN pinNumber, CLR_UINT64 debounceTimeMillisec // driveMode - Drive mode and resistors // return - True if succesful, false invalid pin, pin not putput, invalid drive mode for ouptput // -bool CPU_GPIO_EnableOutputPin(GPIO_PIN pinNumber, GpioPinValue InitialState, GpioPinDriveMode driveMode) +bool CPU_GPIO_EnableOutputPin(GPIO_PIN pinNumber, GpioPinValue InitialState, GpioPinDriveMode driveMode) { - // check not an output drive mode - if (driveMode < (int)GpioPinDriveMode_Output) return false; + // check not an output drive mode + if (driveMode < (int)GpioPinDriveMode_Output) + return false; - // If this is currently an input pin then clean up - DeleteInputState(pinNumber); + // If this is currently an input pin then clean up + DeleteInputState(pinNumber); - if (CPU_GPIO_SetDriveMode(pinNumber, driveMode) == false) return false; + if (CPU_GPIO_SetDriveMode(pinNumber, driveMode) == false) + return false; - CPU_GPIO_SetPinState(pinNumber, InitialState); + CPU_GPIO_SetPinState(pinNumber, InitialState); - return true; + return true; } - void CPU_GPIO_DisablePin(GPIO_PIN pinNumber, GpioPinDriveMode driveMode, uint32_t alternateFunction) { - DeleteInputState(pinNumber); + DeleteInputState(pinNumber); - GLOBAL_LOCK(); + GLOBAL_LOCK(); - CPU_GPIO_SetDriveMode(pinNumber, driveMode); + CPU_GPIO_SetDriveMode(pinNumber, driveMode); - // get IoLine from pin number - ioline_t ioLine = GetIoLine(pinNumber); - palSetLineMode(ioLine, PAL_MODE_ALTERNATE(alternateFunction)); + // get IoLine from pin number + ioline_t ioLine = GetIoLine(pinNumber); + palSetLineMode(ioLine, PAL_MODE_ALTERNATE(alternateFunction)); - GLOBAL_UNLOCK(); + GLOBAL_UNLOCK(); - CPU_GPIO_ReservePin(pinNumber, false); + CPU_GPIO_ReservePin(pinNumber, false); } // Validate pin and set drive mode // return true if ok bool CPU_GPIO_SetDriveMode(GPIO_PIN pinNumber, GpioPinDriveMode driveMode) { - // get IoLine from pin number - ioline_t ioLine = GetIoLine(pinNumber); + // get IoLine from pin number + ioline_t ioLine = GetIoLine(pinNumber); - switch (driveMode) - { - case GpioPinDriveMode_Input: - palSetLineMode(ioLine, PAL_MODE_INPUT); - break; + switch (driveMode) + { + case GpioPinDriveMode_Input: + palSetLineMode(ioLine, PAL_MODE_INPUT); + break; - case GpioPinDriveMode_InputPullDown: - palSetLineMode(ioLine, PAL_MODE_INPUT_PULLDOWN); - break; + case GpioPinDriveMode_InputPullDown: + palSetLineMode(ioLine, PAL_MODE_INPUT_PULLDOWN); + break; - case GpioPinDriveMode_InputPullUp: - palSetLineMode(ioLine, PAL_MODE_INPUT_PULLUP); - break; + case GpioPinDriveMode_InputPullUp: + palSetLineMode(ioLine, PAL_MODE_INPUT_PULLUP); + break; - case GpioPinDriveMode_Output: - palSetLineMode(ioLine, PAL_MODE_OUTPUT_PUSHPULL); - break; + case GpioPinDriveMode_Output: + palSetLineMode(ioLine, PAL_MODE_OUTPUT_PUSHPULL); + break; - case GpioPinDriveMode_OutputOpenDrain: - palSetLineMode(ioLine, PAL_MODE_OUTPUT_OPENDRAIN); - break; + case GpioPinDriveMode_OutputOpenDrain: + palSetLineMode(ioLine, PAL_MODE_OUTPUT_OPENDRAIN); + break; - default: - // all other modes are NOT supported - return false; - } + default: + // all other modes are NOT supported + return false; + } - return true; + return true; } bool CPU_GPIO_DriveModeSupported(GPIO_PIN pinNumber, GpioPinDriveMode driveMode) { - (void)pinNumber; + (void)pinNumber; - bool driveModeSupported = false; + bool driveModeSupported = false; - // check if the requested drive mode is support by ChibiOS config - if ((driveMode == GpioPinDriveMode_Input) || - (driveMode == GpioPinDriveMode_InputPullDown) || - (driveMode == GpioPinDriveMode_InputPullUp) || - (driveMode == GpioPinDriveMode_Output) || - (driveMode == GpioPinDriveMode_OutputOpenDrain)) - { - driveModeSupported = true; - } + // check if the requested drive mode is support by ChibiOS config + if ((driveMode == GpioPinDriveMode_Input) || (driveMode == GpioPinDriveMode_InputPullDown) || + (driveMode == GpioPinDriveMode_InputPullUp) || (driveMode == GpioPinDriveMode_Output) || + (driveMode == GpioPinDriveMode_OutputOpenDrain)) + { + driveModeSupported = true; + } - return driveModeSupported; + return driveModeSupported; } uint32_t CPU_GPIO_GetPinDebounce(GPIO_PIN pinNumber) { - gpio_input_state * ptr = GetInputState(pinNumber); - if (ptr) - { - return ptr->debounceMs; - } + gpio_input_state *ptr = GetInputState(pinNumber); + if (ptr) + { + return ptr->debounceMs; + } - return 0; + return 0; } bool CPU_GPIO_SetPinDebounce(GPIO_PIN pinNumber, CLR_UINT64 debounceTimeMilliseconds) { - gpio_input_state * ptr = GetInputState(pinNumber); - if (ptr) - { - ptr->debounceMs = (uint32_t)(debounceTimeMilliseconds); - return true; - } - return false; + gpio_input_state *ptr = GetInputState(pinNumber); + if (ptr) + { + ptr->debounceMs = (uint32_t)(debounceTimeMilliseconds); + return true; + } + return false; } diff --git a/targets/FreeRTOS/NXP/nanoCLR/Windows.Devices.Gpio/cpu_gpio.cpp b/targets/FreeRTOS/NXP/nanoCLR/Windows.Devices.Gpio/cpu_gpio.cpp index 14450ff3f7..21a50986e8 100644 --- a/targets/FreeRTOS/NXP/nanoCLR/Windows.Devices.Gpio/cpu_gpio.cpp +++ b/targets/FreeRTOS/NXP/nanoCLR/Windows.Devices.Gpio/cpu_gpio.cpp @@ -13,131 +13,130 @@ #include "timers.h" -#define GPIO_MAX_PINS 160 // 5 Ports * 32 bits ? -#define GPIO_BITS_PORT 16 // 16 bits per gpio port -#define TOTAL_GPIO_PORTS ((GPIO_MAX_PINS + (GPIO_BITS_PORT - 1)) / GPIO_BITS_PORT) +#define GPIO_MAX_PINS 160 // 5 Ports * 32 bits ? +#define GPIO_BITS_PORT 16 // 16 bits per gpio port +#define TOTAL_GPIO_PORTS ((GPIO_MAX_PINS + (GPIO_BITS_PORT - 1)) / GPIO_BITS_PORT) // Structure to hold information about input pin struct gpio_input_state { - GPIO_PIN pinNumber; // Pin number - TimerHandle_t debounceTimer; // debounce timer for this Pin - GPIO_INTERRUPT_SERVICE_ROUTINE isrPtr; // Ptr to user ISR or null - uint32_t debounceMs; // debounce Millsecs, no debonce=0 - uint8_t mode; // Interrupt mode - void * param; // Param to user isr call - bool expected; // Expected state for debounce handler - bool waitingDebounce; // True if waiting for debounce timer to complete + GPIO_PIN pinNumber; // Pin number + TimerHandle_t debounceTimer; // debounce timer for this Pin + GPIO_INTERRUPT_SERVICE_ROUTINE isrPtr; // Ptr to user ISR or null + uint32_t debounceMs; // debounce Millsecs, no debonce=0 + uint8_t mode; // Interrupt mode + void *param; // Param to user isr call + bool expected; // Expected state for debounce handler + bool waitingDebounce; // True if waiting for debounce timer to complete }; // Array of gpio_input_state ptrs for each gpio port // each port (GPIO1 to GPIO5) has a low & high 16 bit port. -typedef gpio_input_state * statePortArray[GPIO_BITS_PORT]; +typedef gpio_input_state *statePortArray[GPIO_BITS_PORT]; // For each 16 bit gpio port we have a ptr to an array ptrs to gpio_input_state // These are initialised only when an input gpio bit is enabled keeping memory use to the minimum -static statePortArray * port_array[TOTAL_GPIO_PORTS]; +static statePortArray *port_array[TOTAL_GPIO_PORTS]; // Array of bits for saving reserved state -static uint16_t pinReserved[TOTAL_GPIO_PORTS]; - +static uint16_t pinReserved[TOTAL_GPIO_PORTS]; // this is an utility define to get a port number from our "encoded" pin number // pin 0 -> (GPIO_MAX_PINS - 1) // i.e Port 0 = Pins 0 to 15, port 1 = pins 16 to 31 etc -#define GetIoPort(pinNumber) (pinNumber/GPIO_BITS_PORT) -#define GetIoBit(pinNumber) (pinNumber%GPIO_BITS_PORT) -#define IsValidGpioPin(pinNumber) (pinNumber < GPIO_MAX_PINS) - +#define GetIoPort(pinNumber) (pinNumber / GPIO_BITS_PORT) +#define GetIoBit(pinNumber) (pinNumber % GPIO_BITS_PORT) +#define IsValidGpioPin(pinNumber) (pinNumber < GPIO_MAX_PINS) void Gpio_DebounceHandler(TimerHandle_t xTimer) { - gpio_input_state* pGpio = (gpio_input_state*)pvTimerGetTimerID(xTimer); - if (pGpio->isrPtr) - { - bool actual =(GpioPinValue)GPIO_PinRead(GPIO_BASE(pGpio->pinNumber), GPIO_PIN(pGpio->pinNumber)); - if (actual == pGpio->expected) - { - pGpio->isrPtr(pGpio->pinNumber, actual, pGpio->param); - if (pGpio->mode == GPIO_INT_EDGE_BOTH) - { // both edges - pGpio->expected ^= 1; // update expected state - } - } - } - - pGpio->waitingDebounce = false; + gpio_input_state *pState = (gpio_input_state *)pvTimerGetTimerID(xTimer); + + bool actual = (GpioPinValue)GPIO_PinRead(GPIO_BASE(pState->pinNumber), GPIO_PIN(pState->pinNumber)); + + if (actual == pState->expected) + { + pState->isrPtr(pState->pinNumber, actual); + + if (pState->mode == GPIO_INT_EDGE_BOTH) + { // both edges + pState->expected ^= 1; // update expected state + } + } + + pState->waitingDebounce = false; } -void GPIO_Main_IRQHandler( int portIndex, GPIO_Type * portBase ) +void GPIO_Main_IRQHandler(int portIndex, GPIO_Type *portBase) { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - // Get interrupting pins - uint32_t intPins = GPIO_PortGetInterruptFlags(portBase); + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // Get interrupting pins + uint32_t intPins = GPIO_PortGetInterruptFlags(portBase); - // clear the interrupt status + // clear the interrupt status GPIO_PortClearInterruptFlags(portBase, intPins); - if (portIndex % 2) - { - // use the upper 16 bits for odd ports - intPins >>= 16; - } - else - { - // use the lower 16 bits for even ports - intPins &= 0xFFFF; - } - - // This port been initialised ? - statePortArray * inputStates = port_array[portIndex]; - if ( inputStates ) - { - uint32_t bitNumber = 0; - - // Handle all pins with pending interrupt - while(intPins) - { - if ( intPins & 0x01 ) - { - // Interupt on pin ? - gpio_input_state * pGpio = (*inputStates)[bitNumber]; - // Do we have gpio_input_state setup for this pin ? - if (pGpio) - { - // Ignore any pin changes during debounce - if (!pGpio->waitingDebounce) - { - // If user ISR available then call it - if (pGpio->isrPtr) - { - // If debounce timer defined then first wait for it to expire - if (pGpio->debounceMs > 0) - { - pGpio->waitingDebounce = true; - - // Start Debounce timer - xTimerChangePeriodFromISR(pGpio->debounceTimer, pdMS_TO_TICKS(pGpio->debounceMs), &xHigherPriorityTaskWoken); - } - else - { - GpioPinValue PinState = (GpioPinValue)GPIO_PinRead(GPIO_BASE(pGpio->pinNumber), GPIO_PIN(pGpio->pinNumber)); - pGpio->isrPtr(pGpio->pinNumber, PinState, pGpio->param); - } - } - } - } // if pin setup in nanoFramework - } // if interrupt - - intPins>>=1; - bitNumber++; - } // while - } - - portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + if (portIndex % 2) + { + // use the upper 16 bits for odd ports + intPins >>= 16; + } + else + { + // use the lower 16 bits for even ports + intPins &= 0xFFFF; + } + + // This port been initialised ? + statePortArray *inputStates = port_array[portIndex]; + if (inputStates) + { + uint32_t bitNumber = 0; + + // Handle all pins with pending interrupt + while (intPins) + { + if (intPins & 0x01) + { + // Interupt on pin ? + gpio_input_state *pState = (*inputStates)[bitNumber]; + + // Do we have gpio_input_state setup for this pin ? + if (pState) + { + // Ignore any pin changes during debounce + if (!pState->waitingDebounce) + { + // If debounce timer defined then first wait for it to expire + if (pState->debounceMs > 0) + { + pState->waitingDebounce = true; + + // Start Debounce timer + xTimerChangePeriodFromISR( + pState->debounceTimer, + pdMS_TO_TICKS(pState->debounceMs), + &xHigherPriorityTaskWoken); + } + else + { + GpioPinValue PinState = + (GpioPinValue)GPIO_PinRead(GPIO_BASE(pState->pinNumber), GPIO_PIN(pState->pinNumber)); + pState->isrPtr(pState->pinNumber, PinState); + } + } + } // if pin setup in nanoFramework + } // if interrupt + + intPins >>= 1; + bitNumber++; + } // while + } + + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); // Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping - // exception return operation might vector to incorrect interrupt + // exception return operation might vector to incorrect interrupt #if defined __CORTEX_M && (__CORTEX_M == 4U) __DSB(); #endif @@ -145,205 +144,209 @@ void GPIO_Main_IRQHandler( int portIndex, GPIO_Type * portBase ) extern "C" { -// Gpio ISR handler for GPIO port 1 bits 0-15 -void GPIO1_Combined_0_15_IRQHandler(void) -{ - GPIO_Main_IRQHandler( 0, GPIO1 ); -} -// Gpio ISR handler for GPIO port 1 bits 16-31 -void GPIO1_Combined_16_31_IRQHandler(void) -{ - GPIO_Main_IRQHandler( 1, GPIO1 ); -} -// Gpio ISR handler for GPIO port 2 bits 0-15 -void GPIO2_Combined_0_15_IRQHandler(void) -{ - GPIO_Main_IRQHandler( 2, GPIO2 ); -} -// Gpio ISR handler for GPIO port 2 bits 16-31 - -// TODO: this handler is used to sdcard detect -// void GPIO2_Combined_16_31_IRQHandler(void) -// { -// GPIO_Main_IRQHandler( 3, GPIO2 ); -// } -// Gpio ISR handler for GPIO port 3 bits 0-15 -void GPIO3_Combined_0_15_IRQHandler(void) -{ - GPIO_Main_IRQHandler( 4, GPIO3 ); -} -// Gpio ISR handler for GPIO port 3 bits 16-31 -void GPIO3_Combined_16_31_IRQHandler(void) -{ - GPIO_Main_IRQHandler( 5, GPIO3 ); -} -// Gpio ISR handler for GPIO port 4 bits 0-15 -void GPIO4_Combined_0_15_IRQHandler(void) -{ - GPIO_Main_IRQHandler( 6, GPIO4 ); -} -// Gpio ISR handler for GPIO port 4 bits 16-31 -void GPIO4_Combined_16_31_IRQHandler(void) -{ - GPIO_Main_IRQHandler( 7, GPIO4 ); -} -// Gpio ISR handler for GPIO port 5 bits 0-15 -void GPIO5_Combined_0_15_IRQHandler(void) -{ - GPIO_Main_IRQHandler( 8, GPIO5 ); -} -// Gpio ISR handler for GPIO port 5 bits 16-31 -void GPIO5_Combined_16_31_IRQHandler(void) -{ - GPIO_Main_IRQHandler( 9, GPIO5 ); -} + // Gpio ISR handler for GPIO port 1 bits 0-15 + void GPIO1_Combined_0_15_IRQHandler(void) + { + GPIO_Main_IRQHandler(0, GPIO1); + } + // Gpio ISR handler for GPIO port 1 bits 16-31 + void GPIO1_Combined_16_31_IRQHandler(void) + { + GPIO_Main_IRQHandler(1, GPIO1); + } + // Gpio ISR handler for GPIO port 2 bits 0-15 + void GPIO2_Combined_0_15_IRQHandler(void) + { + GPIO_Main_IRQHandler(2, GPIO2); + } + // Gpio ISR handler for GPIO port 2 bits 16-31 + + // TODO: this handler is used to sdcard detect + // void GPIO2_Combined_16_31_IRQHandler(void) + // { + // GPIO_Main_IRQHandler( 3, GPIO2 ); + // } + // Gpio ISR handler for GPIO port 3 bits 0-15 + void GPIO3_Combined_0_15_IRQHandler(void) + { + GPIO_Main_IRQHandler(4, GPIO3); + } + // Gpio ISR handler for GPIO port 3 bits 16-31 + void GPIO3_Combined_16_31_IRQHandler(void) + { + GPIO_Main_IRQHandler(5, GPIO3); + } + // Gpio ISR handler for GPIO port 4 bits 0-15 + void GPIO4_Combined_0_15_IRQHandler(void) + { + GPIO_Main_IRQHandler(6, GPIO4); + } + // Gpio ISR handler for GPIO port 4 bits 16-31 + void GPIO4_Combined_16_31_IRQHandler(void) + { + GPIO_Main_IRQHandler(7, GPIO4); + } + // Gpio ISR handler for GPIO port 5 bits 0-15 + void GPIO5_Combined_0_15_IRQHandler(void) + { + GPIO_Main_IRQHandler(8, GPIO5); + } + // Gpio ISR handler for GPIO port 5 bits 16-31 + void GPIO5_Combined_16_31_IRQHandler(void) + { + GPIO_Main_IRQHandler(9, GPIO5); + } } // Get pointer to gpio_input_state for Gpio pin // return NULL if not found -gpio_input_state * GetInputState(GPIO_PIN pinNumber ) +gpio_input_state *GetInputState(GPIO_PIN pinNumber) { - int port = GetIoPort(pinNumber); - int bit = GetIoBit(pinNumber); + int port = GetIoPort(pinNumber); + int bit = GetIoBit(pinNumber); - if ( port_array[port] == NULL) return NULL; + if (port_array[port] == NULL) + return NULL; - statePortArray * inputStates = port_array[port]; - return *inputStates[bit]; + statePortArray *inputStates = port_array[port]; + return *inputStates[bit]; } // Allocate a new gpio_input_state and add to end of list // if already exist then just return current ptr -gpio_input_state * AllocateGpioInputState(GPIO_PIN pinNumber) +gpio_input_state *AllocateGpioInputState(GPIO_PIN pinNumber) { - int port = GetIoPort(pinNumber); - int bit = GetIoBit(pinNumber); - - if ( port_array[port] == NULL) - { - port_array[port] = (statePortArray*)platform_malloc(sizeof(statePortArray)); - if (port_array[port] == NULL ) return NULL; - - memset(port_array[port], 0, sizeof(statePortArray) ); - } - - statePortArray * inputStates = port_array[port]; - - gpio_input_state * pGpio = (*inputStates)[bit]; - if (pGpio == NULL) - { - pGpio = (gpio_input_state *)platform_malloc(sizeof(gpio_input_state)); - memset(pGpio, 0, sizeof(gpio_input_state)); - pGpio->pinNumber = pinNumber; - (*inputStates)[bit] = pGpio; - } - return pGpio; + int port = GetIoPort(pinNumber); + int bit = GetIoBit(pinNumber); + + if (port_array[port] == NULL) + { + port_array[port] = (statePortArray *)platform_malloc(sizeof(statePortArray)); + if (port_array[port] == NULL) + return NULL; + + memset(port_array[port], 0, sizeof(statePortArray)); + } + + statePortArray *inputStates = port_array[port]; + + gpio_input_state *pState = (*inputStates)[bit]; + if (pState == NULL) + { + pState = (gpio_input_state *)platform_malloc(sizeof(gpio_input_state)); + memset(pState, 0, sizeof(gpio_input_state)); + pState->pinNumber = pinNumber; + (*inputStates)[bit] = pState; + } + return pState; } // Delete gpio_input_state from List and tidy up ( Timer & ISR handler ) void DeleteInputState(GPIO_PIN pinNumber) { - int port = GetIoPort(pinNumber); - int bit = GetIoBit(pinNumber); - - statePortArray* inputStates = port_array[port]; - if ( inputStates == NULL ) return; - - gpio_input_state * pGpio = (*inputStates)[bit]; - if (pGpio) - { - if (pGpio->debounceTimer != 0) - { - xTimerDelete(pGpio->debounceTimer, 100); - } - - // Remove interrupt associatted with pin - gpio_pin_config_t config = {kGPIO_DigitalInput, 0, kGPIO_NoIntmode }; - GPIO_PinInit(GPIO_BASE(pinNumber), GPIO_PIN(pinNumber), &config); - - platform_free(pGpio); - (*inputStates)[bit] = NULL; - } + int port = GetIoPort(pinNumber); + int bit = GetIoBit(pinNumber); + + statePortArray *inputStates = port_array[port]; + if (inputStates == NULL) + return; + + gpio_input_state *pState = (*inputStates)[bit]; + if (pState) + { + if (pState->debounceTimer != 0) + { + xTimerDelete(pState->debounceTimer, 100); + } + + // Remove interrupt associatted with pin + gpio_pin_config_t config = {kGPIO_DigitalInput, 0, kGPIO_NoIntmode}; + GPIO_PinInit(GPIO_BASE(pinNumber), GPIO_PIN(pinNumber), &config); + + platform_free(pState); + (*inputStates)[bit] = NULL; + } } - -bool CPU_GPIO_Initialize() +bool CPU_GPIO_Initialize() { - // All port ptrs are null - memset(port_array, 0, sizeof(port_array)); + // All port ptrs are null + memset(port_array, 0, sizeof(port_array)); + + // Make sure all pins are not reserved + memset(pinReserved, 0, sizeof(pinReserved)); - // Make sure all pins are not reserved - memset(pinReserved, 0, sizeof(pinReserved)); - - return true; + return true; } -bool CPU_GPIO_Uninitialize() +bool CPU_GPIO_Uninitialize() { - // First remove any active pin states - for(int pinNumber=0; pinNumber < GPIO_MAX_PINS; pinNumber++) - { - DeleteInputState(pinNumber); - } - - // Remove statePortArray if any - for(int port=0; port < TOTAL_GPIO_PORTS; port++) - { - statePortArray* inputStates = port_array[port]; - if ( inputStates != NULL ) - { - platform_free(port_array[port]); // free up inputStates array - port_array[port] = NULL; - } - } - - return true; + // First remove any active pin states + for (int pinNumber = 0; pinNumber < GPIO_MAX_PINS; pinNumber++) + { + DeleteInputState(pinNumber); + } + + // Remove statePortArray if any + for (int port = 0; port < TOTAL_GPIO_PORTS; port++) + { + statePortArray *inputStates = port_array[port]; + if (inputStates != NULL) + { + platform_free(port_array[port]); // free up inputStates array + port_array[port] = NULL; + } + } + + return true; } // Set/reset reserved state of pin -bool CPU_GPIO_ReservePin(GPIO_PIN pinNumber, bool fReserve) +bool CPU_GPIO_ReservePin(GPIO_PIN pinNumber, bool fReserve) { - // Check if valid pin number - if (!IsValidGpioPin(pinNumber)) return false; - - int port = pinNumber >> 4; - int bit = 1 << (pinNumber & 0x0F); - - GLOBAL_LOCK(); - - if (fReserve) - { - if (pinReserved[port] & bit) - { - GLOBAL_UNLOCK(); - return false; // already reserved - } - - pinReserved[port] |= bit; - } - else - { - pinReserved[port] &= ~bit; - } - - GLOBAL_UNLOCK(); - return true; + // Check if valid pin number + if (!IsValidGpioPin(pinNumber)) + return false; + + int port = pinNumber >> 4; + int bit = 1 << (pinNumber & 0x0F); + + GLOBAL_LOCK(); + + if (fReserve) + { + if (pinReserved[port] & bit) + { + GLOBAL_UNLOCK(); + return false; // already reserved + } + + pinReserved[port] |= bit; + } + else + { + pinReserved[port] &= ~bit; + } + + GLOBAL_UNLOCK(); + return true; } // Return if Pin is reserved bool CPU_GPIO_PinIsBusy(GPIO_PIN pinNumber) { - // Check if valid pin number - if (!IsValidGpioPin(pinNumber)) return false; + // Check if valid pin number + if (!IsValidGpioPin(pinNumber)) + return false; - int port = pinNumber >> 4, sh = pinNumber & 0x0F; - return (pinReserved[port] >> sh) & 1; + int port = pinNumber >> 4, sh = pinNumber & 0x0F; + return (pinReserved[port] >> sh) & 1; } // Return maximum number of pins int32_t CPU_GPIO_GetPinCount() { - return GPIO_MAX_PINS; + return GPIO_MAX_PINS; } // Get current state of pin @@ -361,78 +364,98 @@ void CPU_GPIO_SetPinState(GPIO_PIN pinNumber, GpioPinValue PinState) // Toggle pin state void CPU_GPIO_TogglePinState(GPIO_PIN pinNumber) { - GPIO_PortToggle(GPIO_BASE(pinNumber), 0x1u << GPIO_PIN(pinNumber)); + GPIO_PortToggle(GPIO_BASE(pinNumber), 0x1u << GPIO_PIN(pinNumber)); } // // CPU_GPIO_EnableInputPin // Enable input pin // -bool CPU_GPIO_EnableInputPin(GPIO_PIN pinNumber, CLR_UINT64 debounceTimeMilliseconds, GPIO_INTERRUPT_SERVICE_ROUTINE pin_ISR, void* isr_Param, GPIO_INT_EDGE intEdge, GpioPinDriveMode driveMode) +bool CPU_GPIO_EnableInputPin( + GPIO_PIN pinNumber, + CLR_UINT64 debounceTimeMilliseconds, + GPIO_INTERRUPT_SERVICE_ROUTINE pinISR, + void *isrParam, + GPIO_INT_EDGE intEdge, + GpioPinDriveMode driveMode) { - gpio_input_state * pGpio; - - // Check if valid pin number - if (!IsValidGpioPin(pinNumber)) return false; - - // Check Input drive mode - if (driveMode >= (int)GpioPinDriveMode_Output) - return false; - - if (!CPU_GPIO_SetDriveMode(pinNumber, driveMode)) - return false; - - pGpio = AllocateGpioInputState(pinNumber); - - // Map nanoFRamework Interrupt edge to NXP edge - // NONE=0, EDGE_LOW=1, EDGE_HIGH=2, EDGE_BOTH=3, LEVEL_HIGH=4, LEVEL_LOW - const gpio_interrupt_mode_t mapint[6] = { kGPIO_NoIntmode, kGPIO_IntFallingEdge, kGPIO_IntRisingEdge, kGPIO_IntRisingOrFallingEdge, kGPIO_IntHighLevel, kGPIO_IntLowLevel }; - - // enable interupt mode with correct edge - gpio_pin_config_t config = {kGPIO_DigitalInput, 0, mapint[intEdge] }; - GPIO_PinInit(GPIO_BASE(pinNumber), GPIO_PIN(pinNumber), &config); - - // Enable GPIO pin interrupt - IRQn_Type isrNo = (IRQn_Type)(GPIO1_Combined_0_15_IRQn + GetIoPort(pinNumber)); - NVIC_SetPriority(isrNo, 8U); - EnableIRQ(isrNo); - GPIO_PortEnableInterrupts(GPIO_BASE(pinNumber), 1U << GetIoBit(pinNumber)); - GPIO_PortClearInterruptFlags(GPIO_BASE(pinNumber), 1U << GetIoBit(pinNumber)); - - // Initialise Gpio state structure - pGpio->isrPtr = pin_ISR; - pGpio->mode = intEdge; - pGpio->param = (void *)isr_Param; - pGpio->debounceMs = (uint32_t)(debounceTimeMilliseconds); - - // Set up expected new value for debounce - if ( pGpio->debounceMs > 0) - { - if (pGpio->debounceTimer == 0) - { - // Create timer if it doesn't already exist for this pin - pGpio->debounceTimer = xTimerCreate("debounce", 100, pdFALSE, (void*)pGpio, Gpio_DebounceHandler); - } - switch (intEdge) - { - case GPIO_INT_NONE: - case GPIO_INT_EDGE_LOW: - case GPIO_INT_LEVEL_LOW: - pGpio->expected = false; - break; - - case GPIO_INT_EDGE_HIGH: - case GPIO_INT_LEVEL_HIGH: - pGpio->expected = true; - break; - - case GPIO_INT_EDGE_BOTH: - pGpio->expected = !CPU_GPIO_GetPinState(pinNumber); // Use NOT current state - break; - } - } - - return true; + gpio_input_state *pState; + + // Check if valid pin number + if (!IsValidGpioPin(pinNumber)) + return false; + + // Check Input drive mode + if (driveMode >= (int)GpioPinDriveMode_Output) + return false; + + if (!CPU_GPIO_SetDriveMode(pinNumber, driveMode)) + return false; + + pState = AllocateGpioInputState(pinNumber); + + if (pinISR != NULL && (pState->isrPtr == NULL)) + { + // enable interupt mode with correct edge + gpio_pin_config_t config = {kGPIO_DigitalInput, 0, kGPIO_IntRisingOrFallingEdge}; + GPIO_PinInit(GPIO_BASE(pinNumber), GPIO_PIN(pinNumber), &config); + + // Enable GPIO pin interrupt + IRQn_Type isrNo = (IRQn_Type)(GPIO1_Combined_0_15_IRQn + GetIoPort(pinNumber)); + NVIC_SetPriority(isrNo, 8U); + EnableIRQ(isrNo); + GPIO_PortEnableInterrupts(GPIO_BASE(pinNumber), 1U << GetIoBit(pinNumber)); + GPIO_PortClearInterruptFlags(GPIO_BASE(pinNumber), 1U << GetIoBit(pinNumber)); + + // store parameters & configs + pState->isrPtr = pinISR; + pState->mode = intEdge; + pState->param = (void *)isrParam; + pState->debounceMs = (uint32_t)(debounceTimeMilliseconds); + + // Set up expected new value for debounce + if (pState->debounceMs > 0) + { + if (pState->debounceTimer == 0) + { + // Create timer if it doesn't already exist for this pin + pState->debounceTimer = xTimerCreate("debounce", 100, pdFALSE, (void *)pState, Gpio_DebounceHandler); + } + switch (intEdge) + { + case GPIO_INT_NONE: + case GPIO_INT_EDGE_LOW: + case GPIO_INT_LEVEL_LOW: + pState->expected = false; + break; + + case GPIO_INT_EDGE_HIGH: + case GPIO_INT_LEVEL_HIGH: + pState->expected = true; + break; + + case GPIO_INT_EDGE_BOTH: + pState->expected = !CPU_GPIO_GetPinState(pinNumber); // Use NOT current state + break; + } + } + } + else if (pinISR == NULL && (pState->isrPtr != NULL)) + { + // there is no managed handler setup anymore + // remove INT handler + + // disable interrupt + GPIO_PortDisableInterrupts(GPIO_BASE(pinNumber), 1U << GetIoBit(pinNumber)); + + // clear parameters & configs + pState->isrPtr = NULL; + pState->mode = GPIO_INT_NONE; + pState->param = NULL; + pState->debounceMs = 0; + } + + return true; } // Enable an output pin @@ -442,135 +465,137 @@ bool CPU_GPIO_EnableInputPin(GPIO_PIN pinNumber, CLR_UINT64 debounceTimeMillisec // driveMode - Drive mode and resistors // return - True if succesful, false invalid pin, pin not putput, invalid drive mode for ouptput // -bool CPU_GPIO_EnableOutputPin(GPIO_PIN pinNumber, GpioPinValue InitialState, GpioPinDriveMode driveMode) +bool CPU_GPIO_EnableOutputPin(GPIO_PIN pinNumber, GpioPinValue InitialState, GpioPinDriveMode driveMode) { - // Check if valid pin number - if (!IsValidGpioPin(pinNumber)) return false; + // Check if valid pin number + if (!IsValidGpioPin(pinNumber)) + return false; - // check is output drive mode - if (driveMode < (int)GpioPinDriveMode_Output) return false; + // check is output drive mode + if (driveMode < (int)GpioPinDriveMode_Output) + return false; - if (CPU_GPIO_SetDriveMode(pinNumber, driveMode) == false) return false; + if (CPU_GPIO_SetDriveMode(pinNumber, driveMode) == false) + return false; - CPU_GPIO_SetPinState(pinNumber, InitialState); + CPU_GPIO_SetPinState(pinNumber, InitialState); - return true; + return true; } void CPU_GPIO_DisablePin(GPIO_PIN pinNumber, GpioPinDriveMode driveMode, uint32_t alternateFunction) { - GLOBAL_LOCK(); + GLOBAL_LOCK(); - CPU_GPIO_SetDriveMode(pinNumber, driveMode); + CPU_GPIO_SetDriveMode(pinNumber, driveMode); - DeleteInputState(pinNumber); - - if (alternateFunction) - { + DeleteInputState(pinNumber); + + if (alternateFunction) + { GPIO_PinMux(GPIO_PORT(pinNumber), GPIO_PIN(pinNumber), alternateFunction); - } + } - GLOBAL_UNLOCK(); + GLOBAL_UNLOCK(); - CPU_GPIO_ReservePin(pinNumber, false); + CPU_GPIO_ReservePin(pinNumber, false); } - // Validate pin and set drive mode // return true if ok bool CPU_GPIO_SetDriveMode(GPIO_PIN pinNumber, GpioPinDriveMode driveMode) { - // Check if valid pin number - if (!IsValidGpioPin(pinNumber)) return false; - - gpio_pin_direction_t direction; - uint32_t pinConfig; - - switch (driveMode) - { - case GpioPinDriveMode_Input: - direction = kGPIO_DigitalInput; - pinConfig = GPIO_IO; - break; - - case GpioPinDriveMode_InputPullDown: - direction = kGPIO_DigitalInput; - pinConfig = GPIO_IN_PULLDOWN; - break; - - case GpioPinDriveMode_InputPullUp: - direction = kGPIO_DigitalInput; - pinConfig = GPIO_IN_PULLUP; - break; - - case GpioPinDriveMode_Output: - direction = kGPIO_DigitalOutput; - pinConfig = GPIO_IO; - break; - - case GpioPinDriveMode_OutputOpenDrain: - direction = kGPIO_DigitalOutput; - pinConfig = GPIO_OUT_OPENDRAIN; - break; - - default: - // all other modes are NOT supported - return false; - } - - gpio_pin_config_t config = {direction, 0, kGPIO_NoIntmode}; - - GPIO_PinMux(GPIO_PORT(pinNumber), GPIO_PIN(pinNumber), 0x5u); - GPIO_PinConfig(GPIO_PORT(pinNumber), GPIO_PIN(pinNumber), pinConfig); - GPIO_PinInit(GPIO_BASE(pinNumber), GPIO_PIN(pinNumber), &config); - - return true; + // Check if valid pin number + if (!IsValidGpioPin(pinNumber)) + return false; + + gpio_pin_direction_t direction; + uint32_t pinConfig; + + switch (driveMode) + { + case GpioPinDriveMode_Input: + direction = kGPIO_DigitalInput; + pinConfig = GPIO_IO; + break; + + case GpioPinDriveMode_InputPullDown: + direction = kGPIO_DigitalInput; + pinConfig = GPIO_IN_PULLDOWN; + break; + + case GpioPinDriveMode_InputPullUp: + direction = kGPIO_DigitalInput; + pinConfig = GPIO_IN_PULLUP; + break; + + case GpioPinDriveMode_Output: + direction = kGPIO_DigitalOutput; + pinConfig = GPIO_IO; + break; + + case GpioPinDriveMode_OutputOpenDrain: + direction = kGPIO_DigitalOutput; + pinConfig = GPIO_OUT_OPENDRAIN; + break; + + default: + // all other modes are NOT supported + return false; + } + + gpio_pin_config_t config = {direction, 0, kGPIO_NoIntmode}; + + GPIO_PinMux(GPIO_PORT(pinNumber), GPIO_PIN(pinNumber), 0x5u); + GPIO_PinConfig(GPIO_PORT(pinNumber), GPIO_PIN(pinNumber), pinConfig); + GPIO_PinInit(GPIO_BASE(pinNumber), GPIO_PIN(pinNumber), &config); + + return true; } bool CPU_GPIO_DriveModeSupported(GPIO_PIN pinNumber, GpioPinDriveMode driveMode) { - // Check if valid pin number - if (!IsValidGpioPin(pinNumber)) return false; - - bool driveModeSupported = false; - - // check if the requested drive mode is supported - if ((driveMode == GpioPinDriveMode_Input) || - (driveMode == GpioPinDriveMode_InputPullDown) || - (driveMode == GpioPinDriveMode_InputPullUp) || - (driveMode == GpioPinDriveMode_Output) || - (driveMode == GpioPinDriveMode_OutputOpenDrain)) - { - driveModeSupported = true; - } - - return driveModeSupported; + // Check if valid pin number + if (!IsValidGpioPin(pinNumber)) + return false; + + bool driveModeSupported = false; + + // check if the requested drive mode is supported + if ((driveMode == GpioPinDriveMode_Input) || (driveMode == GpioPinDriveMode_InputPullDown) || + (driveMode == GpioPinDriveMode_InputPullUp) || (driveMode == GpioPinDriveMode_Output) || + (driveMode == GpioPinDriveMode_OutputOpenDrain)) + { + driveModeSupported = true; + } + + return driveModeSupported; } uint32_t CPU_GPIO_GetPinDebounce(GPIO_PIN pinNumber) { - // Check if valid pin number - if (IsValidGpioPin(pinNumber)) - { - gpio_input_state * ptr = GetInputState(pinNumber); - if (ptr) - return ptr->debounceMs; - } - - return 0; + // Check if valid pin number + if (IsValidGpioPin(pinNumber)) + { + gpio_input_state *ptr = GetInputState(pinNumber); + if (ptr) + return ptr->debounceMs; + } + + return 0; } bool CPU_GPIO_SetPinDebounce(GPIO_PIN pinNumber, CLR_UINT64 debounceTimeMilliseconds) { - // Check if valid pin number - if (IsValidGpioPin(pinNumber)) - { - gpio_input_state * ptr = GetInputState(pinNumber); - if (ptr) - { - ptr->debounceMs = (uint32_t)(debounceTimeMilliseconds); - return true; - } - } - return false; + // Check if valid pin number + if (IsValidGpioPin(pinNumber)) + { + gpio_input_state *ptr = GetInputState(pinNumber); + if (ptr) + { + ptr->debounceMs = (uint32_t)(debounceTimeMilliseconds); + return true; + } + } + return false; } diff --git a/targets/FreeRTOS_ESP32/ESP32_WROOM_32/nanoCLR/Windows.Devices.Gpio/cpu_gpio.cpp b/targets/FreeRTOS_ESP32/ESP32_WROOM_32/nanoCLR/Windows.Devices.Gpio/cpu_gpio.cpp index 0d8aeecd6f..e5fcb754cd 100644 --- a/targets/FreeRTOS_ESP32/ESP32_WROOM_32/nanoCLR/Windows.Devices.Gpio/cpu_gpio.cpp +++ b/targets/FreeRTOS_ESP32/ESP32_WROOM_32/nanoCLR/Windows.Devices.Gpio/cpu_gpio.cpp @@ -18,90 +18,91 @@ #include "Esp32_DeviceMapping.h" -static const char* TAG = "cpu_Gpio"; +static const char *TAG = "cpu_Gpio"; -#define ESP32_Gpio_MaxPins GPIO_PIN_COUNT // 0 -> 31, 32-39 (high) +#define ESP32_Gpio_MaxPins GPIO_PIN_COUNT // 0 -> 31, 32-39 (high) #define TOTAL_GPIO_PORTS ((ESP32_Gpio_MaxPins + 15) / 16) // Double linkedlist to hold the state of each Input pin struct gpio_input_state : public HAL_DblLinkedNode { - GPIO_PIN pinNumber; // Pin number - TimerHandle_t debounceTimer; // debounce timer for this Pin - GPIO_INTERRUPT_SERVICE_ROUTINE isrPtr; // Ptr to user ISR or null - uint32_t debounceMs; // debounce Millsecs, no debonce=0 - uint8_t mode; // Interrupt mode - void * param; // Param to user isr call - bool expected; // Expected state for debounce handler - bool waitingDebounce; // True if waiting for debounce timer to complete + GPIO_PIN pinNumber; // Pin number + TimerHandle_t debounceTimer; // debounce timer for this Pin + GPIO_INTERRUPT_SERVICE_ROUTINE isrPtr; // Ptr to user ISR or null + uint32_t debounceMs; // debounce Millsecs, no debonce=0 + uint8_t mode; // Interrupt mode + void *param; // Param to user isr call + bool expected; // Expected state for debounce handler + bool waitingDebounce; // True if waiting for debounce timer to complete }; -static HAL_DblLinkedList gpioInputList; // Doulble LInkedlist for GPIO input status -static uint16_t pinReserved[TOTAL_GPIO_PORTS]; // reserved - 1 bit per pin - +static HAL_DblLinkedList gpioInputList; // Doulble LInkedlist for GPIO input status +static uint16_t pinReserved[TOTAL_GPIO_PORTS]; // reserved - 1 bit per pin // Get pointer to gpio_input_state for Gpio pin // return NULL if not found -gpio_input_state * GetInputState(GPIO_PIN pinNumber) +gpio_input_state *GetInputState(GPIO_PIN pinNumber) { - gpio_input_state * ptr = gpioInputList.FirstNode(); - while ( ptr->Next() != NULL ) - { - if (ptr->pinNumber == pinNumber) return ptr; - ptr = ptr->Next(); - } - return NULL; + gpio_input_state *ptr = gpioInputList.FirstNode(); + while (ptr->Next() != NULL) + { + if (ptr->pinNumber == pinNumber) + return ptr; + ptr = ptr->Next(); + } + return NULL; } // Allocate a new gpio_input_state and add to end of list // if already exist then just return current ptr -gpio_input_state * AllocateGpioInputState(GPIO_PIN pinNumber) +gpio_input_state *AllocateGpioInputState(GPIO_PIN pinNumber) { - gpio_input_state * ptr = GetInputState(pinNumber); - if (ptr == NULL) - { - ptr = (gpio_input_state *)platform_malloc(sizeof(gpio_input_state)); - memset(ptr, 0, sizeof(gpio_input_state)); - ptr->pinNumber = pinNumber; - gpioInputList.LinkAtBack(ptr); - - } - return ptr; + gpio_input_state *ptr = GetInputState(pinNumber); + if (ptr == NULL) + { + ptr = (gpio_input_state *)platform_malloc(sizeof(gpio_input_state)); + memset(ptr, 0, sizeof(gpio_input_state)); + ptr->pinNumber = pinNumber; + gpioInputList.LinkAtBack(ptr); + } + return ptr; } -void UnlinkInputState(gpio_input_state * pState) +void UnlinkInputState(gpio_input_state *pState) { - if (pState->debounceTimer != 0) - { - xTimerDelete(pState->debounceTimer, 100); - } + if (pState->debounceTimer != 0) + { + xTimerDelete(pState->debounceTimer, 100); + } - // Remove interrupt associatted with pin - gpio_isr_handler_remove((gpio_num_t)pState->pinNumber); + // Remove interrupt associatted with pin + gpio_isr_handler_remove((gpio_num_t)pState->pinNumber); - pState->Unlink(); - platform_free(pState); + pState->Unlink(); + platform_free(pState); } // Delete gpio_input_state from List and tidy up ( Timer & ISR handler ) void DeleteInputState(GPIO_PIN pinNumber) { - gpio_input_state * pState = GetInputState(pinNumber); - if (pState) - UnlinkInputState(pState); + gpio_input_state *pState = GetInputState(pinNumber); + if (pState) + UnlinkInputState(pState); } -void Esp_Gpio_fire_event(gpio_input_state* pState) +void Esp_Gpio_fire_event(gpio_input_state *pState) { - bool actual = CPU_GPIO_GetPinState(pState->pinNumber); // get current pin state - if (actual == pState->expected) - { - pState->isrPtr(pState->pinNumber, actual, pState->param); - if (pState->mode == GPIO_INT_EDGE_BOTH) - { // both edges - pState->expected ^= 1; // update expected state - } - } + bool actual = CPU_GPIO_GetPinState(pState->pinNumber); // get current pin state + if (actual == pState->expected) + { + pState->isrPtr(pState->pinNumber, actual); + + if (pState->mode == GPIO_INT_EDGE_BOTH) + { + // both edges + pState->expected ^= 1; // update expected state + } + } } // @@ -109,203 +110,230 @@ void Esp_Gpio_fire_event(gpio_input_state* pState) // void Esp_Gpio_DebounceHandler(TimerHandle_t xTimer) { - gpio_input_state* pState = (gpio_input_state*)pvTimerGetTimerID(xTimer); - if (pState->isrPtr) - { - Esp_Gpio_fire_event(pState); - } + gpio_input_state *pState = (gpio_input_state *)pvTimerGetTimerID(xTimer); + if (pState->isrPtr) + { + Esp_Gpio_fire_event(pState); + } - pState->waitingDebounce = false; + pState->waitingDebounce = false; } -bool CPU_GPIO_Initialize() +bool CPU_GPIO_Initialize() { - // Initialise Double linked list for input pin states - gpioInputList.Initialize(); - - // Make sure all pins are not reserved - memset(pinReserved, 0, sizeof(pinReserved)); - - // Reserve Pins 6-11 as used by Spi flash - for (int pinNumber = 6; pinNumber <= 11; pinNumber++) - CPU_GPIO_ReservePin(pinNumber, true); - - // Install ISR service for GPIO - esp_err_t ret = gpio_install_isr_service(0); - if (ret != ESP_OK) - { - ESP_LOGE(TAG, "Install isr service"); - return false; - } - - return true; + // Initialise Double linked list for input pin states + gpioInputList.Initialize(); + + // Make sure all pins are not reserved + memset(pinReserved, 0, sizeof(pinReserved)); + + // Reserve Pins 6-11 as used by Spi flash + for (int pinNumber = 6; pinNumber <= 11; pinNumber++) + CPU_GPIO_ReservePin(pinNumber, true); + + // Install ISR service for GPIO + esp_err_t ret = gpio_install_isr_service(0); + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "Install isr service"); + return false; + } + + return true; } -bool CPU_GPIO_Uninitialize() +bool CPU_GPIO_Uninitialize() { - gpio_input_state * pGpio; + gpio_input_state *pGpio; - pGpio = gpioInputList.FirstNode(); + pGpio = gpioInputList.FirstNode(); - // Clean up input state list - while ( pGpio->Next() != NULL ) - { - UnlinkInputState(pGpio); - pGpio = pGpio->Next(); - } + // Clean up input state list + while (pGpio->Next() != NULL) + { + UnlinkInputState(pGpio); + pGpio = pGpio->Next(); + } - gpio_uninstall_isr_service(); - return true; + gpio_uninstall_isr_service(); + return true; } // Set/reset reserved state of pin -bool CPU_GPIO_ReservePin(GPIO_PIN pinNumber, bool fReserve) +bool CPU_GPIO_ReservePin(GPIO_PIN pinNumber, bool fReserve) { - // Check if valid pin number - if (!GPIO_IS_VALID_GPIO((gpio_num_t)pinNumber)) return false; - - int port = pinNumber >> 4, bit = 1 << (pinNumber & 0x0F); - GLOBAL_LOCK(); - - if (fReserve) - { - if (pinReserved[port] & bit) - { - GLOBAL_UNLOCK(); - return false; // already reserved - } - - pinReserved[port] |= bit; - } - else - { - pinReserved[port] &= ~bit; - } - - GLOBAL_UNLOCK(); - return true; + // Check if valid pin number + if (!GPIO_IS_VALID_GPIO((gpio_num_t)pinNumber)) + return false; + + int port = pinNumber >> 4, bit = 1 << (pinNumber & 0x0F); + GLOBAL_LOCK(); + + if (fReserve) + { + if (pinReserved[port] & bit) + { + GLOBAL_UNLOCK(); + return false; // already reserved + } + + pinReserved[port] |= bit; + } + else + { + pinReserved[port] &= ~bit; + } + + GLOBAL_UNLOCK(); + return true; } // Return if Pin is reserved bool CPU_GPIO_PinIsBusy(GPIO_PIN pin) { - int port = pin >> 4, sh = pin & 0x0F; - return (pinReserved[port] >> sh) & 1; + int port = pin >> 4, sh = pin & 0x0F; + return (pinReserved[port] >> sh) & 1; } // Return maximum number of pins int32_t CPU_GPIO_GetPinCount() { - return ESP32_Gpio_MaxPins; + return ESP32_Gpio_MaxPins; } // Get current state of pin GpioPinValue CPU_GPIO_GetPinState(GPIO_PIN pin) { - return (GpioPinValue)gpio_get_level((gpio_num_t)pin); + return (GpioPinValue)gpio_get_level((gpio_num_t)pin); } // Set Pin state void CPU_GPIO_SetPinState(GPIO_PIN pin, GpioPinValue PinState) { - gpio_set_level((gpio_num_t)pin, (uint32_t)PinState); + gpio_set_level((gpio_num_t)pin, (uint32_t)PinState); } // ISR called by IDF -static void gpio_isr(void * arg) +static void gpio_isr(void *arg) { - NATIVE_INTERRUPT_START - - gpio_input_state * pState = (gpio_input_state *)arg;; - - // Ignore any pin changes during debounce - if (pState->waitingDebounce) return; - - // If user ISR available then call it - if (pState->isrPtr) - { - if (pState->debounceMs > 0) - { - pState->waitingDebounce = true; - - if (pState->debounceTimer == 0) - { - // Create timer if it doesn't already exist for this pin - pState->debounceTimer = xTimerCreate("debounce", 100, pdFALSE, (void*)pState, Esp_Gpio_DebounceHandler); - } - - // Start Debounce timer (minimum 1 freeRtos tick(10ms) ) - int ticks = pdMS_TO_TICKS(pState->debounceMs); - if (ticks == 0) ticks = 1; - xTimerChangePeriodFromISR(pState->debounceTimer, ticks, pdFALSE); - } - else - { - Esp_Gpio_fire_event(pState); - } - } - - NATIVE_INTERRUPT_END + NATIVE_INTERRUPT_START + + gpio_input_state *pState = (gpio_input_state *)arg; + ; + + // Ignore any pin changes during debounce + if (pState->waitingDebounce) + return; + + if (pState->debounceMs > 0) + { + pState->waitingDebounce = true; + + if (pState->debounceTimer == 0) + { + // Create timer if it doesn't already exist for this pin + pState->debounceTimer = xTimerCreate("debounce", 100, pdFALSE, (void *)pState, Esp_Gpio_DebounceHandler); + } + + // Start Debounce timer (minimum 1 freeRtos tick(10ms) ) + int ticks = pdMS_TO_TICKS(pState->debounceMs); + if (ticks == 0) + ticks = 1; + xTimerChangePeriodFromISR(pState->debounceTimer, ticks, pdFALSE); + } + else + { + Esp_Gpio_fire_event(pState); + } + + NATIVE_INTERRUPT_END } -bool CPU_GPIO_EnableInputPin(GPIO_PIN pinNumber, CLR_UINT64 debounceTimeMilliseconds, GPIO_INTERRUPT_SERVICE_ROUTINE pin_ISR, void* isr_Param, GPIO_INT_EDGE intEdge, GpioPinDriveMode driveMode) +bool CPU_GPIO_EnableInputPin( + GPIO_PIN pinNumber, + CLR_UINT64 debounceTimeMilliseconds, + GPIO_INTERRUPT_SERVICE_ROUTINE pinISR, + void *isr_Param, + GPIO_INT_EDGE intEdge, + GpioPinDriveMode driveMode) { - esp_err_t ret; - gpio_input_state * pState; - - // Check Input drive mode - if (driveMode >= (int)GpioPinDriveMode_Output) - return false; - - // Set as Input GPIO_INT_EDGE intEdge, GPIO_RESISTOR ResistorState - if (!CPU_GPIO_SetDriveMode(pinNumber, driveMode)) - return false; - - pState = AllocateGpioInputState(pinNumber); - - // Link ISR ptr supplied and not already set up - // CPU_GPIO_EnableInputPin could be called a 2nd time with changed parameters - if ( (pin_ISR != NULL) && (pState->isrPtr == NULL)) - { - ret = gpio_isr_handler_add((gpio_num_t)pinNumber, gpio_isr, (void *)pState); - if (ret != ESP_OK) - { - ESP_LOGE(TAG, "Add interrupt to gpio pin failed"); - return false; - } - - // Map Interrupt edge to ESP32 edge - // NONE=0, EDGE_LOW=1, EDGE_HIGH=2, EDGE_BOTH=3, LEVEL_HIGH=4, LEVEL_LOW - uint8_t mapint[6] = { GPIO_INTR_DISABLE, GPIO_INTR_NEGEDGE ,GPIO_INTR_POSEDGE, GPIO_INTR_ANYEDGE, GPIO_INTR_HIGH_LEVEL, GPIO_INTR_LOW_LEVEL }; - gpio_set_intr_type((gpio_num_t)pinNumber, (gpio_int_type_t)mapint[intEdge]); - } - - pState->isrPtr = pin_ISR; - pState->mode = intEdge; - pState->param = (void *)isr_Param; - pState->debounceMs = (uint32_t)(debounceTimeMilliseconds); - - switch (intEdge) - { - case GPIO_INT_EDGE_LOW: - case GPIO_INT_LEVEL_LOW: - pState->expected = false; - break; - - case GPIO_INT_EDGE_HIGH: - case GPIO_INT_LEVEL_HIGH: - pState->expected = true; - break; - - case GPIO_INT_EDGE_BOTH: - pState->expected = !CPU_GPIO_GetPinState(pinNumber); // Use not current state - break; - - default: - break; - } - - return true; + esp_err_t ret; + gpio_input_state *pState; + + // Check Input drive mode + if (driveMode >= (int)GpioPinDriveMode_Output) + return false; + + // Set as Input GPIO_INT_EDGE intEdge, GPIO_RESISTOR ResistorState + if (!CPU_GPIO_SetDriveMode(pinNumber, driveMode)) + return false; + + pState = AllocateGpioInputState(pinNumber); + + // Link ISR ptr supplied and not already set up + // CPU_GPIO_EnableInputPin could be called a 2nd time with changed parameters + if (pinISR != NULL && (pState->isrPtr == NULL)) + { + ret = gpio_isr_handler_add((gpio_num_t)pinNumber, gpio_isr, (void *)pState); + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "Add interrupt to gpio pin failed"); + return false; + } + + // Map Interrupt edge to ESP32 edge + // NONE=0, EDGE_LOW=1, EDGE_HIGH=2, EDGE_BOTH=3, LEVEL_HIGH=4, LEVEL_LOW + uint8_t mapint[6] = { + GPIO_INTR_DISABLE, + GPIO_INTR_NEGEDGE, + GPIO_INTR_POSEDGE, + GPIO_INTR_ANYEDGE, + GPIO_INTR_HIGH_LEVEL, + GPIO_INTR_LOW_LEVEL}; + gpio_set_intr_type((gpio_num_t)pinNumber, (gpio_int_type_t)mapint[intEdge]); + + // store parameters & configs + pState->isrPtr = pinISR; + pState->mode = intEdge; + pState->param = (void *)isr_Param; + pState->debounceMs = (uint32_t)(debounceTimeMilliseconds); + + switch (intEdge) + { + case GPIO_INT_EDGE_LOW: + case GPIO_INT_LEVEL_LOW: + pState->expected = false; + break; + + case GPIO_INT_EDGE_HIGH: + case GPIO_INT_LEVEL_HIGH: + pState->expected = true; + break; + + case GPIO_INT_EDGE_BOTH: + pState->expected = !CPU_GPIO_GetPinState(pinNumber); // Use not current state + break; + + default: + break; + } + } + else if (pinISR == NULL && (pState->isrPtr != NULL)) + { + // there is no managed handler setup anymore + // remove INT handler + + // remove callback + gpio_isr_handler_remove((gpio_num_t)pState->pinNumber); + + // clear parameters & configs + pState->isrPtr = NULL; + pState->mode = GPIO_INT_NONE; + pState->param = NULL; + pState->debounceMs = 0; + } + + return true; } // Enable an output pin @@ -315,142 +343,145 @@ bool CPU_GPIO_EnableInputPin(GPIO_PIN pinNumber, CLR_UINT64 debounceTimeMillisec // driveMode - Drive mode and resistors // return - True if succesful, false invalid pin, pin not putput, invalid drive mode for ouptput // -bool CPU_GPIO_EnableOutputPin(GPIO_PIN pinNumber, GpioPinValue InitialState, GpioPinDriveMode driveMode) +bool CPU_GPIO_EnableOutputPin(GPIO_PIN pinNumber, GpioPinValue InitialState, GpioPinDriveMode driveMode) { - // check not an output drive mode - if (driveMode < (int)GpioPinDriveMode_Output) return false; + // check not an output drive mode + if (driveMode < (int)GpioPinDriveMode_Output) + return false; - // If this is currently an input pin then clean up - DeleteInputState(pinNumber); + // If this is currently an input pin then clean up + DeleteInputState(pinNumber); - if (CPU_GPIO_SetDriveMode(pinNumber, driveMode) == false) return false; + if (CPU_GPIO_SetDriveMode(pinNumber, driveMode) == false) + return false; - CPU_GPIO_SetPinState(pinNumber, InitialState); + CPU_GPIO_SetPinState(pinNumber, InitialState); - return true; + return true; } - void CPU_GPIO_DisablePin(GPIO_PIN pinNumber, GpioPinDriveMode driveMode, uint32_t alternateFunction) { - GLOBAL_LOCK(); - - DeleteInputState(pinNumber); + GLOBAL_LOCK(); - CPU_GPIO_SetDriveMode(pinNumber, driveMode); - - if (alternateFunction != 0) - { - Esp32_SetMappedDevicePins((uint8_t)pinNumber, alternateFunction); - } + DeleteInputState(pinNumber); - GLOBAL_UNLOCK(); + CPU_GPIO_SetDriveMode(pinNumber, driveMode); - CPU_GPIO_ReservePin(pinNumber, false); -} + if (alternateFunction != 0) + { + Esp32_SetMappedDevicePins((uint8_t)pinNumber, alternateFunction); + } + + GLOBAL_UNLOCK(); + CPU_GPIO_ReservePin(pinNumber, false); +} // Validate pin and set drive mode // return true if ok bool CPU_GPIO_SetDriveMode(GPIO_PIN pinNumber, GpioPinDriveMode driveMode) { - // Valid Pin - if (!GPIO_IS_VALID_GPIO(pinNumber)) - { - return false; - } - - // Check Pin is output capable - if (driveMode >= (int)GpioPinDriveMode_Output && !GPIO_IS_VALID_OUTPUT_GPIO(pinNumber)) - { - return false; - } - - gpio_mode_t mode = GPIO_MODE_DISABLE; - gpio_pullup_t pull_up_en = GPIO_PULLUP_DISABLE; - gpio_pulldown_t pull_down_en = GPIO_PULLDOWN_DISABLE; - gpio_int_type_t intr_type = GPIO_INTR_ANYEDGE; - - switch (driveMode) - { - case GpioPinDriveMode_Input: - mode = GPIO_MODE_INPUT; - break; - case GpioPinDriveMode_InputPullDown: - mode = GPIO_MODE_INPUT; - pull_down_en = GPIO_PULLDOWN_ENABLE; - break; - case GpioPinDriveMode_InputPullUp: - mode = GPIO_MODE_INPUT; - pull_up_en = GPIO_PULLUP_ENABLE; - break; - case GpioPinDriveMode_Output: - mode = GPIO_MODE_OUTPUT; - break; - case GpioPinDriveMode_OutputOpenDrain: - mode = GPIO_MODE_OUTPUT_OD; - break; - case GpioPinDriveMode_OutputOpenDrainPullUp: - mode = GPIO_MODE_OUTPUT_OD; - pull_up_en = GPIO_PULLUP_ENABLE; - break; - case GpioPinDriveMode_OutputOpenSource: - mode = GPIO_MODE_OUTPUT_OD; - break; - case GpioPinDriveMode_OutputOpenSourcePullDown: - mode = GPIO_MODE_OUTPUT_OD; - pull_down_en = GPIO_PULLDOWN_ENABLE; - break; - } - - gpio_config_t GPIOConfig; - - GPIOConfig.pin_bit_mask = (1ULL << pinNumber); - GPIOConfig.mode = mode; - GPIOConfig.pull_up_en = pull_up_en; - GPIOConfig.pull_down_en = pull_down_en; - GPIOConfig.intr_type = intr_type; - - gpio_config(&GPIOConfig); - - return true; + // Valid Pin + if (!GPIO_IS_VALID_GPIO(pinNumber)) + { + return false; + } + + // Check Pin is output capable + if (driveMode >= (int)GpioPinDriveMode_Output && !GPIO_IS_VALID_OUTPUT_GPIO(pinNumber)) + { + return false; + } + + gpio_mode_t mode = GPIO_MODE_DISABLE; + gpio_pullup_t pull_up_en = GPIO_PULLUP_DISABLE; + gpio_pulldown_t pull_down_en = GPIO_PULLDOWN_DISABLE; + gpio_int_type_t intr_type = GPIO_INTR_ANYEDGE; + + switch (driveMode) + { + case GpioPinDriveMode_Input: + mode = GPIO_MODE_INPUT; + break; + case GpioPinDriveMode_InputPullDown: + mode = GPIO_MODE_INPUT; + pull_down_en = GPIO_PULLDOWN_ENABLE; + break; + case GpioPinDriveMode_InputPullUp: + mode = GPIO_MODE_INPUT; + pull_up_en = GPIO_PULLUP_ENABLE; + break; + case GpioPinDriveMode_Output: + mode = GPIO_MODE_OUTPUT; + break; + case GpioPinDriveMode_OutputOpenDrain: + mode = GPIO_MODE_OUTPUT_OD; + break; + case GpioPinDriveMode_OutputOpenDrainPullUp: + mode = GPIO_MODE_OUTPUT_OD; + pull_up_en = GPIO_PULLUP_ENABLE; + break; + case GpioPinDriveMode_OutputOpenSource: + mode = GPIO_MODE_OUTPUT_OD; + break; + case GpioPinDriveMode_OutputOpenSourcePullDown: + mode = GPIO_MODE_OUTPUT_OD; + pull_down_en = GPIO_PULLDOWN_ENABLE; + break; + } + + gpio_config_t GPIOConfig; + + GPIOConfig.pin_bit_mask = (1ULL << pinNumber); + GPIOConfig.mode = mode; + GPIOConfig.pull_up_en = pull_up_en; + GPIOConfig.pull_down_en = pull_down_en; + GPIOConfig.intr_type = intr_type; + + gpio_config(&GPIOConfig); + + return true; } bool CPU_GPIO_DriveModeSupported(GPIO_PIN pinNumber, GpioPinDriveMode driveMode) { - if (!GPIO_IS_VALID_GPIO(pinNumber)) return false; - - // Input & Output pins use any valid drivemode. - // Note: all output pins are also input pins - if (GPIO_IS_VALID_OUTPUT_GPIO(pinNumber)) - { - return (driveMode <= GpioPinDriveMode_OutputOpenSourcePullDown); - } - - // Input only pins only input drive modes - return (driveMode <= GpioPinDriveMode_InputPullUp); + if (!GPIO_IS_VALID_GPIO(pinNumber)) + return false; + + // Input & Output pins use any valid drivemode. + // Note: all output pins are also input pins + if (GPIO_IS_VALID_OUTPUT_GPIO(pinNumber)) + { + return (driveMode <= GpioPinDriveMode_OutputOpenSourcePullDown); + } + + // Input only pins only input drive modes + return (driveMode <= GpioPinDriveMode_InputPullUp); } uint32_t CPU_GPIO_GetPinDebounce(GPIO_PIN pinNumber) { - if (!GPIO_IS_VALID_GPIO(pinNumber)) return 0; + if (!GPIO_IS_VALID_GPIO(pinNumber)) + return 0; - gpio_input_state * ptr = GetInputState(pinNumber); - if (ptr) - return ptr->debounceMs; + gpio_input_state *ptr = GetInputState(pinNumber); + if (ptr) + return ptr->debounceMs; - return 0; + return 0; } bool CPU_GPIO_SetPinDebounce(GPIO_PIN pinNumber, CLR_UINT64 debounceTimeMilliseconds) { - if (!GPIO_IS_VALID_GPIO(pinNumber)) return false; - - gpio_input_state * ptr = GetInputState(pinNumber); - if (ptr) - { - ptr->debounceMs = (uint32_t)(debounceTimeMilliseconds); - return true; - } - return false; + if (!GPIO_IS_VALID_GPIO(pinNumber)) + return false; + + gpio_input_state *ptr = GetInputState(pinNumber); + if (ptr) + { + ptr->debounceMs = (uint32_t)(debounceTimeMilliseconds); + return true; + } + return false; } diff --git a/targets/TI-SimpleLink/nanoCLR/Windows.Devices.Gpio/cpu_gpio.cpp b/targets/TI-SimpleLink/nanoCLR/Windows.Devices.Gpio/cpu_gpio.cpp index 8912ded185..83abc763a8 100644 --- a/targets/TI-SimpleLink/nanoCLR/Windows.Devices.Gpio/cpu_gpio.cpp +++ b/targets/TI-SimpleLink/nanoCLR/Windows.Devices.Gpio/cpu_gpio.cpp @@ -65,7 +65,7 @@ struct gpio_input_state : public HAL_DblLinkedNode void *param; // expected state for debounce handler - bool expected; + uint_fast8_t expected; // flag for waiting for debounce timer to complete bool waitingDebounce; @@ -96,6 +96,25 @@ gpio_input_state *GetInputState(GPIO_PIN pinNumber) return NULL; } +// Get pointer to gpio_input_state for GPIO pin +// return NULL if not found +gpio_input_state *GetInputStateByConfigIndex(uint8_t pinConfigIndex) +{ + gpio_input_state *pState = gpioInputList.FirstNode(); + + while (pState->Next() != NULL) + { + if (pState->pinConfigIndex == pinConfigIndex) + { + return pState; + } + + pState = pState->Next(); + } + + return NULL; +} + // find a free slot in the pin config array int8_t FindFreePinConfig() { @@ -157,7 +176,7 @@ gpio_input_state *AllocateGpioInputState(GPIO_PIN pinNumber) gpioInputList.LinkAtBack(pState); // set the pin number in the config array - gpioPinConfigs[index] = pinNumber | GPIO_CFG_IN_NOPULL | GPIO_CFG_IN_INT_NONE; + gpioPinConfigs[index] = pinNumber | PIN_INPUT_EN | PIN_NOPULL | PIN_IRQ_DIS; } } } @@ -203,41 +222,33 @@ void DeleteGpioInputState(GPIO_PIN pinNumber) // // Debounce Handler, called when timer is complete // -static void debounceTimer_Callback(UArg arg) +static void DebounceTimerCallback(UArg arg) { - int16_t index = (int16_t)arg; + NATIVE_INTERRUPT_START - gpio_input_state *pState = GetInputState(index); + gpio_input_state *pState = GetInputStateByConfigIndex((int16_t)arg); if (pState) { - if (pState->isrPtr) + // get current pin state + uint_fast8_t pinState = GPIO_read(pState->pinConfigIndex); + + if (pinState == pState->expected) { - // get current pin state - bool actual = CPU_GPIO_GetPinState(pState->pinNumber); - if (actual == pState->expected) - { - pState->isrPtr(pState->pinNumber, actual, pState->param); - - if (pState->mode == GPIO_INT_EDGE_BOTH) - { - // both edges - // update expected state - pState->expected ^= 1; - } - } + // post a managed event with the current pin reading + pState->isrPtr(pState->pinNumber, pinState); } - } - pState->waitingDebounce = false; + pState->waitingDebounce = false; + } } -// Gpio event callback +// GPIO event callback static void GpioEventCallback(uint_least8_t index) { NATIVE_INTERRUPT_START - gpio_input_state *pState = GetInputState(index); + gpio_input_state *pState = GetInputStateByConfigIndex(index); // Any pin set up here ? if (pState != NULL) @@ -245,49 +256,28 @@ static void GpioEventCallback(uint_least8_t index) // Ignore any pin changes during debounce timeout if (!pState->waitingDebounce) { - // If calling ISR available then call it - if (pState->isrPtr) + uint_fast8_t pinState = GPIO_read(pState->pinConfigIndex); + + // Debounce time set ? + if (pState->debounceMs > 0) + { + // Yes, set up debounce timer + pState->waitingDebounce = true; + + // store expected state + pState->expected = pinState; + + // timer already exists + // set timeout as we are using a one-shot timer + Clock_setTimeout(pState->debounceTimer, pState->debounceMs * 1000 / Clock_tickPeriod); + + // start timer + Clock_start(pState->debounceTimer); + } + else { - // Debounce time set ? - if (pState->debounceMs > 0) - { - // Yes, set up debounce timer - pState->waitingDebounce = true; - - // Timer created yet ? - if (pState->debounceTimer == 0) - { - // setup timer - Clock_Params params; - - Clock_Params_init(¶ms); - params.arg = (UArg)index; - params.startFlag = false; - params.period = 0; - - // Create and start timer - pState->debounceTimer = Clock_create( - debounceTimer_Callback, - pState->debounceMs / Clock_tickPeriod, - ¶ms, - Error_IGNORE); - } - else - { - // timer already exists - // set timeout - Clock_setTimeout(pState->debounceTimer, pState->debounceMs / Clock_tickPeriod); - } - - // start timer - Clock_start(pState->debounceTimer); - } - else - { - // No debounce so just call ISR with current pin state - uint_fast8_t pinState = GPIO_read(pState->pinConfigIndex); - pState->isrPtr(pState->pinNumber, pinState, pState->param); - } + // No debounce so just post a managed event with the current pin reading + pState->isrPtr(pState->pinNumber, pinState); } } } @@ -377,11 +367,11 @@ int32_t CPU_GPIO_GetPinCount() GpioPinValue CPU_GPIO_GetPinState(GPIO_PIN pinNumber) { // get index of pin in config array - uint8_t index = FindPinConfig(pinNumber); + uint8_t pinConfigIndex = FindPinConfig(pinNumber); - if (index >= 0) + if (pinConfigIndex >= 0) { - return (GpioPinValue)GPIO_read(index); + return (GpioPinValue)GPIO_read(pinConfigIndex); } } @@ -389,22 +379,22 @@ GpioPinValue CPU_GPIO_GetPinState(GPIO_PIN pinNumber) void CPU_GPIO_SetPinState(GPIO_PIN pinNumber, GpioPinValue pinState) { // get index of pin in config array - uint8_t index = FindPinConfig(pinNumber); + uint8_t pinConfigIndex = FindPinConfig(pinNumber); - if (index >= 0) + if (pinConfigIndex >= 0) { - GPIO_write(index, pinState); + GPIO_write(pinConfigIndex, pinState); } } // Toggle pin state void CPU_GPIO_TogglePinState(GPIO_PIN pinNumber) { - uint8_t index = FindPinConfig(pinNumber); + uint8_t pinConfigIndex = FindPinConfig(pinNumber); - if (index >= 0) + if (pinConfigIndex >= 0) { - GPIO_toggle(index); + GPIO_toggle(pinConfigIndex); } } @@ -412,8 +402,8 @@ void CPU_GPIO_TogglePinState(GPIO_PIN pinNumber) bool CPU_GPIO_EnableInputPin( GPIO_PIN pinNumber, CLR_UINT64 debounceTimeMilliseconds, - GPIO_INTERRUPT_SERVICE_ROUTINE pin_ISR, - void *isr_Param, + GPIO_INTERRUPT_SERVICE_ROUTINE pinISR, + void *isrParam, GPIO_INT_EDGE intEdge, GpioPinDriveMode driveMode) { @@ -434,7 +424,7 @@ bool CPU_GPIO_EnableInputPin( // Link ISR ptr supplied and not already set up // CPU_GPIO_EnableInputPin could be called a 2nd time with changed parameters - if ((pin_ISR != NULL) && (pState->isrPtr == NULL)) + if (pinISR != NULL && (pState->isrPtr == NULL)) { // get current config GPIO_PinConfig currentPinConfig; @@ -442,33 +432,80 @@ bool CPU_GPIO_EnableInputPin( // set interrupt on both edges GPIO_setConfig(pState->pinConfigIndex, currentPinConfig | GPIO_CFG_IN_INT_BOTH_EDGES); + // set callback GPIO_setCallback(pState->pinConfigIndex, GpioEventCallback); - } + // enable INT + GPIO_enableInt(pState->pinConfigIndex); - pState->isrPtr = pin_ISR; - pState->mode = intEdge; - pState->param = (void *)isr_Param; - pState->debounceMs = (uint32_t)(debounceTimeMilliseconds); + // store parameters & configs + pState->isrPtr = pinISR; + pState->mode = intEdge; + pState->param = isrParam; + pState->debounceMs = (uint32_t)(debounceTimeMilliseconds); - switch (intEdge) - { - case GPIO_INT_EDGE_LOW: - case GPIO_INT_LEVEL_LOW: - pState->expected = false; - break; + // create timer if not there yet + if (pState->debounceMs > 0 && pState->debounceTimer == NULL) + { + // setup timer + Clock_Params params; + + Clock_Params_init(¶ms); + params.arg = (UArg)pState->pinConfigIndex; + params.startFlag = FALSE; + // period it's 0 because we are using a one-shot timer + params.period = 0; + + // create timer + // set timeout as we are using a one-shot timer + pState->debounceTimer = Clock_create( + DebounceTimerCallback, + pState->debounceMs * 1000 / Clock_tickPeriod, + ¶ms, + Error_IGNORE); + } - case GPIO_INT_EDGE_HIGH: - case GPIO_INT_LEVEL_HIGH: - pState->expected = true; - break; + switch (intEdge) + { + case GPIO_INT_EDGE_LOW: + case GPIO_INT_LEVEL_LOW: + pState->expected = false; + break; + + case GPIO_INT_EDGE_HIGH: + case GPIO_INT_LEVEL_HIGH: + pState->expected = true; + break; + + case GPIO_INT_EDGE_BOTH: + // Use inverse of current pin state + pState->expected = !CPU_GPIO_GetPinState(pState->pinConfigIndex); + break; + + default: + break; + } + } + else if (pinISR == NULL && (pState->isrPtr != NULL)) + { + // there is no managed handler setup anymore + // remove INT handler - case GPIO_INT_EDGE_BOTH: - // Use inverse of current pin state - pState->expected = !CPU_GPIO_GetPinState(pinNumber); - break; + // get current config + GPIO_PinConfig currentPinConfig; + GPIO_getConfig(pState->pinConfigIndex, ¤tPinConfig); - default: - break; + // disable interrupt + GPIO_disableInt(pState->pinConfigIndex); + // remove callback + GPIO_setCallback(pState->pinConfigIndex, NULL); + // remove interrupt config + GPIO_setConfig(pState->pinConfigIndex, currentPinConfig | GPIO_CFG_IN_INT_NONE); + + // clear parameters & configs + pState->isrPtr = NULL; + pState->mode = GPIO_INT_NONE; + pState->param = NULL; + pState->debounceMs = 0; } return true; @@ -493,16 +530,16 @@ bool CPU_GPIO_EnableOutputPin(GPIO_PIN pinNumber, GpioPinValue InitialState, Gpi DeleteGpioInputState(pinNumber); // get free slot in pin config array - uint8_t index = FindFreePinConfig(); + uint8_t pinConfigIndex = FindFreePinConfig(); - if (index >= 0) + if (pinConfigIndex >= 0) { // found a free slot! // set the pin number in the config array - gpioPinConfigs[index] = pinNumber | PIN_GPIO_OUTPUT_EN; + gpioPinConfigs[pinConfigIndex] = pinNumber | GPIO_CFG_OUT_STD; - if (CPU_GPIO_SetDriveMode(index, driveMode) == false) + if (CPU_GPIO_SetDriveMode(pinConfigIndex, driveMode) == false) { return false; } @@ -519,17 +556,17 @@ void CPU_GPIO_DisablePin(GPIO_PIN pinNumber, GpioPinDriveMode driveMode, uint32_ { GLOBAL_LOCK(); - uint8_t index = FindPinConfig(pinNumber); + uint8_t pinConfigIndex = FindPinConfig(pinNumber); - if (index >= 0) + if (pinConfigIndex >= 0) { DeleteGpioInputState(pinNumber); - CPU_GPIO_SetDriveMode(index, driveMode); + CPU_GPIO_SetDriveMode(pinConfigIndex, driveMode); if (alternateFunction) { - GPIO_setConfig(index, alternateFunction); + GPIO_setConfig(pinConfigIndex, alternateFunction); } GLOBAL_UNLOCK(); @@ -541,39 +578,40 @@ void CPU_GPIO_DisablePin(GPIO_PIN pinNumber, GpioPinDriveMode driveMode, uint32_ // Set drive mode // pinNumber is the index of the corresponding PIN config in array // return true if ok -bool CPU_GPIO_SetDriveMode(GPIO_PIN pinNumber, GpioPinDriveMode driveMode) +bool CPU_GPIO_SetDriveMode(GPIO_PIN pinConfigIndex, GpioPinDriveMode driveMode) { - // disable interrupt as default - GPIO_disableInt(pinNumber); + // get current config + GPIO_PinConfig currentPinConfig; + GPIO_getConfig(pinConfigIndex, ¤tPinConfig); switch (driveMode) { case GpioPinDriveMode_Input: - GPIO_setConfig(pinNumber, GPIO_CFG_IN_NOPULL); + GPIO_setConfig(pinConfigIndex, currentPinConfig | GPIO_CFG_IN_NOPULL); break; case GpioPinDriveMode_InputPullDown: - GPIO_setConfig(pinNumber, GPIO_CFG_IN_PD); + GPIO_setConfig(pinConfigIndex, currentPinConfig | GPIO_CFG_IN_PD); break; case GpioPinDriveMode_InputPullUp: - GPIO_setConfig(pinNumber, GPIO_CFG_IN_PU); + GPIO_setConfig(pinConfigIndex, currentPinConfig | GPIO_CFG_IN_PU); break; case GpioPinDriveMode_Output: - GPIO_setConfig(pinNumber, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_STR_MED | GPIO_CFG_OUT_LOW); + GPIO_setConfig(pinConfigIndex, currentPinConfig | GPIO_CFG_OUT_STD | GPIO_CFG_OUT_STR_MED); break; case GpioPinDriveMode_OutputOpenDrain: - GPIO_setConfig(pinNumber, GPIO_CFG_OUT_OD_NOPULL); + GPIO_setConfig(pinConfigIndex, currentPinConfig | GPIO_CFG_OUT_OD_NOPULL); break; case GpioPinDriveMode_OutputOpenDrainPullUp: - GPIO_setConfig(pinNumber, GPIO_CFG_OUT_OD_PU); + GPIO_setConfig(pinConfigIndex, currentPinConfig | GPIO_CFG_OUT_OD_PU); break; case GpioPinDriveMode_OutputOpenSourcePullDown: - GPIO_setConfig(pinNumber, GPIO_CFG_OUT_OD_PD); + GPIO_setConfig(pinConfigIndex, currentPinConfig | GPIO_CFG_OUT_OD_PD); break; default: @@ -615,9 +653,12 @@ bool CPU_GPIO_SetPinDebounce(GPIO_PIN pinNumber, CLR_UINT64 debounceTimeMillisec { gpio_input_state *pState = GetInputState(pinNumber); - _ASSERTE(pState == NULL); - - pState->debounceMs = (uint32_t)(debounceTimeMilliseconds); + // can only change the debounce in pin state if the pin has already been configured as input + // if not, doesn't matter, because the new debounce will be used next time it's required + if (pState != NULL) + { + pState->debounceMs = (uint32_t)(debounceTimeMilliseconds); + } return true; }