22#include < cstring>
33#include < hal/nrf_gpio.h>
44#include < nrfx_log.h>
5-
5+ #include < nrfx_twim.h>
6+ #include < nrf_drv_twi.h>
67using namespace Pinetime ::Drivers;
78
89// TODO use shortcut to automatically send STOP when receive LastTX, for example
910// TODO use DMA/IRQ
1011
11- TwiMaster::TwiMaster (const Modules module , const Parameters& params) : module{module }, params{params} {
12- mutex = xSemaphoreCreateBinary ();
13- }
14-
15- void TwiMaster::Init () {
16- NRF_GPIO->PIN_CNF [params.pinScl ] = ((uint32_t )GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)
17- | ((uint32_t )GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
18- | ((uint32_t )GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos)
19- | ((uint32_t )GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos)
20- | ((uint32_t )GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
21-
22- NRF_GPIO->PIN_CNF [params.pinSda ] = ((uint32_t )GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)
23- | ((uint32_t )GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
24- | ((uint32_t )GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos)
25- | ((uint32_t )GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos)
26- | ((uint32_t )GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
27-
12+ TwiMaster::TwiMaster (const Modules module , const Parameters& params) : module{module }, params{params}, mutex{xSemaphoreCreateBinary ()} {
13+ ASSERT (mutex != nullptr );
2814 switch (module ) {
29- case Modules::TWIM1: twiBaseAddress = NRF_TWIM1; break ;
15+ case Modules::TWIM1:
3016 default :
31- return ;
32- }
33-
34- switch (static_cast <Frequencies>(params.frequency )) {
35- case Frequencies::Khz100 : twiBaseAddress->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K100; break ;
36- case Frequencies::Khz250 : twiBaseAddress->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K250; break ;
37- case Frequencies::Khz400 : twiBaseAddress->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K400; break ;
17+ twim = NRFX_TWIM_INSTANCE (1 );
18+ break ;
3819 }
20+ }
3921
40- twiBaseAddress->PSEL .SCL = params.pinScl ;
41- twiBaseAddress->PSEL .SDA = params.pinSda ;
42- twiBaseAddress->EVENTS_LASTRX = 0 ;
43- twiBaseAddress->EVENTS_STOPPED = 0 ;
44- twiBaseAddress->EVENTS_LASTTX = 0 ;
45- twiBaseAddress->EVENTS_ERROR = 0 ;
46- twiBaseAddress->EVENTS_RXSTARTED = 0 ;
47- twiBaseAddress->EVENTS_SUSPENDED = 0 ;
48- twiBaseAddress->EVENTS_TXSTARTED = 0 ;
49-
50- twiBaseAddress->ENABLE = (TWIM_ENABLE_ENABLE_Enabled << TWIM_ENABLE_ENABLE_Pos);
51-
52-
53- /* // IRQ
54- NVIC_ClearPendingIRQ(_IRQn);
55- NVIC_SetPriority(_IRQn, 2);
56- NVIC_EnableIRQ(_IRQn);
57- */
22+ void TwiMaster::Init () {
23+ nrfx_twim_config_t config;
24+ config.frequency = static_cast <nrf_twim_frequency_t >(params.frequency );
25+ config.hold_bus_uninit = false ;
26+ config.interrupt_priority = 0 ;
27+ config.scl = params.pinScl ;
28+ config.sda = params.pinSda ;
29+ nrfx_twim_init (&twim,
30+ &config,
31+ nullptr ,
32+ nullptr );
33+ nrfx_twim_enable (&twim);
5834
5935 xSemaphoreGive (mutex);
60-
6136}
6237
6338TwiMaster::ErrorCodes TwiMaster::Read (uint8_t deviceAddress, uint8_t registerAddress, uint8_t *data, size_t size) {
6439 xSemaphoreTake (mutex, portMAX_DELAY);
65- auto ret = ReadWithRetry (deviceAddress, registerAddress, data, size);
40+ TwiMaster::ErrorCodes ret;
41+
42+ auto err = nrfx_twim_tx (&twim, deviceAddress, ®isterAddress, 1 , false );
43+ if (err != 0 ) {
44+ return TwiMaster::ErrorCodes::TransactionFailed;
45+ }
46+
47+ err = nrfx_twim_rx (&twim, deviceAddress, data, size);
48+ if (err != 0 ) {
49+ return TwiMaster::ErrorCodes::TransactionFailed;
50+ }
6651 xSemaphoreGive (mutex);
6752
68- return ret ;
53+ return TwiMaster::ErrorCodes::NoError ;
6954}
7055
7156TwiMaster::ErrorCodes TwiMaster::Write (uint8_t deviceAddress, uint8_t registerAddress, const uint8_t *data, size_t size) {
7257 ASSERT (size <= maxDataSize);
7358 xSemaphoreTake (mutex, portMAX_DELAY);
74-
75- auto ret = WriteWithRetry (deviceAddress, registerAddress, data, size);
76- xSemaphoreGive (mutex);
77- return ret;
78- }
79-
80- /* Execute a read transaction (composed of a write and a read operation). If one of these opeartion fails,
81- * it's retried once. If it fails again, an error is returned */
82- TwiMaster::ErrorCodes TwiMaster::ReadWithRetry (uint8_t deviceAddress, uint8_t registerAddress, uint8_t *data, size_t size) {
8359 TwiMaster::ErrorCodes ret;
84- ret = Write (deviceAddress, ®isterAddress, 1 , false );
85- if (ret != ErrorCodes::NoError)
86- ret = Write (deviceAddress, ®isterAddress, 1 , false );
87-
88- if (ret != ErrorCodes::NoError) return ret;
8960
90- ret = Read (deviceAddress, data, size, true );
91- if (ret != ErrorCodes::NoError)
92- ret = Read (deviceAddress, data, size, true );
93-
94- return ret;
95- }
96-
97- /* Execute a write transaction. If it fails, it is retried once. If it fails again, an error is returned. */
98- TwiMaster::ErrorCodes TwiMaster::WriteWithRetry (uint8_t deviceAddress, uint8_t registerAddress, const uint8_t *data, size_t size) {
9961 internalBuffer[0 ] = registerAddress;
10062 std::memcpy (internalBuffer+1 , data, size);
101- auto ret = Write (deviceAddress, internalBuffer, size+1 , true );
102- if (ret != ErrorCodes::NoError)
103- ret = Write (deviceAddress, internalBuffer, size+1 , true );
104-
105- return ret;
106- }
107-
108-
109- TwiMaster::ErrorCodes TwiMaster::Read (uint8_t deviceAddress, uint8_t *buffer, size_t size, bool stop) {
110- twiBaseAddress->ADDRESS = deviceAddress;
111- twiBaseAddress->TASKS_RESUME = 0x1UL ;
112- twiBaseAddress->RXD .PTR = (uint32_t )buffer;
113- twiBaseAddress->RXD .MAXCNT = size;
114-
115- twiBaseAddress->TASKS_STARTRX = 1 ;
116-
117- while (!twiBaseAddress->EVENTS_RXSTARTED && !twiBaseAddress->EVENTS_ERROR );
118- twiBaseAddress->EVENTS_RXSTARTED = 0x0UL ;
119-
120- txStartedCycleCount = DWT->CYCCNT ;
121- uint32_t currentCycleCount;
122- while (!twiBaseAddress->EVENTS_LASTRX && !twiBaseAddress->EVENTS_ERROR ) {
123- currentCycleCount = DWT->CYCCNT ;
124- if ((currentCycleCount-txStartedCycleCount) > HwFreezedDelay) {
125- FixHwFreezed ();
126- return ErrorCodes::TransactionFailed;
127- }
128- }
129- twiBaseAddress->EVENTS_LASTRX = 0x0UL ;
130-
131- if (stop || twiBaseAddress->EVENTS_ERROR ) {
132- twiBaseAddress->TASKS_STOP = 0x1UL ;
133- while (!twiBaseAddress->EVENTS_STOPPED );
134- twiBaseAddress->EVENTS_STOPPED = 0x0UL ;
135- }
136- else {
137- twiBaseAddress->TASKS_SUSPEND = 0x1UL ;
138- while (!twiBaseAddress->EVENTS_SUSPENDED );
139- twiBaseAddress->EVENTS_SUSPENDED = 0x0UL ;
63+ auto err = nrfx_twim_tx (&twim, deviceAddress, internalBuffer , size+1 , false );
64+ if (err != 0 ){
65+ return TwiMaster::ErrorCodes::TransactionFailed;
14066 }
14167
142- if (twiBaseAddress->EVENTS_ERROR ) {
143- twiBaseAddress->EVENTS_ERROR = 0x0UL ;
144- }
145- return ErrorCodes::NoError;
146- }
147-
148- TwiMaster::ErrorCodes TwiMaster::Write (uint8_t deviceAddress, const uint8_t *data, size_t size, bool stop) {
149- twiBaseAddress->ADDRESS = deviceAddress;
150- twiBaseAddress->TASKS_RESUME = 0x1UL ;
151- twiBaseAddress->TXD .PTR = (uint32_t )data;
152- twiBaseAddress->TXD .MAXCNT = size;
153-
154- twiBaseAddress->TASKS_STARTTX = 1 ;
155-
156- while (!twiBaseAddress->EVENTS_TXSTARTED && !twiBaseAddress->EVENTS_ERROR );
157- twiBaseAddress->EVENTS_TXSTARTED = 0x0UL ;
158-
159- txStartedCycleCount = DWT->CYCCNT ;
160- uint32_t currentCycleCount;
161- while (!twiBaseAddress->EVENTS_LASTTX && !twiBaseAddress->EVENTS_ERROR ) {
162- currentCycleCount = DWT->CYCCNT ;
163- if ((currentCycleCount-txStartedCycleCount) > HwFreezedDelay) {
164- FixHwFreezed ();
165- return ErrorCodes::TransactionFailed;
166- }
167- }
168- twiBaseAddress->EVENTS_LASTTX = 0x0UL ;
169-
170- if (stop || twiBaseAddress->EVENTS_ERROR ) {
171- twiBaseAddress->TASKS_STOP = 0x1UL ;
172- while (!twiBaseAddress->EVENTS_STOPPED );
173- twiBaseAddress->EVENTS_STOPPED = 0x0UL ;
174- }
175- else {
176- twiBaseAddress->TASKS_SUSPEND = 0x1UL ;
177- while (!twiBaseAddress->EVENTS_SUSPENDED );
178- twiBaseAddress->EVENTS_SUSPENDED = 0x0UL ;
179- }
180-
181- if (twiBaseAddress->EVENTS_ERROR ) {
182- twiBaseAddress->EVENTS_ERROR = 0x0UL ;
183- uint32_t error = twiBaseAddress->ERRORSRC ;
184- twiBaseAddress->ERRORSRC = error;
185- }
186-
187- return ErrorCodes::NoError;
68+ xSemaphoreGive (mutex);
69+ return TwiMaster::ErrorCodes::NoError;
18870}
18971
19072void TwiMaster::Sleep () {
191- while (twiBaseAddress-> ENABLE != 0 ) {
192- twiBaseAddress-> ENABLE = (TWIM_ENABLE_ENABLE_Disabled << TWIM_ENABLE_ENABLE_Pos );
193- }
73+ nrfx_twim_disable (&twim);
74+ nrfx_twim_uninit (&twim );
75+
19476 nrf_gpio_cfg_default (6 );
19577 nrf_gpio_cfg_default (7 );
19678 NRF_LOG_INFO (" [TWIMASTER] Sleep" );
@@ -200,30 +82,3 @@ void TwiMaster::Wakeup() {
20082 Init ();
20183 NRF_LOG_INFO (" [TWIMASTER] Wakeup" );
20284}
203-
204- /* Sometimes, the TWIM device just freeze and never set the event EVENTS_LASTTX.
205- * This method disable and re-enable the peripheral so that it works again.
206- * This is just a workaround, and it would be better if we could find a way to prevent
207- * this issue from happening.
208- * */
209- void TwiMaster::FixHwFreezed () {
210- NRF_LOG_INFO (" I2C device frozen, reinitializing it!" );
211- // Disable I²C
212- uint32_t twi_state = NRF_TWI1->ENABLE ;
213- twiBaseAddress->ENABLE = TWIM_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
214-
215- NRF_GPIO->PIN_CNF [params.pinScl ] = ((uint32_t )GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)
216- | ((uint32_t )GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
217- | ((uint32_t )GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos)
218- | ((uint32_t )GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
219- | ((uint32_t )GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
220-
221- NRF_GPIO->PIN_CNF [params.pinSda ] = ((uint32_t )GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)
222- | ((uint32_t )GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
223- | ((uint32_t )GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos)
224- | ((uint32_t )GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
225- | ((uint32_t )GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
226-
227- // Re-enable I²C
228- twiBaseAddress->ENABLE = twi_state;
229- }
0 commit comments