diff --git a/src/CLR/Core/CLR_RT_StackFrame.cpp b/src/CLR/Core/CLR_RT_StackFrame.cpp index cf5eb34fda..3ad15dd10e 100644 --- a/src/CLR/Core/CLR_RT_StackFrame.cpp +++ b/src/CLR/Core/CLR_RT_StackFrame.cpp @@ -1112,7 +1112,8 @@ void CLR_RT_StackFrame::NegateResult() //--// -// input HeapBlock has timeout value in ticks +// input HeapBlock has timeout value **IN TICKS** +// sometimes you have to force a cast to (CLR_INT64) otherwise the set operations will fail because of the var size mismatch HRESULT CLR_RT_StackFrame::SetupTimeoutFromTicks( CLR_RT_HeapBlock& input, CLR_INT64*& output ) { NATIVE_PROFILE_CLR_CORE(); diff --git a/src/CLR/Core/Hardware/Hardware.cpp b/src/CLR/Core/Hardware/Hardware.cpp index 62986e59f1..9c8fb2cf12 100644 --- a/src/CLR/Core/Hardware/Hardware.cpp +++ b/src/CLR/Core/Hardware/Hardware.cpp @@ -153,9 +153,9 @@ void CLR_HW_Hardware::ProcessActivity() eventsCLR |= CLR_RT_ExecutionEngine::c_Event_Socket; } - if(events & SYSTEM_EVENT_FLAG_IO) + if(events & SYSTEM_EVENT_FLAG_I2C_MASTER) { - eventsCLR |= CLR_RT_ExecutionEngine::c_Event_IO; + eventsCLR |= CLR_RT_ExecutionEngine::c_Event_I2cMaster; } if(eventsCLR) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 9cd87831b4..cbf9134d63 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -2655,6 +2655,8 @@ static const TypeIndexLookup c_TypeIndexLookup[] = TIL( "System.Net.Sockets" , "SocketException" , m_SocketException ), + TIL( "Windows.Devices.I2c" , "I2cTransferResult" , m_I2cTransferResult ), + #undef TIL }; diff --git a/src/CLR/Include/nanoCLR_Hardware.h b/src/CLR/Include/nanoCLR_Hardware.h index 90a2397797..2e5d89487f 100644 --- a/src/CLR/Include/nanoCLR_Hardware.h +++ b/src/CLR/Include/nanoCLR_Hardware.h @@ -58,11 +58,11 @@ struct CLR_HW_Hardware static const CLR_UINT32 c_Default_WakeupEvents = SYSTEM_EVENT_FLAG_COM_IN | SYSTEM_EVENT_FLAG_COM_OUT | SYSTEM_EVENT_FLAG_SYSTEM_TIMER | + SYSTEM_EVENT_FLAG_I2C_MASTER | SYSTEM_EVENT_HW_INTERRUPT | SYSTEM_EVENT_FLAG_SOCKET | SYSTEM_EVENT_FLAG_DEBUGGER_ACTIVITY | - SYSTEM_EVENT_FLAG_MESSAGING_ACTIVITY| - SYSTEM_EVENT_FLAG_IO ; + SYSTEM_EVENT_FLAG_MESSAGING_ACTIVITY; //--// diff --git a/src/CLR/Include/nanoCLR_Runtime.h b/src/CLR/Include/nanoCLR_Runtime.h index dd57d48699..4d75aaba76 100644 --- a/src/CLR/Include/nanoCLR_Runtime.h +++ b/src/CLR/Include/nanoCLR_Runtime.h @@ -1238,6 +1238,8 @@ struct CLR_RT_WellKnownTypes CLR_RT_TypeDef_Index m_SocketException; + CLR_RT_TypeDef_Index m_I2cTransferResult; + PROHIBIT_COPY_CONSTRUCTORS(CLR_RT_WellKnownTypes); }; @@ -2727,14 +2729,14 @@ extern bool g_CLR_RT_fBadStack; struct CLR_RT_ExecutionEngine { - static const CLR_UINT32 c_Event_SerialPortIn = 0x00000002; - static const CLR_UINT32 c_Event_SerialPortOut = 0x00000004; - static const CLR_UINT32 c_Event_EndPoint = 0x00000008; - static const CLR_UINT32 c_Event_IO = 0x00000080; - static const CLR_UINT32 c_Event_AppDomain = 0x02000000; - static const CLR_UINT32 c_Event_Socket = 0x20000000; - static const CLR_UINT32 c_Event_IdleCPU = 0x40000000; - static const CLR_UINT32 c_Event_LowMemory = 0x80000000; // Wait for a low-memory condition. + static const CLR_UINT32 c_Event_SerialPortIn = 0x00000002; + static const CLR_UINT32 c_Event_SerialPortOut = 0x00000004; + static const CLR_UINT32 c_Event_EndPoint = 0x00000008; + static const CLR_UINT32 c_Event_I2cMaster = 0x00000080; + static const CLR_UINT32 c_Event_AppDomain = 0x02000000; + static const CLR_UINT32 c_Event_Socket = 0x20000000; + static const CLR_UINT32 c_Event_IdleCPU = 0x40000000; + static const CLR_UINT32 c_Event_LowMemory = 0x80000000; // Wait for a low-memory condition. //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/HAL/Include/nanoHAL_v2.h b/src/HAL/Include/nanoHAL_v2.h index 3c1c26daa1..106265e028 100644 --- a/src/HAL/Include/nanoHAL_v2.h +++ b/src/HAL/Include/nanoHAL_v2.h @@ -48,7 +48,7 @@ typedef enum SLEEP_LEVEL //#define SYSTEM_EVENT_FLAG_SPI 0x00008000 //#define SYSTEM_EVENT_FLAG_OEM_RESERVED_1 0x00020000 //#define SYSTEM_EVENT_FLAG_OEM_RESERVED_2 0x00040000 -#define SYSTEM_EVENT_FLAG_IO 0x00080000 +//#define SYSTEM_EVENT_FLAG_UNUSED_0x00080000 0x00080000 //#define SYSTEM_EVENT_FLAG_UNUSED_0x00100000 0x00100000 @@ -63,6 +63,7 @@ typedef enum SLEEP_LEVEL //#define SYSTEM_EVENT_FLAG_UNUSED_0x01000000 0x01000000 //#define SYSTEM_EVENT_FLAG_UNUSED_0x02000000 0x02000000 //#define SYSTEM_EVENT_FLAG_UNUSED_0x04000000 0x04000000 +#define SYSTEM_EVENT_FLAG_I2C_MASTER 0x04000000 #define SYSTEM_EVENT_HW_INTERRUPT 0x08000000 #define SYSTEM_EVENT_FLAG_DEBUGGER_ACTIVITY 0x20000000 #define SYSTEM_EVENT_FLAG_MESSAGING_ACTIVITY 0x40000000 diff --git a/targets/CMSIS-OS/ChibiOS/MBN_QUAIL/CMakeLists.txt b/targets/CMSIS-OS/ChibiOS/MBN_QUAIL/CMakeLists.txt index 8e9132b74c..5d9eb3568e 100644 --- a/targets/CMSIS-OS/ChibiOS/MBN_QUAIL/CMakeLists.txt +++ b/targets/CMSIS-OS/ChibiOS/MBN_QUAIL/CMakeLists.txt @@ -50,6 +50,11 @@ endif() # sources for target specifc stuff related with APIs list(APPEND API_RELATED_TARGET_SOURCES "") +# Windows.Devices.I2c +if(API_Windows.Devices.I2c) + list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_i2c_config.cpp") +endif() + # Windows.Devices.SerialCommunication if(API_Windows.Devices.SerialCommunication) list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_serialcommunication_config.cpp") diff --git a/targets/CMSIS-OS/ChibiOS/MBN_QUAIL/target_windows_devices_i2c_config.cpp b/targets/CMSIS-OS/ChibiOS/MBN_QUAIL/target_windows_devices_i2c_config.cpp new file mode 100644 index 0000000000..c3a4e92bcc --- /dev/null +++ b/targets/CMSIS-OS/ChibiOS/MBN_QUAIL/target_windows_devices_i2c_config.cpp @@ -0,0 +1,34 @@ +// +// Copyright (c) 2018 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +#include "win_dev_i2c_native.h" + +////////// +// I2C1 // +////////// + +// buffers size +// tx buffer size (in bytes) +#define I2C1_WR_SIZE 100 +// rx buffer size (in bytes) +#define I2C1_RD_SIZE 100 + +// buffers declaration +// buffers that are R/W by DMA are recommended to be aligned with 32 bytes cache page size boundary +// because of issues with cache coherency and DMA (this is particularly important with Cortex-M7 because of cache) +#if defined(__GNUC__) +__attribute__((aligned (32))) +#endif +uint8_t I2C1_WriteBuffer[I2C1_WR_SIZE]; +#if defined(__GNUC__) +__attribute__((aligned (32))) +#endif +uint8_t I2C1_ReadBuffer[I2C1_RD_SIZE]; + +// initialization for I2C1 +I2C_INIT(1, I2C1_WR_SIZE, I2C1_RD_SIZE) + +// un-initialization for I2C1 +I2C_UNINIT(1) diff --git a/targets/CMSIS-OS/ChibiOS/NETDUINO3_WIFI/CMakeLists.txt b/targets/CMSIS-OS/ChibiOS/NETDUINO3_WIFI/CMakeLists.txt index 084eff8612..6097c051ca 100644 --- a/targets/CMSIS-OS/ChibiOS/NETDUINO3_WIFI/CMakeLists.txt +++ b/targets/CMSIS-OS/ChibiOS/NETDUINO3_WIFI/CMakeLists.txt @@ -50,16 +50,21 @@ endif() # sources for target specifc stuff related with APIs list(APPEND API_RELATED_TARGET_SOURCES "") -# Windows.Devices.SerialCommunication -if(API_Windows.Devices.SerialCommunication) - list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_serialcommunication_config.cpp") -endif() - # Windows.Devices.Adc if(API_Windows.Devices.Adc) list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_adc_config.cpp") endif() +# Windows.Devices.I2c +if(API_Windows.Devices.I2c) + list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_i2c_config.cpp") +endif() + +# Windows.Devices.SerialCommunication +if(API_Windows.Devices.SerialCommunication) + list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_serialcommunication_config.cpp") +endif() + ####################################### add_subdirectory("common") diff --git a/targets/CMSIS-OS/ChibiOS/NETDUINO3_WIFI/target_windows_devices_i2c_config.cpp b/targets/CMSIS-OS/ChibiOS/NETDUINO3_WIFI/target_windows_devices_i2c_config.cpp new file mode 100644 index 0000000000..c3a4e92bcc --- /dev/null +++ b/targets/CMSIS-OS/ChibiOS/NETDUINO3_WIFI/target_windows_devices_i2c_config.cpp @@ -0,0 +1,34 @@ +// +// Copyright (c) 2018 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +#include "win_dev_i2c_native.h" + +////////// +// I2C1 // +////////// + +// buffers size +// tx buffer size (in bytes) +#define I2C1_WR_SIZE 100 +// rx buffer size (in bytes) +#define I2C1_RD_SIZE 100 + +// buffers declaration +// buffers that are R/W by DMA are recommended to be aligned with 32 bytes cache page size boundary +// because of issues with cache coherency and DMA (this is particularly important with Cortex-M7 because of cache) +#if defined(__GNUC__) +__attribute__((aligned (32))) +#endif +uint8_t I2C1_WriteBuffer[I2C1_WR_SIZE]; +#if defined(__GNUC__) +__attribute__((aligned (32))) +#endif +uint8_t I2C1_ReadBuffer[I2C1_RD_SIZE]; + +// initialization for I2C1 +I2C_INIT(1, I2C1_WR_SIZE, I2C1_RD_SIZE) + +// un-initialization for I2C1 +I2C_UNINIT(1) diff --git a/targets/CMSIS-OS/ChibiOS/ST_NUCLEO144_F746ZG/CMakeLists.txt b/targets/CMSIS-OS/ChibiOS/ST_NUCLEO144_F746ZG/CMakeLists.txt index d2168efd38..fba295980f 100644 --- a/targets/CMSIS-OS/ChibiOS/ST_NUCLEO144_F746ZG/CMakeLists.txt +++ b/targets/CMSIS-OS/ChibiOS/ST_NUCLEO144_F746ZG/CMakeLists.txt @@ -51,16 +51,21 @@ endif() # sources for target specifc stuff related with APIs list(APPEND API_RELATED_TARGET_SOURCES "") -# Windows.Devices.SerialCommunication -if(API_Windows.Devices.SerialCommunication) - list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_serialcommunication_config.cpp") -endif() - # Windows.Devices.Adc if(API_Windows.Devices.Adc) list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_adc_config.cpp") endif() +# Windows.Devices.I2c +if(API_Windows.Devices.I2c) + list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_i2c_config.cpp") +endif() + +# Windows.Devices.SerialCommunication +if(API_Windows.Devices.SerialCommunication) + list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_serialcommunication_config.cpp") +endif() + ####################################### add_subdirectory("common") diff --git a/targets/CMSIS-OS/ChibiOS/ST_NUCLEO144_F746ZG/target_windows_devices_i2c_config.cpp b/targets/CMSIS-OS/ChibiOS/ST_NUCLEO144_F746ZG/target_windows_devices_i2c_config.cpp new file mode 100644 index 0000000000..4b4ced0e3c --- /dev/null +++ b/targets/CMSIS-OS/ChibiOS/ST_NUCLEO144_F746ZG/target_windows_devices_i2c_config.cpp @@ -0,0 +1,62 @@ +// +// Copyright (c) 2018 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +#include "win_dev_i2c_native.h" + +////////// +// I2C1 // +////////// + +// buffers size +// tx buffer size (in bytes) +#define I2C1_WR_SIZE 100 +// rx buffer size (in bytes) +#define I2C1_RD_SIZE 100 + +// buffers declaration +// buffers that are R/W by DMA are recommended to be aligned with 32 bytes cache page size boundary +// because of issues with cache coherency and DMA (this is particularly important with Cortex-M7 because of cache) +#if defined(__GNUC__) +__attribute__((aligned (32))) +#endif +uint8_t I2C1_WriteBuffer[I2C1_WR_SIZE]; +#if defined(__GNUC__) +__attribute__((aligned (32))) +#endif +uint8_t I2C1_ReadBuffer[I2C1_RD_SIZE]; + +// initialization for I2C1 +I2C_INIT(1, I2C1_WR_SIZE, I2C1_RD_SIZE) + +// un-initialization for I2C1 +I2C_UNINIT(1) + +////////// +// I2C2 // +////////// + +// buffers size +// tx buffer size (in bytes) +#define I2C2_WR_SIZE 100 +// rx buffer size (in bytes) +#define I2C2_RD_SIZE 100 + +// buffers declaration +// buffers that are R/W by DMA are recommended to be aligned with 32 bytes cache page size boundary +// because of issues with cache coherency and DMA (this is particularly important with Cortex-M7 because of cache) +#if defined(__GNUC__) +__attribute__((aligned (32))) +#endif +uint8_t I2C2_WriteBuffer[I2C2_WR_SIZE]; +#if defined(__GNUC__) +__attribute__((aligned (32))) +#endif +uint8_t I2C2_ReadBuffer[I2C2_RD_SIZE]; + +// initialization for I2C2 +I2C_INIT(2, I2C2_WR_SIZE, I2C2_RD_SIZE) + +// un-initialization for I2C2 +I2C_UNINIT(2) diff --git a/targets/CMSIS-OS/ChibiOS/ST_STM32F429I_DISCOVERY/CMakeLists.txt b/targets/CMSIS-OS/ChibiOS/ST_STM32F429I_DISCOVERY/CMakeLists.txt index 05bc518ccf..05361a3b5e 100644 --- a/targets/CMSIS-OS/ChibiOS/ST_STM32F429I_DISCOVERY/CMakeLists.txt +++ b/targets/CMSIS-OS/ChibiOS/ST_STM32F429I_DISCOVERY/CMakeLists.txt @@ -50,16 +50,21 @@ endif() # sources for target specifc stuff related with APIs list(APPEND API_RELATED_TARGET_SOURCES "") -# Windows.Devices.SerialCommunication -if(API_Windows.Devices.SerialCommunication) - list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_serialcommunication_config.cpp") -endif() - # Windows.Devices.Adc if(API_Windows.Devices.Adc) list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_adc_config.cpp") endif() +# Windows.Devices.I2c +if(API_Windows.Devices.I2c) + list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_i2c_config.cpp") +endif() + +# Windows.Devices.SerialCommunication +if(API_Windows.Devices.SerialCommunication) + list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_serialcommunication_config.cpp") +endif() + ####################################### add_subdirectory("common") diff --git a/targets/CMSIS-OS/ChibiOS/ST_STM32F429I_DISCOVERY/target_windows_devices_i2c_config.cpp b/targets/CMSIS-OS/ChibiOS/ST_STM32F429I_DISCOVERY/target_windows_devices_i2c_config.cpp new file mode 100644 index 0000000000..b57e1c5f04 --- /dev/null +++ b/targets/CMSIS-OS/ChibiOS/ST_STM32F429I_DISCOVERY/target_windows_devices_i2c_config.cpp @@ -0,0 +1,34 @@ +// +// Copyright (c) 2018 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +#include "win_dev_i2c_native.h" + +////////// +// I2C3 // +////////// + +// buffers size +// write buffer size (in bytes) +#define I2C3_WR_SIZE 100 +// read buffer size (in bytes) +#define I2C3_RD_SIZE 100 + +// buffers declaration +// buffers that are R/W by DMA are recommended to be aligned with 32 bytes cache page size boundary +// because of issues with cache coherency and DMA (this is particularly important with Cortex-M7 because of cache) +#if defined(__GNUC__) +__attribute__((aligned (32))) +#endif +uint8_t I2C3_WriteBuffer[I2C3_WR_SIZE]; +#if defined(__GNUC__) +__attribute__((aligned (32))) +#endif +uint8_t I2C3_ReadBuffer[I2C3_RD_SIZE]; + +// initialization of I2C3 PAL structure +I2C_INIT(3, I2C3_WR_SIZE, I2C3_RD_SIZE) + +// un-initialization of I2C3 PAL structure +I2C_UNINIT(3) diff --git a/targets/CMSIS-OS/ChibiOS/ST_STM32F4_DISCOVERY/CMakeLists.txt b/targets/CMSIS-OS/ChibiOS/ST_STM32F4_DISCOVERY/CMakeLists.txt index 9e05387296..2a25efae99 100644 --- a/targets/CMSIS-OS/ChibiOS/ST_STM32F4_DISCOVERY/CMakeLists.txt +++ b/targets/CMSIS-OS/ChibiOS/ST_STM32F4_DISCOVERY/CMakeLists.txt @@ -50,16 +50,21 @@ endif() # sources for target specifc stuff related with APIs list(APPEND API_RELATED_TARGET_SOURCES "") -# Windows.Devices.SerialCommunication -if(API_Windows.Devices.SerialCommunication) - list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_serialcommunication_config.cpp") -endif() - # Windows.Devices.Adc if(API_Windows.Devices.Adc) list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_adc_config.cpp") endif() +# Windows.Devices.I2c +if(API_Windows.Devices.I2c) + list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_i2c_config.cpp") +endif() + +# Windows.Devices.SerialCommunication +if(API_Windows.Devices.SerialCommunication) + list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_serialcommunication_config.cpp") +endif() + ####################################### add_subdirectory("common") diff --git a/targets/CMSIS-OS/ChibiOS/ST_STM32F4_DISCOVERY/target_windows_devices_i2c_config.cpp b/targets/CMSIS-OS/ChibiOS/ST_STM32F4_DISCOVERY/target_windows_devices_i2c_config.cpp new file mode 100644 index 0000000000..c3a4e92bcc --- /dev/null +++ b/targets/CMSIS-OS/ChibiOS/ST_STM32F4_DISCOVERY/target_windows_devices_i2c_config.cpp @@ -0,0 +1,34 @@ +// +// Copyright (c) 2018 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +#include "win_dev_i2c_native.h" + +////////// +// I2C1 // +////////// + +// buffers size +// tx buffer size (in bytes) +#define I2C1_WR_SIZE 100 +// rx buffer size (in bytes) +#define I2C1_RD_SIZE 100 + +// buffers declaration +// buffers that are R/W by DMA are recommended to be aligned with 32 bytes cache page size boundary +// because of issues with cache coherency and DMA (this is particularly important with Cortex-M7 because of cache) +#if defined(__GNUC__) +__attribute__((aligned (32))) +#endif +uint8_t I2C1_WriteBuffer[I2C1_WR_SIZE]; +#if defined(__GNUC__) +__attribute__((aligned (32))) +#endif +uint8_t I2C1_ReadBuffer[I2C1_RD_SIZE]; + +// initialization for I2C1 +I2C_INIT(1, I2C1_WR_SIZE, I2C1_RD_SIZE) + +// un-initialization for I2C1 +I2C_UNINIT(1) diff --git a/targets/CMSIS-OS/ChibiOS/ST_STM32F769I_DISCOVERY/CMakeLists.txt b/targets/CMSIS-OS/ChibiOS/ST_STM32F769I_DISCOVERY/CMakeLists.txt index 508a72be33..f8aaeed79c 100644 --- a/targets/CMSIS-OS/ChibiOS/ST_STM32F769I_DISCOVERY/CMakeLists.txt +++ b/targets/CMSIS-OS/ChibiOS/ST_STM32F769I_DISCOVERY/CMakeLists.txt @@ -51,16 +51,21 @@ endif() # sources for target specifc stuff related with APIs list(APPEND API_RELATED_TARGET_SOURCES "") -# Windows.Devices.SerialCommunication -if(API_Windows.Devices.SerialCommunication) - list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_serialcommunication_config.cpp") -endif() - # Windows.Devices.Adc if(API_Windows.Devices.Adc) list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_adc_config.cpp") endif() +# Windows.Devices.I2c +if(API_Windows.Devices.I2c) + list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_i2c_config.cpp") +endif() + +# Windows.Devices.SerialCommunication +if(API_Windows.Devices.SerialCommunication) + list(APPEND API_RELATED_TARGET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_windows_devices_serialcommunication_config.cpp") +endif() + ####################################### add_subdirectory("common") diff --git a/targets/CMSIS-OS/ChibiOS/ST_STM32F769I_DISCOVERY/target_windows_devices_i2c_config.cpp b/targets/CMSIS-OS/ChibiOS/ST_STM32F769I_DISCOVERY/target_windows_devices_i2c_config.cpp new file mode 100644 index 0000000000..c3a4e92bcc --- /dev/null +++ b/targets/CMSIS-OS/ChibiOS/ST_STM32F769I_DISCOVERY/target_windows_devices_i2c_config.cpp @@ -0,0 +1,34 @@ +// +// Copyright (c) 2018 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +#include "win_dev_i2c_native.h" + +////////// +// I2C1 // +////////// + +// buffers size +// tx buffer size (in bytes) +#define I2C1_WR_SIZE 100 +// rx buffer size (in bytes) +#define I2C1_RD_SIZE 100 + +// buffers declaration +// buffers that are R/W by DMA are recommended to be aligned with 32 bytes cache page size boundary +// because of issues with cache coherency and DMA (this is particularly important with Cortex-M7 because of cache) +#if defined(__GNUC__) +__attribute__((aligned (32))) +#endif +uint8_t I2C1_WriteBuffer[I2C1_WR_SIZE]; +#if defined(__GNUC__) +__attribute__((aligned (32))) +#endif +uint8_t I2C1_ReadBuffer[I2C1_RD_SIZE]; + +// initialization for I2C1 +I2C_INIT(1, I2C1_WR_SIZE, I2C1_RD_SIZE) + +// un-initialization for I2C1 +I2C_UNINIT(1) diff --git a/targets/CMSIS-OS/ChibiOS/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native.cpp b/targets/CMSIS-OS/ChibiOS/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native.cpp index a77967c947..f5a4d9812d 100644 --- a/targets/CMSIS-OS/ChibiOS/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native.cpp +++ b/targets/CMSIS-OS/ChibiOS/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native.cpp @@ -1,3 +1,8 @@ +// +// Copyright (c) 2017 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + #include "win_dev_i2c_native.h" @@ -17,9 +22,6 @@ static const CLR_RT_MethodHandler method_lookup[] = NULL, NULL, NULL, - Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeInit___VOID, - Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::DisposeNative___VOID, - Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeTransmit___I4__SZARRAY_U1__U4__SZARRAY_U1__U4, NULL, NULL, NULL, @@ -30,6 +32,10 @@ static const CLR_RT_MethodHandler method_lookup[] = NULL, NULL, NULL, + Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeInit___VOID, + Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::DisposeNative___VOID, + Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeTransmit___WindowsDevicesI2cI2cTransferResult__SZARRAY_U1__SZARRAY_U1, + NULL, NULL, Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::GetDeviceSelector___STATIC__STRING, NULL, @@ -38,12 +44,14 @@ static const CLR_RT_MethodHandler method_lookup[] = NULL, NULL, NULL, + NULL, + NULL, + NULL, }; const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_Windows_Devices_I2c = { "Windows.Devices.I2c", - 0xC5ABF45E, + 0xA170B1E0, method_lookup }; - diff --git a/targets/CMSIS-OS/ChibiOS/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native.h b/targets/CMSIS-OS/ChibiOS/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native.h index 3c805ca2a3..e4d4e794e1 100644 --- a/targets/CMSIS-OS/ChibiOS/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native.h +++ b/targets/CMSIS-OS/ChibiOS/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native.h @@ -1,15 +1,7 @@ -//----------------------------------------------------------------------------- // -// ** WARNING! ** -// This file was generated automatically by a tool. -// Re-running the tool will overwrite this file. -// You should copy this file to a custom location -// before adding any customization in the copy to -// prevent loss of your changes when the tool is -// re-run. +// Copyright (c) 2017 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. // -//----------------------------------------------------------------------------- - #ifndef _WIN_DEV_I2C_NATIVE_H_ #define _WIN_DEV_I2C_NATIVE_H_ @@ -19,13 +11,6 @@ #include #include -struct nfI2CConfig -{ - I2CConfig Configuration; - I2CDriver * Driver; - uint16_t SlaveAddress; -}; - struct Library_win_dev_i2c_native_Windows_Devices_I2c_I2cConnectionSettings { static const int FIELD___slaveAddress = 1; @@ -39,7 +24,8 @@ struct Library_win_dev_i2c_native_Windows_Devices_I2c_I2cConnectionSettings struct Library_win_dev_i2c_native_Windows_Devices_I2c_I2cController { - static const int FIELD_STATIC__DeviceCollection = 0; + static const int FIELD_STATIC__s_instance = 0; + static const int FIELD_STATIC__s_deviceCollection = 1; //--// @@ -51,28 +37,104 @@ struct Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice static const int FIELD___syncLock = 1; static const int FIELD___deviceId = 2; static const int FIELD___connectionSettings = 3; - static const int FIELD___i2cBus = 4; - static const int FIELD___disposedValue = 5; + static const int FIELD___disposed = 4; NANOCLR_NATIVE_DECLARE(NativeInit___VOID); NANOCLR_NATIVE_DECLARE(DisposeNative___VOID); - NANOCLR_NATIVE_DECLARE(NativeTransmit___I4__SZARRAY_U1__U4__SZARRAY_U1__U4); + NANOCLR_NATIVE_DECLARE(NativeTransmit___WindowsDevicesI2cI2cTransferResult__SZARRAY_U1__SZARRAY_U1); NANOCLR_NATIVE_DECLARE(GetDeviceSelector___STATIC__STRING); //--// - static nfI2CConfig GetConfig(int bus, CLR_RT_HeapBlock* config); + static void GetConfig(CLR_RT_HeapBlock* managedConfig, I2CConfig* llConfig); }; struct Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult { - static const int FIELD__BytesTransferred = 1; - static const int FIELD__Status = 2; + static const int FIELD___bytesTransferred = 1; + static const int FIELD___status = 2; //--// }; - extern const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_Windows_Devices_I2c; +extern const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_Windows_Devices_I2c; + +// struct representing the I2C +struct NF_PAL_I2C +{ + I2CDriver* Driver; + I2CConfig Configuration; + thread_t* WorkingThread; + i2caddr_t Address; + + uint8_t* WriteBuffer; + uint8_t WriteSize; + + uint8_t* ReadBuffer; + uint8_t ReadSize; +}; + +/////////////////////////////////////////// +// declaration of the the I2C PAL strucs // +/////////////////////////////////////////// +#if STM32_I2C_USE_I2C1 + extern NF_PAL_I2C I2C1_PAL; +#endif +#if STM32_I2C_USE_I2C2 + extern NF_PAL_I2C I2C2_PAL; +#endif +#if STM32_I2C_USE_I2C3 + extern NF_PAL_I2C I2C3_PAL; +#endif +#if STM32_I2C_USE_I2C4 + extern NF_PAL_I2C I2C4_PAL; +#endif + + +///////////////////////////////////// +// I2C Tx buffers // +// these live in the target folder // +///////////////////////////////////// +extern uint8_t I2C1_WriteBuffer[]; +extern uint8_t I2C2_WriteBuffer[]; +extern uint8_t I2C3_WriteBuffer[]; +extern uint8_t I2C4_WriteBuffer[]; + + +///////////////////////////////////// +// I2C Rx buffers // +// these live in the target folder // +///////////////////////////////////// +extern uint8_t I2C1_ReadBuffer[]; +extern uint8_t I2C2_ReadBuffer[]; +extern uint8_t I2C3_ReadBuffer[]; +extern uint8_t I2C4_ReadBuffer[]; + + +// the following macro defines a function that initializes an I2C struct +// it gets called in the Windows_Devices_I2c_I2cDevice::NativeInit function +#define I2C_INIT(num, tx_buffer_size, rx_buffer_size) void Init_I2C##num() { \ + I2C##num##_PAL.WriteBuffer = I2C##num##_WriteBuffer; \ + I2C##num##_PAL.ReadBuffer = I2C##num##_ReadBuffer; \ +} + +// when a I2C is defined the declarations bellow will have the real function/configuration +// in the target folder @ target_windows_devices_i2c_config.cpp +void Init_I2C1(); +void Init_I2C2(); +void Init_I2C3(); +void Init_I2C4(); + +// the following macro defines a function that un initializes an I2C struct +// it gets called in the Windows_Devices_I2c_I2cDevice::NativeDispose function +#define I2C_UNINIT(num) void UnInit_I2C##num() { return; } + +// when a I2C is defined the declarations bellow will have the real function/configuration +// in the target folder @ target_windows_devices_i2c_config.cpp +void UnInit_I2C1(); +void UnInit_I2C2(); +void UnInit_I2C3(); +void UnInit_I2C4(); #endif //_WIN_DEV_I2C_NATIVE_H_ diff --git a/targets/CMSIS-OS/ChibiOS/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native_Windows_Devices_I2C_I2cDevice.cpp b/targets/CMSIS-OS/ChibiOS/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native_Windows_Devices_I2C_I2cDevice.cpp index 0d102231f4..33c35a406d 100644 --- a/targets/CMSIS-OS/ChibiOS/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native_Windows_Devices_I2C_I2cDevice.cpp +++ b/targets/CMSIS-OS/ChibiOS/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native_Windows_Devices_I2C_I2cDevice.cpp @@ -5,196 +5,426 @@ #include #include -#include #include #include - +#include #include "win_dev_i2c_native.h" +#define I2C_TRANSACTION_TIMEOUT_MS 1000 + /////////////////////////////////////////////////////////////////////////////////////// // !!! KEEP IN SYNC WITH Windows.Devices.I2c.I2cSharingMode (in managed code) !!! // /////////////////////////////////////////////////////////////////////////////////////// enum I2cSharingMode - { - Exclusive = 0, - Shared - }; +{ + Exclusive = 0, + Shared +}; /////////////////////////////////////////////////////////////////////////////////////// // !!! KEEP IN SYNC WITH Windows.Devices.I2c.I2cTransferStatus (in managed code) !!! // /////////////////////////////////////////////////////////////////////////////////////// enum I2cTransferStatus - { - I2cTransferStatus_FullTransfer = 0, - I2cTransferStatus_ClockStretchTimeout, - I2cTransferStatus_PartialTransfer, - I2cTransferStatus_SlaveAddressNotAcknowledged, - I2cTransferStatus_UnknownError - }; +{ + I2cTransferStatus_FullTransfer = 0, + I2cTransferStatus_ClockStretchTimeout, + I2cTransferStatus_PartialTransfer, + I2cTransferStatus_SlaveAddressNotAcknowledged, + I2cTransferStatus_UnknownError +}; /////////////////////////////////////////////////////////////////////////////////////// // !!! KEEP IN SYNC WITH Windows.Devices.I2c.I2cBusSpeed (in managed code) !!! // /////////////////////////////////////////////////////////////////////////////////////// enum I2cBusSpeed - { - I2cBusSpeed_StandardMode = 0, - I2cBusSpeed_FastMode - }; +{ + I2cBusSpeed_StandardMode = 0, + I2cBusSpeed_FastMode +}; typedef Library_win_dev_i2c_native_Windows_Devices_I2c_I2cConnectionSettings I2cConnectionSettings; -nfI2CConfig Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::GetConfig(int bus, CLR_RT_HeapBlock* config) -{ - I2CDriver * _drv; - - int slaveAddress = config[ I2cConnectionSettings::FIELD___slaveAddress ].NumericByRef().s4; - int busSpeed = config[ I2cConnectionSettings::FIELD___busSpeed ].NumericByRef().s4; - // Choose the driver that is mapped to the chosen bus - switch (bus) - { +///////////////////////////////////////////////////// +// I2C PAL strucs declared in win_dev_i2c_native.h // +///////////////////////////////////////////////////// #if STM32_I2C_USE_I2C1 - case 1 : _drv = &I2CD1; - break; + NF_PAL_I2C I2C1_PAL; #endif #if STM32_I2C_USE_I2C2 - case 2 : _drv = &I2CD2; - break; + NF_PAL_I2C I2C2_PAL; #endif #if STM32_I2C_USE_I2C3 - case 3 : _drv = &I2CD3; - break; + NF_PAL_I2C I2C3_PAL; #endif #if STM32_I2C_USE_I2C4 - case 4 : _drv = &I2CD4; - break; + NF_PAL_I2C I2C4_PAL; #endif - } - // Create the final configuration - nfI2CConfig cfg = + +// ChibiOS I2C working thread +static THD_FUNCTION(I2CWorkingThread, arg) +{ + NF_PAL_I2C* palI2c = (NF_PAL_I2C*)arg; + msg_t result; + + // because the bus access is shared, acquire the appropriate bus + i2cStart(palI2c->Driver, &palI2c->Configuration); + i2cAcquireBus(palI2c->Driver); + + if (palI2c->ReadSize != 0 && palI2c->WriteSize != 0) + { + // this is a Write/Read transaction + result = i2cMasterTransmitTimeout(palI2c->Driver, palI2c->Address, palI2c->WriteBuffer, palI2c->WriteSize, palI2c->ReadBuffer, palI2c->ReadSize, I2C_TRANSACTION_TIMEOUT_MS); + } + else { + if (palI2c->ReadSize == 0) { -#ifdef STM32F4xx_MCUCONF - OPMODE_I2C, - busSpeed == I2cBusSpeed_StandardMode ? 100000U : 400000U, - busSpeed == I2cBusSpeed_StandardMode ? STD_DUTY_CYCLE : FAST_DUTY_CYCLE_2 -#endif -#ifdef STM32F7xx_MCUCONF - // Standard mode : 100 KHz, Rise time 120 ns, Fall time 25 ns, 54MHz clock source - // Fast mode : 400 KHz, Rise time 120 ns, Fall time 25 ns, 54MHz clock source - // Timing register value calculated by STM32 CubeMx - busSpeed == I2cBusSpeed_StandardMode ? 0x80201721 : 0x00B01B59, - 0, - 0 -#endif - }, - _drv, - (uint16_t)slaveAddress - }; + // this is Write only transaction + result = i2cMasterTransmitTimeout(palI2c->Driver, palI2c->Address, palI2c->WriteBuffer, palI2c->WriteSize, NULL, 0, I2C_TRANSACTION_TIMEOUT_MS); + } + else + { + // this is a Read only transaction + result = i2cMasterReceiveTimeout (palI2c->Driver, palI2c->Address, palI2c->ReadBuffer, palI2c->ReadSize, I2C_TRANSACTION_TIMEOUT_MS); + } + } + + i2cReleaseBus(palI2c->Driver); + + // fire event for I2C transaction complete + Events_Set(SYSTEM_EVENT_FLAG_I2C_MASTER); + + chThdExit(result); +} + +void Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::GetConfig(CLR_RT_HeapBlock* managedConfig, I2CConfig* llConfig) +{ + I2cBusSpeed busSpeed = (I2cBusSpeed)managedConfig[ I2cConnectionSettings::FIELD___busSpeed ].NumericByRef().s4; + + // set the LL I2C configuration (according to I2C driver version) + #if defined(STM32F1xx_MCUCONF) || defined(STM32F4xx_MCUCONF) || defined(STM32L1xx_MCUCONF) + + llConfig->op_mode = OPMODE_I2C; + llConfig->clock_speed = busSpeed == I2cBusSpeed_StandardMode ? 100000U : 400000U; + llConfig->duty_cycle = busSpeed == I2cBusSpeed_StandardMode ? STD_DUTY_CYCLE : FAST_DUTY_CYCLE_2; + + #endif + + #if defined(STM32F7xx_MCUCONF) || defined(STM32F3xx_MCUCONF) || defined(STM32F0xx_MCUCONF) || \ + defined(STM32L0xx_MCUCONF) || defined(STM32L4xx_MCUCONF) || \ + defined(STM32H7xx_MCUCONF) + + // Standard mode : 100 KHz, Rise time 120 ns, Fall time 25 ns, 54MHz clock source + // Fast mode : 400 KHz, Rise time 120 ns, Fall time 25 ns, 54MHz clock source + // Timing register value calculated by STM32 CubeMx + llConfig->timingr = busSpeed == I2cBusSpeed_StandardMode ? 0x80201721 : 0x00B01B59; + llConfig->cr1 = 0; + llConfig->cr2 = 0; + + #endif - return cfg; } HRESULT Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeInit___VOID( CLR_RT_StackFrame& stack ) { NANOCLR_HEADER(); + { + // get a pointer to the managed object instance and check that it's not NULL + CLR_RT_HeapBlock* pThis = stack.This(); FAULT_ON_NULL(pThis); + + // get bus index + // this is coded with a multiplication, need to perform and int division to get the number + // see the comments in the I2cDevice() constructor in managed code for details + uint8_t busIndex = (uint8_t)(pThis[ FIELD___deviceId ].NumericByRef().s4 / 1000); + + // init the PAL struct for this I2C bus and assign the respective driver + // all this occurs if not already done + // why do we need this? because several I2cDevice objects can be created associated to the same bus just using different addresses + switch (busIndex) + { + #if STM32_I2C_USE_I2C1 + case 1 : + if(I2C1_PAL.Driver == NULL) + { + Init_I2C1(); + I2C1_PAL.Driver = &I2CD1; + } + break; + #endif + #if STM32_I2C_USE_I2C2 + case 2 : + if(I2C2_PAL.Driver == NULL) + { + Init_I2C2(); + I2C2_PAL.Driver = &I2CD2; + } + break; + #endif + #if STM32_I2C_USE_I2C3 + case 3 : + if(I2C3_PAL.Driver == NULL) + { + Init_I2C3(); + I2C3_PAL.Driver = &I2CD3; + } + break; + #endif + #if STM32_I2C_USE_I2C4 + case 4 : + if(I2C4_PAL.Driver == NULL) + { + Init_I2C4(); + I2C4_PAL.Driver = &I2CD4; + } + break; + #endif + default: + // this I2C bus is not valid + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + break; + } + + } NANOCLR_NOCLEANUP(); } HRESULT Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::DisposeNative___VOID( CLR_RT_StackFrame& stack ) { NANOCLR_HEADER(); + { + NF_PAL_I2C* palI2c; + // get a pointer to the managed object instance and check that it's not NULL + CLR_RT_HeapBlock* pThis = stack.This(); FAULT_ON_NULL(pThis); + + // get bus index + // this is coded with a multiplication, need to perform and int division to get the number + // see the comments in the I2cDevice() constructor in managed code for details + uint8_t busIndex = (uint8_t)(pThis[ FIELD___deviceId ].NumericByRef().s4 / 1000); + + // uninit the PAL struct for this I2C bus + switch (busIndex) + { + #if STM32_I2C_USE_I2C1 + case 1 : + UnInit_I2C1(); + break; + #endif + #if STM32_I2C_USE_I2C2 + case 2 : + UnInit_I2C2(); + break; + #endif + #if STM32_I2C_USE_I2C3 + case 3 : + UnInit_I2C3(); + break; + #endif + #if STM32_I2C_USE_I2C4 + case 4 : + UnInit_I2C3(); + break; + #endif + default: + // this I2C bus is not valid + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + break; + } + + } NANOCLR_NOCLEANUP(); } -HRESULT Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeTransmit___I4__SZARRAY_U1__U4__SZARRAY_U1__U4( CLR_RT_StackFrame& stack ) +HRESULT Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeTransmit___WindowsDevicesI2cI2cTransferResult__SZARRAY_U1__SZARRAY_U1( CLR_RT_StackFrame& stack ) { NANOCLR_HEADER(); { + uint8_t busIndex; + NF_PAL_I2C* palI2c; - unsigned char * writeData = NULL; - unsigned char * readData = NULL; - int writeSize = 0; - int readSize = 0; - msg_t i2cStatus; - int returnStatus = I2cTransferStatus_FullTransfer; + CLR_RT_HeapBlock hbTimeout; + CLR_INT64* timeout; + bool eventResult = true; + + CLR_RT_HeapBlock_Array* writeBuffer; + CLR_RT_HeapBlock_Array* readBuffer; + CLR_RT_HeapBlock* result; // get a pointer to the managed object instance and check that it's not NULL CLR_RT_HeapBlock* pThis = stack.This(); FAULT_ON_NULL(pThis); - - // get a pointer to the managed spi connectionSettings object instance - CLR_RT_HeapBlock* pConfig = pThis[ FIELD___connectionSettings ].Dereference(); // get bus index // this is coded with a multiplication, need to perform and int division to get the number - // see the comments in the SpiDevice() constructor in managed code for details - uint8_t bus = (uint8_t)(pThis[ FIELD___deviceId ].NumericByRef().s4 / 1000); - - // Get a complete low-level SPI configuration, depending on user's managed parameters - nfI2CConfig cfg = GetConfig(bus, pThis[ FIELD___connectionSettings ].Dereference()); + // see the comments in the I2cDevice() constructor in managed code for details + busIndex = (uint8_t)(pThis[ FIELD___deviceId ].NumericByRef().s4 / 1000); - // dereference the write and read buffers from the arguments - CLR_RT_HeapBlock_Array* writeBuffer = stack.Arg1().DereferenceArray(); - if (writeBuffer != NULL) + // get the driver for the I2C bus + switch (busIndex) { - // grab the pointer to the array by getting the first element of the array - writeData = writeBuffer->GetFirstElement(); - - // get the size of the buffer by reading the number of elements in the HeapBlock array - writeSize = writeBuffer->m_numOfElements; + #if STM32_I2C_USE_I2C1 + case 1 : + palI2c = &I2C1_PAL; + break; + #endif + #if STM32_I2C_USE_I2C2 + case 2 : + palI2c = &I2C2_PAL; + break; + #endif + #if STM32_I2C_USE_I2C3 + case 3 : + palI2c = &I2C3_PAL; + break; + #endif + #if STM32_I2C_USE_I2C4 + case 4 : + palI2c = &I2C4_PAL; + break; + #endif + default: + // the requested I2C bus is not valid + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + break; } - CLR_RT_HeapBlock_Array* readBuffer = stack.Arg3().DereferenceArray(); - if (readBuffer != NULL) - { - // grab the pointer to the array by getting the first element of the array - readData = readBuffer->GetFirstElement(); + // set timeout to twice the I2C transaction timeout + // it should be enough to ensure thread start and execution, including any potential timeout there + // this value has to be in ticks to be properly loaded by SetupTimeoutFromTicks() bellow + hbTimeout.SetInteger((CLR_INT64)I2C_TRANSACTION_TIMEOUT_MS * TIME_CONVERSION__TO_MILLISECONDS); - // get the size of the buffer by reading the number of elements in the HeapBlock array - readSize = readBuffer->m_numOfElements; - } + NANOCLR_CHECK_HRESULT(stack.SetupTimeoutFromTicks( hbTimeout, timeout )); - // because the bus access is shared, acquire the appropriate bus - i2cStart(cfg.Driver, &cfg.Configuration); - i2cAcquireBus(cfg.Driver); -#ifdef STM32F7xx_MCUCONF - SCB_CleanInvalidateDCache(); -#endif - if (readSize != 0 && writeSize != 0) // WriteRead - { - i2cStatus = i2cMasterTransmitTimeout(cfg.Driver, cfg.SlaveAddress, &writeData[0], writeSize, &readData[0], readSize, 2000); - } - else + // this is going to be used to check for the right event in case of simultaneous I2C transaction + if(stack.m_customState == 1) { - if (readSize == 0) //Write + // get pointer to connection settings field + CLR_RT_HeapBlock* connectionSettings = pThis[ FIELD___connectionSettings ].Dereference(); + + // get a complete low-level I2C configuration, based in connection settings + GetConfig(connectionSettings, &palI2c->Configuration); + + // get slave address from connection settings field + palI2c->Address = (i2caddr_t)connectionSettings[Library_win_dev_i2c_native_Windows_Devices_I2c_I2cConnectionSettings::FIELD___slaveAddress].NumericByRef().s4; + + // when using I2Cv1 driver the address needs to be loaded in the I2C driver struct + #if defined(STM32F1xx_MCUCONF) || defined(STM32F4xx_MCUCONF) || defined(STM32L1xx_MCUCONF) + palI2c->Driver->addr = palI2c->Address; + #endif + + // dereference the write and read buffers from the arguments + writeBuffer = stack.Arg1().DereferenceArray(); + if (writeBuffer != NULL) + { + // get the size of the buffer by reading the number of elements in the HeapBlock array + palI2c->WriteSize = writeBuffer->m_numOfElements; + + // copy to DMA write buffer + memcpy(palI2c->WriteBuffer, writeBuffer->GetFirstElement(), palI2c->WriteSize); + } + + readBuffer = stack.Arg2().DereferenceArray(); + if (readBuffer != NULL) { - i2cStatus = i2cMasterTransmitTimeout(cfg.Driver, cfg.SlaveAddress, &writeData[0], writeSize, NULL, 0, 2000); + // get the size of the buffer by reading the number of elements in the HeapBlock array + palI2c->ReadSize = readBuffer->m_numOfElements; } - else // Read + + // flush DMA buffer to ensure cache coherency + // (only required for Cortex-M7) + cacheBufferInvalidate(palI2c->WriteBuffer, palI2c->WriteSize); + + // spawn working thread to perform the I2C transaction + palI2c->WorkingThread = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(128), + "I2CWT", NORMALPRIO, I2CWorkingThread, palI2c); + + if(palI2c->WorkingThread == NULL) { - i2cStatus = i2cMasterReceiveTimeout (cfg.Driver, cfg.SlaveAddress, &readData[0], readSize, 2000); + NANOCLR_SET_AND_LEAVE(CLR_E_PROCESS_EXCEPTION); } + + // bump custom state + stack.m_customState = 2; } - i2cReleaseBus(cfg.Driver); - if (i2cStatus != MSG_OK) + while(eventResult) { - int errorMask = i2cGetErrors(cfg.Driver); + if(palI2c->WorkingThread->state == CH_STATE_FINAL) + { + // I2C working thread is now complete + break; + } - //TODO: return correct error status regarding UWP API - returnStatus = I2cTransferStatus_UnknownError; + // non-blocking wait allowing other threads to run while we wait for the I2C transaction to complete + NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.WaitEvents( stack.m_owningThread, *timeout, CLR_RT_ExecutionEngine::c_Event_I2cMaster, eventResult )); } - // null pointers and vars - writeData = NULL; - readData = NULL; - writeBuffer = NULL; - readBuffer = NULL; - pThis = NULL; + // pop timeout heap block from stack + stack.PopValue(); + + if(eventResult) + { + // event occurred + // ChibiOS requirement: need to call chThdWait for I2C working thread in order to have it's memory released to the heap, otherwise it won't be returned + msg_t threadResult = chThdWait(palI2c->WorkingThread); + + // create the return object (I2cTransferResult) + // only at this point we are sure that there will be a return from this thread so it's OK to use the managed stack + CLR_RT_HeapBlock& top = stack.PushValueAndClear(); + NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewObjectFromIndex(top, g_CLR_RT_WellKnownTypes.m_I2cTransferResult)); + result = top.Dereference(); FAULT_ON_NULL(result); + + // get the result from the working thread execution + if (threadResult != MSG_OK) + { + // error in transaction + int errors = i2cGetErrors(palI2c->Driver); + + // figure out what was the error and set the status field + switch(errors) + { + case I2C_ACK_FAILURE: + result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___status ].SetInteger((CLR_UINT32)I2cTransferStatus_SlaveAddressNotAcknowledged); + break; + + case I2C_TIMEOUT: + result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___status ].SetInteger((CLR_UINT32)I2cTransferStatus_ClockStretchTimeout); + break; + + default: + result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___status ].SetInteger((CLR_UINT32)I2cTransferStatus_UnknownError); + } + + // set the bytes transferred count to 0 because we don't have a way to know how many bytes were actually sent/received + result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___bytesTransferred ].SetInteger(0); + } + else + { + // successfull transaction + // set the result field + result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___status ].SetInteger((CLR_UINT32)I2cTransferStatus_FullTransfer); + + // set the bytes transferred field + result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___bytesTransferred ].SetInteger((CLR_UINT32)(palI2c->WriteSize + palI2c->ReadSize)); + + if(palI2c->ReadSize > 0) + { + // because this was a Read transaction, need to copy from DMA buffer to managed buffer + + // need to dereference readBuffer argument to be able to write back on it + readBuffer = stack.Arg2().DereferenceArray(); + + // flush DMA buffer to ensure cache coherency + // (only required for Cortex-M7) + cacheBufferInvalidate(palI2c->ReadBuffer, palI2c->ReadSize); + + // copy I2C read buffer into managed buffer + memcpy(readBuffer->GetFirstElement(), palI2c->ReadBuffer, palI2c->ReadSize); + } + } + } - stack.SetResult_I4(returnStatus); } NANOCLR_NOCLEANUP(); } @@ -202,28 +432,28 @@ HRESULT Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeTransmit HRESULT Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::GetDeviceSelector___STATIC__STRING( CLR_RT_StackFrame& stack ) { NANOCLR_HEADER(); - { + { // declare the device selector string whose max size is "I2C1,I2C2,I2C3,I2C4," + terminator and init with the terminator - char deviceSelectorString[ 20 + 1] = { 0 }; - - #if STM32_I2C_USE_I2C1 - strcat(deviceSelectorString, "I2C1,"); - #endif - #if STM32_I2C_USE_I2C2 - strcat(deviceSelectorString, "I2C2,"); - #endif - #if STM32_I2C_USE_I2C3 - strcat(deviceSelectorString, "I2C3,"); - #endif - #if STM32_I2C_USE_I2C4 - strcat(deviceSelectorString, "I2C4,"); - #endif - // replace the last comma with a terminator + char deviceSelectorString[20 + 1] = { 0 }; + + #if STM32_I2C_USE_I2C1 + strcat(deviceSelectorString, "I2C1,"); + #endif + #if STM32_I2C_USE_I2C2 + strcat(deviceSelectorString, "I2C2,"); + #endif + #if STM32_I2C_USE_I2C3 + strcat(deviceSelectorString, "I2C3,"); + #endif + #if STM32_I2C_USE_I2C4 + strcat(deviceSelectorString, "I2C4,"); + #endif + // replace the last comma with a terminator deviceSelectorString[hal_strlen_s(deviceSelectorString) - 1] = '\0'; // because the caller is expecting a result to be returned // we need set a return result in the stack argument using the appropriate SetResult according to the variable type (a string here) stack.SetResult_String(deviceSelectorString); - } - NANOCLR_NOCLEANUP(); + } + NANOCLR_NOCLEANUP(); } diff --git a/targets/FreeRTOS/ESP32_DevKitC/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native.cpp b/targets/FreeRTOS/ESP32_DevKitC/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native.cpp index 76c6da7b31..084f2790fe 100644 --- a/targets/FreeRTOS/ESP32_DevKitC/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native.cpp +++ b/targets/FreeRTOS/ESP32_DevKitC/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native.cpp @@ -1,6 +1,5 @@ // // Copyright (c) 2017 The nanoFramework project contributors -// Portions Copyright (c) Microsoft Corporation. All rights reserved. // See LICENSE file in the project root for full license information. // @@ -23,9 +22,6 @@ static const CLR_RT_MethodHandler method_lookup[] = NULL, NULL, NULL, - Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeInit___VOID, - Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::DisposeNative___VOID, - Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeTransmit___I4__SZARRAY_U1__U4__SZARRAY_U1__U4, NULL, NULL, NULL, @@ -36,6 +32,10 @@ static const CLR_RT_MethodHandler method_lookup[] = NULL, NULL, NULL, + Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeInit___VOID, + Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::DisposeNative___VOID, + Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeTransmit___WindowsDevicesI2cI2cTransferResult__SZARRAY_U1__SZARRAY_U1, + NULL, NULL, Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::GetDeviceSelector___STATIC__STRING, NULL, @@ -44,12 +44,14 @@ static const CLR_RT_MethodHandler method_lookup[] = NULL, NULL, NULL, + NULL, + NULL, + NULL, }; const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_Windows_Devices_I2c = { "Windows.Devices.I2c", - 0xC5ABF45E, + 0xA170B1E0, method_lookup }; - diff --git a/targets/FreeRTOS/ESP32_DevKitC/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native.h b/targets/FreeRTOS/ESP32_DevKitC/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native.h index 2bad87d260..e925204f11 100644 --- a/targets/FreeRTOS/ESP32_DevKitC/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native.h +++ b/targets/FreeRTOS/ESP32_DevKitC/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native.h @@ -1,6 +1,5 @@ // // Copyright (c) 2017 The nanoFramework project contributors -// Portions Copyright (c) Microsoft Corporation. All rights reserved. // See LICENSE file in the project root for full license information. // @@ -11,7 +10,6 @@ #include #include - struct Library_win_dev_i2c_native_Windows_Devices_I2c_I2cConnectionSettings { static const int FIELD___slaveAddress = 1; @@ -25,7 +23,8 @@ struct Library_win_dev_i2c_native_Windows_Devices_I2c_I2cConnectionSettings struct Library_win_dev_i2c_native_Windows_Devices_I2c_I2cController { - static const int FIELD_STATIC__DeviceCollection = 0; + static const int FIELD_STATIC__s_instance = 0; + static const int FIELD_STATIC__s_deviceCollection = 1; //--// @@ -37,12 +36,11 @@ struct Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice static const int FIELD___syncLock = 1; static const int FIELD___deviceId = 2; static const int FIELD___connectionSettings = 3; - static const int FIELD___i2cBus = 4; - static const int FIELD___disposedValue = 5; + static const int FIELD___disposed = 4; NANOCLR_NATIVE_DECLARE(NativeInit___VOID); NANOCLR_NATIVE_DECLARE(DisposeNative___VOID); - NANOCLR_NATIVE_DECLARE(NativeTransmit___I4__SZARRAY_U1__U4__SZARRAY_U1__U4); + NANOCLR_NATIVE_DECLARE(NativeTransmit___WindowsDevicesI2cI2cTransferResult__SZARRAY_U1__SZARRAY_U1); NANOCLR_NATIVE_DECLARE(GetDeviceSelector___STATIC__STRING); //--// @@ -51,14 +49,14 @@ struct Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice struct Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult { - static const int FIELD__BytesTransferred = 1; - static const int FIELD__Status = 2; + static const int FIELD___bytesTransferred = 1; + static const int FIELD___status = 2; //--// }; - extern const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_Windows_Devices_I2c; +extern const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_Windows_Devices_I2c; #endif //_WIN_DEV_I2C_NATIVE_H_ diff --git a/targets/FreeRTOS/ESP32_DevKitC/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native_Windows_Devices_I2C_I2cDevice.cpp b/targets/FreeRTOS/ESP32_DevKitC/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native_Windows_Devices_I2C_I2cDevice.cpp index 47c1eb0174..b772a2ed1c 100644 --- a/targets/FreeRTOS/ESP32_DevKitC/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native_Windows_Devices_I2C_I2cDevice.cpp +++ b/targets/FreeRTOS/ESP32_DevKitC/nanoCLR/Windows.Devices.I2c/win_dev_i2c_native_Windows_Devices_I2C_I2cDevice.cpp @@ -6,40 +6,40 @@ #include #include - #include "win_dev_i2c_native.h" #include "Esp32_DeviceMapping.h" + /////////////////////////////////////////////////////////////////////////////////////// // !!! KEEP IN SYNC WITH Windows.Devices.I2c.I2cSharingMode (in managed code) !!! // /////////////////////////////////////////////////////////////////////////////////////// enum I2cSharingMode - { - Exclusive = 0, - Shared - }; +{ + Exclusive = 0, + Shared +}; /////////////////////////////////////////////////////////////////////////////////////// // !!! KEEP IN SYNC WITH Windows.Devices.I2c.I2cTransferStatus (in managed code) !!! // /////////////////////////////////////////////////////////////////////////////////////// enum I2cTransferStatus - { - I2cTransferStatus_FullTransfer = 0, - I2cTransferStatus_ClockStretchTimeout, - I2cTransferStatus_PartialTransfer, - I2cTransferStatus_SlaveAddressNotAcknowledged, - I2cTransferStatus_UnknownError - }; +{ + I2cTransferStatus_FullTransfer = 0, + I2cTransferStatus_ClockStretchTimeout, + I2cTransferStatus_PartialTransfer, + I2cTransferStatus_SlaveAddressNotAcknowledged, + I2cTransferStatus_UnknownError +}; /////////////////////////////////////////////////////////////////////////////////////// // !!! KEEP IN SYNC WITH Windows.Devices.I2c.I2cBusSpeed (in managed code) !!! // /////////////////////////////////////////////////////////////////////////////////////// enum I2cBusSpeed - { - I2cBusSpeed_StandardMode = 0, - I2cBusSpeed_FastMode - }; +{ + I2cBusSpeed_StandardMode = 0, + I2cBusSpeed_FastMode +}; typedef Library_win_dev_i2c_native_Windows_Devices_I2c_I2cConnectionSettings I2cConnectionSettings; @@ -128,7 +128,7 @@ HRESULT Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::DisposeNative_ NANOCLR_NOCLEANUP(); } -HRESULT Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeTransmit___I4__SZARRAY_U1__U4__SZARRAY_U1__U4( CLR_RT_StackFrame& stack ) +HRESULT Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeTransmit___WindowsDevicesI2cI2cTransferResult__SZARRAY_U1__SZARRAY_U1( CLR_RT_StackFrame& stack ) { NANOCLR_HEADER(); { @@ -139,6 +139,10 @@ HRESULT Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeTransmit esp_err_t i2cStatus; int returnStatus = I2cTransferStatus_FullTransfer; + CLR_RT_HeapBlock* result; + // create the return object (I2cTransferResult) + CLR_RT_HeapBlock& top = stack.PushValueAndClear(); + // get a pointer to the managed object instance and check that it's not NULL CLR_RT_HeapBlock* pThis = stack.This(); FAULT_ON_NULL(pThis); @@ -194,13 +198,38 @@ HRESULT Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeTransmit i2cStatus = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_RATE_MS); i2c_cmd_link_delete(cmd); + // create return object + NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewObjectFromIndex(top, g_CLR_RT_WellKnownTypes.m_I2cTransferResult)); + result = top.Dereference(); FAULT_ON_NULL(result); + if (i2cStatus != ESP_OK) { + // set the result field if ( i2cStatus == ESP_FAIL ) - returnStatus = I2cTransferStatus_SlaveAddressNotAcknowledged; + { + result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___status ].SetInteger((CLR_UINT32)I2cTransferStatus_SlaveAddressNotAcknowledged); + } else - returnStatus = I2cTransferStatus_UnknownError; - } + { + result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___status ].SetInteger((CLR_UINT32)I2cTransferStatus_UnknownError); + } + + // set the bytes transferred field + result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___bytesTransferred ].SetInteger(0); + } + else + { + result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___status ].SetInteger((CLR_UINT32)I2cTransferStatus_FullTransfer); + + // set the bytes transferred field + result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___bytesTransferred ].SetInteger((CLR_UINT32)(writeSize + readSize)); + + if(readSize > 0) + { + // because this was a Read transaction, need to copy from DMA buffer to managed buffer + memcpy(readBuffer->GetFirstElement(), &readData[0], readSize); + } + } // null pointers and vars writeData = NULL;