Browse Source

Use the IRQ signal from the nrf24l01 instead of polling the status

This is done to avoid transmission erros as described in
https://forum.mysensors.org/topic/10452/nrf24l01-communication-failure-root-cause-and-solution
Bernd Gottschlag 5 years ago
parent
commit
e7bfca4363

+ 8
- 0
weather-sensor/firmware/led.h View File

1
+#ifndef LED_H
2
+#define LED_H
3
+
4
+#define LED_DDR   DDRD
5
+#define LED_PORT  PORTD
6
+#define LED_PIN   PD3
7
+
8
+#endif

+ 12
- 16
weather-sensor/firmware/main.c View File

6
 #include <stdio.h>
6
 #include <stdio.h>
7
 #include <stdlib.h>
7
 #include <stdlib.h>
8
 #include <string.h>
8
 #include <string.h>
9
+#include <stdbool.h>
9
 
10
 
11
+#include "led.h"
10
 #include "spi.h"
12
 #include "spi.h"
11
 #include "nrf24l01.h"
13
 #include "nrf24l01.h"
12
 #include "nrf24l01_definitions.h"
14
 #include "nrf24l01_definitions.h"
15
 
17
 
16
 
18
 
17
 
19
 
18
-/* Debug LED: */
19
-#define LED_DDR   DDRD
20
-#define LED_PORT  PORTD
21
-#define LED_PIN   PD3
22
 
20
 
23
 
21
 
24
 char bool_case = 0;
22
 char bool_case = 0;
27
 
25
 
28
 volatile uint8_t cycle = 0;
26
 volatile uint8_t cycle = 0;
29
 
27
 
28
+volatile bool nrfInterruptRaised;
29
+
30
 volatile uint8_t interruptCounter;
30
 volatile uint8_t interruptCounter;
31
 volatile uint8_t executionFlag;
31
 volatile uint8_t executionFlag;
32
 
32
 
50
 void Enter_Power_Save_Mode(void);
50
 void Enter_Power_Save_Mode(void);
51
 
51
 
52
 
52
 
53
-ISR( TIMER2_COMPA_vect )
53
+ISR(TIMER2_COMPA_vect)
54
 {
54
 {
55
 	/* Do nothing as the interrupt is only used to wake up the MCU. */
55
 	/* Do nothing as the interrupt is only used to wake up the MCU. */
56
 }
56
 }
57
 
57
 
58
+ISR(PCINT2_vect)
59
+{
60
+	nrfInterruptRaised = true;
61
+}
62
+
58
 int main (void)
63
 int main (void)
59
 {
64
 {
60
 	struct bme280_data sensorData;
65
 	struct bme280_data sensorData;
62
 //	uint8_t registerContent[5];
67
 //	uint8_t registerContent[5];
63
 //	char registerContentString[30];
68
 //	char registerContentString[30];
64
 //	uint8_t lengthRead;
69
 //	uint8_t lengthRead;
65
-	uint8_t temp = 0;
66
 
70
 
67
 	/* Enable the debug LED */
71
 	/* Enable the debug LED */
68
 	LED_DDR |= (1 << LED_PIN);
72
 	LED_DDR |= (1 << LED_PIN);
103
 			BME280_Get_Measurement(&sensorData);
107
 			BME280_Get_Measurement(&sensorData);
104
 			NRF24L01_Send_Message((uint8_t*)&sensorData, sizeof(sensorData));
108
 			NRF24L01_Send_Message((uint8_t*)&sensorData, sizeof(sensorData));
105
 
109
 
106
-			if (temp == 0)
107
-			{
108
-				LED_PORT |= (1 << LED_PIN);
109
-				temp = 1;
110
-			}
111
-			else
112
-			{
113
-				temp = 0;
114
-				LED_PORT &= ~(1 << LED_PIN);
115
-			}
110
+			_delay_ms(100); /* TODO: only for debugging, remove this later! */
111
+			LED_PORT &= ~(1 << LED_PIN);
116
 
112
 
117
 			cycle = 0;
113
 			cycle = 0;
118
 		}
114
 		}

+ 2
- 2
weather-sensor/firmware/makefile View File

5
 	rm -f main
5
 	rm -f main
6
 
6
 
7
 flash: main.hex
7
 flash: main.hex
8
-	sudo avrdude -c buspirate -b 115200 -P /dev/ttyUSB0 -p m88p -v -U flash:w:main.hex
8
+	sudo avrdude -c buspirate -b 115200 -P /dev/ttyUSB1 -p m88p -v -U flash:w:main.hex
9
 
9
 
10
-main: main.c spi.c spi.h nrf24l01.c nrf24l01.h nrf24l01_definitions.h bme280_interface.c bme280_interface.h BME280_driver/bme280.c BME280_driver/bme280.h
10
+main: main.c spi.c spi.h nrf24l01.c nrf24l01.h nrf24l01_definitions.h bme280_interface.c bme280_interface.h BME280_driver/bme280.c BME280_driver/bme280.h led.h
11
 	avr-gcc main.c spi.c nrf24l01.c bme280_interface.c BME280_driver/bme280.c -I BME280_driver -o main -mmcu=atmega88p -Os -Wall -Wextra -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -DF_CPU=1000000UL -D BME280_32BIT_ENABLE
11
 	avr-gcc main.c spi.c nrf24l01.c bme280_interface.c BME280_driver/bme280.c -I BME280_driver -o main -mmcu=atmega88p -Os -Wall -Wextra -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -DF_CPU=1000000UL -D BME280_32BIT_ENABLE
12
 
12
 
13
 main.hex: main
13
 main.hex: main

+ 35
- 41
weather-sensor/firmware/nrf24l01.c View File

4
 #include <stdio.h>
4
 #include <stdio.h>
5
 #include <stdbool.h>
5
 #include <stdbool.h>
6
 
6
 
7
+#include "led.h" // TODO: for debugging
7
 #include "spi.h"
8
 #include "spi.h"
8
 #include "nrf24l01.h"
9
 #include "nrf24l01.h"
9
 #include "nrf24l01_definitions.h"
10
 #include "nrf24l01_definitions.h"
10
 
11
 
11
 /* TODO
12
 /* TODO
12
- * - Build a state machine that tracks the mode the NRF is set to
13
- * - Configuration of NRF24L01 and startup
14
- * - Send and Receive functions
15
- * - Interrupt handling for Send and Receive
13
+ * - Send functions
14
+ * - Interrupt handling for Send
16
  */
15
  */
17
 
16
 
17
+extern volatile bool nrfInterruptRaised;
18
+
18
 void Print_Register_Contents(uint8_t address);
19
 void Print_Register_Contents(uint8_t address);
19
 void Send_TX_Flush_Command(void);
20
 void Send_TX_Flush_Command(void);
20
 
21
 
51
 
52
 
52
 	/* Ensure that the CE pin is set to 0*/
53
 	/* Ensure that the CE pin is set to 0*/
53
 	NRF_CE_PORT &= ~(1 << NRF_CE_PIN);
54
 	NRF_CE_PORT &= ~(1 << NRF_CE_PIN);
55
+
56
+	/* Set the interrupt pin */
57
+	/* TODO: PCINT21 -> PCINT2 */
58
+	NRF_IRQ_DDR &= ~(1 << NRF_IRQ_PIN); // Set the pin as input
59
+	NRF_IRQ_PORT |= (1 << NRF_IRQ_PORT); // Enable the pullup for the pin
54
 }
60
 }
55
 
61
 
56
 void Configure_Transmission(void)
62
 void Configure_Transmission(void)
106
 	Set_TX_Address(0x123456);
112
 	Set_TX_Address(0x123456);
107
 
113
 
108
 	Set_RX_P0_Address(0x123456);
114
 	Set_RX_P0_Address(0x123456);
109
-	
110
-
111
 	// TODO: set addresses for all data pipes
115
 	// TODO: set addresses for all data pipes
116
+
117
+
118
+	PCMSK2 |= (1<<PCINT21); // Set the external interrupt for PD5
112
 }
119
 }
113
 
120
 
114
 void NRF24L01_Send_Message(uint8_t *buffer, uint8_t length)
121
 void NRF24L01_Send_Message(uint8_t *buffer, uint8_t length)
115
 {
122
 {
116
-	bool transmissionFinished = false;
117
-
118
 	STATUS_REGISTER statusRegisterContents = {.byte = 0x0};
123
 	STATUS_REGISTER statusRegisterContents = {.byte = 0x0};
119
-	uint32_t timeout = 0;
120
-	/* TODO:
121
-	 * - if needed: PRIM_RX = 0
122
-	 * - Set CE = 1 for more than 10 us
123
-	 * - Wait until the transmission is finished
124
-	 * - Read number of retries for debug purposes
125
-	 * - Check if the FIFO is empty -> if not, flush it
126
-	 * - reset the interupts of the STATUS
127
-	 */
128
 	
124
 	
129
-	/* TODO: messages with more than 32 byte length */
130
 	if ((length > 32) || (length == 0))
125
 	if ((length > 32) || (length == 0))
131
 	{
126
 	{
132
 		return;
127
 		return;
133
 	}
128
 	}
134
 
129
 
130
+	PCICR |= (1<<PCIE2); // Enable the interrupt for the IRQ signal
131
+
135
 	Write_Message_To_TX_FIFO(length, buffer);
132
 	Write_Message_To_TX_FIFO(length, buffer);
136
 
133
 
137
 	/* Set CE = 1 for more than 10 us */
134
 	/* Set CE = 1 for more than 10 us */
139
 	_delay_us(15);
136
 	_delay_us(15);
140
 	NRF_CE_PORT &= ~(1 << NRF_CE_PIN);
137
 	NRF_CE_PORT &= ~(1 << NRF_CE_PIN);
141
 
138
 
139
+	while (nrfInterruptRaised == false); // Wait until the transmission is complete
140
+	/* An interrupt instead of polling the status register is used to avoid transmission errors
141
+	 * induced by the SPI:
142
+	 * https://forum.mysensors.org/topic/10452/nrf24l01-communication-failure-root-cause-and-solution
143
+	 */
144
+	LED_PORT |= (1 << LED_PIN);
142
 
145
 
143
-	do
146
+	statusRegisterContents.byte = Read_NRF_Status_Register();
147
+
148
+
149
+	if (statusRegisterContents.bits.MAX_RT == 1)
144
 	{
150
 	{
145
-		_delay_ms(1);
146
-		/* TODO: instead of polling the status register use the IRQ to spawn an interrupt as the
147
-		 * constant polling may induce transmission errors:
148
-		 * https://forum.mysensors.org/topic/10452/nrf24l01-communication-failure-root-cause-and-solution
149
-		 */
150
-		statusRegisterContents.byte = Read_NRF_Status_Register();
151
-
152
-		if (statusRegisterContents.bits.TX_DS == 1)
153
-		{
154
-			transmissionFinished = true;
155
-		}
156
-
157
-		if (statusRegisterContents.bits.MAX_RT == 1)
158
-		{
159
-			transmissionFinished = true; //TODO: indicate failure
160
-
161
-			Send_TX_Flush_Command(); /* Remove the packet from the TX FIFO as it is not done automatically */
162
-		}
163
-		
164
-		timeout ++; // TODO: this should work without the time out, as MAX_RT should be triggered if no ACK is received
165
-	} while ((transmissionFinished == false) && (timeout < 0xFF));
151
+		Send_TX_Flush_Command(); /* Remove the packet from the TX FIFO as it is not done automatically */
152
+	}
153
+	
166
 
154
 
167
 	/* Reset the interrupts */
155
 	/* Reset the interrupts */
168
-	statusRegisterContents.byte = Read_NRF_Status_Register();
169
 	statusRegisterContents.bits.TX_DS = 1;
156
 	statusRegisterContents.bits.TX_DS = 1;
170
 	statusRegisterContents.bits.MAX_RT = 1;
157
 	statusRegisterContents.bits.MAX_RT = 1;
158
+	statusRegisterContents.bits.RX_DR = 1;
171
 	Write_NRF_Register(STATUS_ADDRESS, statusRegisterContents.byte);
159
 	Write_NRF_Register(STATUS_ADDRESS, statusRegisterContents.byte);
160
+
161
+	PCICR &= ~(1<<PCIE2); // Disable the interrupt for the IRQ signal
162
+	nrfInterruptRaised = false;
163
+
164
+
165
+	return;
172
 }
166
 }
173
 
167
 
174
 void Print_Register_Contents(uint8_t address)
168
 void Print_Register_Contents(uint8_t address)

+ 4
- 3
weather-sensor/firmware/nrf24l01.h View File

12
 #define NRF_CSN_PORT  PORTD
12
 #define NRF_CSN_PORT  PORTD
13
 #define NRF_CSN_PIN   PD6
13
 #define NRF_CSN_PIN   PD6
14
 
14
 
15
-#define NRF_IRQ_DDR   DDRD
16
-#define NRF_IRQ_PORT  PORTD
17
-#define NRF_IRQ_PIN   PD5
15
+#define NRF_IRQ_DDR     DDRD
16
+#define NRF_IRQ_PORT    PORTD
17
+#define NRF_IRQ_PIN     PD5
18
+#define NRF_IRQ_PORTIN  PIND
18
 
19
 
19
 void Initialize_NRF24L01(void);
20
 void Initialize_NRF24L01(void);
20
 void Set_NRF24L01_Pins(void);
21
 void Set_NRF24L01_Pins(void);

Loading…
Cancel
Save