Sfoglia il codice sorgente

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 anni fa
parent
commit
e7bfca4363

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

@@ -0,0 +1,8 @@
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 Vedi File

@@ -6,7 +6,9 @@
6 6
 #include <stdio.h>
7 7
 #include <stdlib.h>
8 8
 #include <string.h>
9
+#include <stdbool.h>
9 10
 
11
+#include "led.h"
10 12
 #include "spi.h"
11 13
 #include "nrf24l01.h"
12 14
 #include "nrf24l01_definitions.h"
@@ -15,10 +17,6 @@
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 22
 char bool_case = 0;
@@ -27,6 +25,8 @@ int timer_max = 0;
27 25
 
28 26
 volatile uint8_t cycle = 0;
29 27
 
28
+volatile bool nrfInterruptRaised;
29
+
30 30
 volatile uint8_t interruptCounter;
31 31
 volatile uint8_t executionFlag;
32 32
 
@@ -50,11 +50,16 @@ void Set_Up_Power_Save_Mode(void);
50 50
 void Enter_Power_Save_Mode(void);
51 51
 
52 52
 
53
-ISR( TIMER2_COMPA_vect )
53
+ISR(TIMER2_COMPA_vect)
54 54
 {
55 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 63
 int main (void)
59 64
 {
60 65
 	struct bme280_data sensorData;
@@ -62,7 +67,6 @@ int main (void)
62 67
 //	uint8_t registerContent[5];
63 68
 //	char registerContentString[30];
64 69
 //	uint8_t lengthRead;
65
-	uint8_t temp = 0;
66 70
 
67 71
 	/* Enable the debug LED */
68 72
 	LED_DDR |= (1 << LED_PIN);
@@ -103,16 +107,8 @@ int main (void)
103 107
 			BME280_Get_Measurement(&sensorData);
104 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 113
 			cycle = 0;
118 114
 		}

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

@@ -5,9 +5,9 @@ clean:
5 5
 	rm -f main
6 6
 
7 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 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 13
 main.hex: main

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

@@ -4,17 +4,18 @@
4 4
 #include <stdio.h>
5 5
 #include <stdbool.h>
6 6
 
7
+#include "led.h" // TODO: for debugging
7 8
 #include "spi.h"
8 9
 #include "nrf24l01.h"
9 10
 #include "nrf24l01_definitions.h"
10 11
 
11 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 19
 void Print_Register_Contents(uint8_t address);
19 20
 void Send_TX_Flush_Command(void);
20 21
 
@@ -51,6 +52,11 @@ void Set_NRF24L01_Pins(void)
51 52
 
52 53
 	/* Ensure that the CE pin is set to 0*/
53 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 62
 void Configure_Transmission(void)
@@ -106,32 +112,23 @@ void Configure_Transmission(void)
106 112
 	Set_TX_Address(0x123456);
107 113
 
108 114
 	Set_RX_P0_Address(0x123456);
109
-	
110
-
111 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 121
 void NRF24L01_Send_Message(uint8_t *buffer, uint8_t length)
115 122
 {
116
-	bool transmissionFinished = false;
117
-
118 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 125
 	if ((length > 32) || (length == 0))
131 126
 	{
132 127
 		return;
133 128
 	}
134 129
 
130
+	PCICR |= (1<<PCIE2); // Enable the interrupt for the IRQ signal
131
+
135 132
 	Write_Message_To_TX_FIFO(length, buffer);
136 133
 
137 134
 	/* Set CE = 1 for more than 10 us */
@@ -139,36 +136,33 @@ void NRF24L01_Send_Message(uint8_t *buffer, uint8_t length)
139 136
 	_delay_us(15);
140 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 155
 	/* Reset the interrupts */
168
-	statusRegisterContents.byte = Read_NRF_Status_Register();
169 156
 	statusRegisterContents.bits.TX_DS = 1;
170 157
 	statusRegisterContents.bits.MAX_RT = 1;
158
+	statusRegisterContents.bits.RX_DR = 1;
171 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 168
 void Print_Register_Contents(uint8_t address)

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

@@ -12,9 +12,10 @@
12 12
 #define NRF_CSN_PORT  PORTD
13 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 20
 void Initialize_NRF24L01(void);
20 21
 void Set_NRF24L01_Pins(void);

Loading…
Annulla
Salva