Pārlūkot izejas kodu

Add power save mode and send messages every 7.5s

Bernd Gottschlag 5 gadus atpakaļ
vecāks
revīzija
204ff8d220

+ 8
- 4
weather-sensor/firmware/bme280_interface.c Parādīt failu

@@ -21,10 +21,7 @@ int8_t Initialize_BME280(void)
21 21
 	uint8_t settings_sel;
22 22
 
23 23
 
24
-	/* Setup the SPI interface */
25
-	BME_CSN_DDR |= (1 << BME_CSN_PIN);
26
-	BME_CSN_PORT |= (1 << BME_CSN_PIN);
27
-
24
+	Set_BME280_Pins();
28 25
 
29 26
 	/* Sensor_0 interface over SPI with native chip select line */
30 27
 	deviceStructure.dev_id = 0;
@@ -51,6 +48,13 @@ int8_t Initialize_BME280(void)
51 48
 	return rslt;
52 49
 }
53 50
 
51
+void Set_BME280_Pins(void)
52
+{
53
+	/* Setup the SPI interface */
54
+	BME_CSN_DDR |= (1 << BME_CSN_PIN);
55
+	BME_CSN_PORT |= (1 << BME_CSN_PIN);
56
+}
57
+
54 58
 /* Get one measurement in forced mode */
55 59
 void BME280_Get_Measurement(struct bme280_data * data)
56 60
 {

+ 1
- 0
weather-sensor/firmware/bme280_interface.h Parādīt failu

@@ -10,6 +10,7 @@
10 10
 #define BME_CSN_PIN   PB2
11 11
 
12 12
 int8_t Initialize_BME280(void);
13
+void Set_BME280_Pins(void);
13 14
 void BME280_Get_Measurement(struct bme280_data * data);
14 15
 
15 16
 #endif

+ 138
- 7
weather-sensor/firmware/main.c Parādīt failu

@@ -1,4 +1,6 @@
1 1
 #include <avr/io.h>
2
+#include <avr/interrupt.h>
3
+#include <avr/sleep.h>
2 4
 #include <util/delay.h>
3 5
 #include <stdint.h>
4 6
 #include <stdio.h>
@@ -10,10 +12,6 @@
10 12
 #include "bme280_interface.h"
11 13
 #include "bme280_defs.h"
12 14
 
13
-//#define LED_DDR     DDRB        //DDRA, DDRB...
14
-//#define LED_PORT    PORTB       //PORTA, PORTB...
15
-//#define LED_PORTPIN PB0         //PA0, PA1..., PB0, PB1..., ...
16
-//#define time_off    8
17 15
 
18 16
 /* SPI: */
19 17
 /* TODO: move to spi.h */
@@ -22,14 +20,46 @@
22 20
 #define SPI_MOSI_PIN  PB3
23 21
 #define SPI_MISO_PIN  PB4
24 22
 
23
+/* Debug LED: */
24
+#define LED_DDR   DDRD
25
+#define LED_PORT  PORTD
26
+#define LED_PIN   PD3
25 27
 
26 28
 
27 29
 char bool_case = 0;
28 30
 int timer = 0;
29 31
 int timer_max = 0;
30 32
 
33
+volatile uint8_t cycle = 0;
34
+
35
+volatile uint8_t interruptCounter;
36
+volatile uint8_t executionFlag;
37
+
31 38
 
32 39
 void Initialize_SPI(void);
40
+void Enter_Power_Save_Mode(void);
41
+void Exit_Power_Save_Mode(void);
42
+
43
+
44
+/* TODO Notes for power saving:
45
+ * - Power-save-mode needed -> SM2...0 bits written to 011
46
+ * - Entering by issuing the SLEEP instruction -> What call in C?
47
+ *   - Before executing the SLEEP instruction, write bit SE of the SMCR to 1
48
+ * - Let Timer/Counter2 run with the necessary period and enable an interrupt.
49
+ *   -> The Global Interrupt Enable bit in SREG has to be set.
50
+ * - asynchronous/synchronous clock source?
51
+ * - When waking up
52
+ *   - Set PRR bits for needed peripherals
53
+ * - 
54
+ */
55
+void Set_Up_Power_Save_Mode(void);
56
+void Enter_Power_Save_Mode(void);
57
+
58
+
59
+ISR( TIMER2_COMPA_vect )
60
+{
61
+	/* Do nothing as the interrupt is only used to wake up the MCU. */
62
+}
33 63
 
34 64
 int main (void)
35 65
 {
@@ -38,7 +68,10 @@ int main (void)
38 68
 //	uint8_t registerContent[5];
39 69
 //	char registerContentString[30];
40 70
 //	uint8_t lengthRead;
71
+	uint8_t temp = 0;
41 72
 
73
+	/* Enable the debug LED */
74
+	LED_DDR |= (1 << LED_PIN);
42 75
 
43 76
 	/* Initialize the SPI */
44 77
 	Initialize_SPI();
@@ -52,21 +85,119 @@ int main (void)
52 85
 
53 86
 	/* Initialize the BME280 */
54 87
 	Initialize_BME280();
88
+	Set_Up_Power_Save_Mode();
55 89
 
56 90
 
91
+	/* Delay the change of the operating frequency by the function Enter_Power_Save_Mode for the
92
+	 * first function pass. If it is changed before the ISP can flash the MCU the clocks of the ISP
93
+	 * and MCU are mismatched and the flashing will fail.
94
+	 */
95
+	_delay_ms(500);
57 96
 
58 97
 	while(1)
59 98
 	{
60
-		BME280_Get_Measurement(&sensorData);
61
-		NRF24L01_Send_Message((uint8_t*)&sensorData, sizeof(sensorData));
62
-		_delay_ms(1000);
99
+		Enter_Power_Save_Mode(); // The MCU enters the Power Save Mode here.
100
+		Exit_Power_Save_Mode(); // The MCU exits the Power Save Mode here.
101
+
102
+		if (cycle == 0) // TODO cycle == 7 to execute this every 60 s
103
+		{
104
+			/* Re-Initialize the peripherals */
105
+			Set_BME280_Pins();
106
+			Set_NRF24L01_Pins();
107
+
108
+			/* Get measurement and send it */
109
+			BME280_Get_Measurement(&sensorData);
110
+			NRF24L01_Send_Message((uint8_t*)&sensorData, sizeof(sensorData));
111
+
112
+			if (temp == 0)
113
+			{
114
+				LED_PORT |= (1 << LED_PIN);
115
+				temp = 1;
116
+			}
117
+			else
118
+			{
119
+				temp = 0;
120
+				LED_PORT &= ~(1 << LED_PIN);
121
+			}
122
+
123
+			cycle = 0;
124
+		}
125
+		else
126
+		{
127
+			cycle ++;
128
+		}
63 129
 	}
64 130
 }
65 131
 
66 132
 void Initialize_SPI(void)
67 133
 {
134
+	/* TODO: move to spi.h */
68 135
 	/* Set MOSI and SCK output, all others input */
69 136
 	SPI_DDR = (1<<SPI_MOSI_PIN)|(1<<SPI_SCK_PIN);
70 137
 	/* Enable SPI, Master, set clock rate fck/16 */
71 138
 	SPCR = (1<<SPE)|(1<<MSTR);
72 139
 }
140
+
141
+void Set_Up_Power_Save_Mode(void)
142
+{
143
+	// Disable Brown-Out-Detection by setting the BODLEVEL 2:0 Fuses to 0b111 (should be default)
144
+	// Disable the on-chip debug system by setting the DWEN Fuse to 1 (should be default)
145
+
146
+	/* Disable some unused peripherals that are not used during operation of the weather station: */
147
+	// The ADC is turned off by default
148
+	ACSR &= ~(1<<ACD); // Analog comperator
149
+	ACSR &= ~(1<<ACIE); // The interrupt bit has to be cleared after switchin of the analog comperator
150
+	/*
151
+	 * The Internal voltager reference is automatically disabled if the BOD, ADC and Voltage
152
+	 * Reference are disabled
153
+	 */
154
+
155
+	/* Set up Timer/Counter2 */
156
+	PRR &= ~(1<<PRTIM2); // Enable the timer 2 in the Power Reduction Register
157
+
158
+	TCCR2A |= (1<<COM2A1)|(1<<COM2A0)|(1<<WGM21); // Set the timer to ClearTimer on Compare Match with output compare mode for channel A
159
+	/* There is a problem: The maximum time until the counter 2 overflows is 262ms at the nominal
160
+	 * core frquency of 1MHz and a timer prescaler of 1024.
161
+	 * This can be attenuated by lowering the system frequency to 31.25 kHz via the clock prescaler
162
+	 * (CLKPS3...0) of the register CLKPR. This gives a overflow time of 8.3s.
163
+	 * The cycle time of one minute can thus be accomplished by setting the output compare register
164
+	 * to 229. This spawns an interrupt every 7.5s which means the operation has to be executed
165
+	 * every 8 interrupt calls.
166
+	 */
167
+
168
+	TCCR2B |= (1<<CS22)|(1<<CS21)|(1<<CS20); // Set the timer prescaler to 1/1024
169
+	OCR2A = 229; // TODO: calculate this number from the wanted cycle time and the timer frequency.
170
+
171
+	TIMSK2 |= (1<<OCIE2A); // Enable the Output Compare Match A Interrupt.
172
+
173
+	/* Enable global interrupts: */
174
+	sei();
175
+}
176
+
177
+void Enter_Power_Save_Mode(void)
178
+{
179
+	PRR |= (1<<PRTWI) | (1<<PRTIM0) | (1<<PRTIM1) | (1<<PRSPI) | (1<<PRUSART0) | (1<<PRADC); /* Only timer 2 is needed for wake-up interrupt */
180
+
181
+	/* Set the clock prescaler for a frequency of 32.25 kHz*/
182
+	CLKPR = (1<<CLKPCE);
183
+	CLKPR = (1<<CLKPS3);
184
+
185
+	TCNT2 = 0;// Reset timer 2
186
+	TIMSK2 |= (1<<OCIE2A); // Enable the Output Compare Match A Interrupt.
187
+
188
+
189
+	set_sleep_mode(SLEEP_MODE_PWR_SAVE);
190
+	sleep_mode();
191
+}
192
+
193
+void Exit_Power_Save_Mode(void)
194
+{
195
+	TIMSK2 &= ~(1<<OCIE2A); // Disable the Output Compare Match A Interrupt.
196
+
197
+	/* Set the normal operating frequency of 1 MHz */
198
+	CLKPR = (1<<CLKPCE);
199
+	CLKPR = (1<<CLKPS1) | (1<<CLKPS0);
200
+
201
+	PRR &= ~(1<<PRSPI); // Enable SPI
202
+	Initialize_SPI(); // reinitalize SPI
203
+}

+ 18
- 9
weather-sensor/firmware/nrf24l01.c Parādīt failu

@@ -24,15 +24,7 @@ void Initialize_NRF24L01(void)
24 24
 	CONFIG_REGISTER configRegisterContents = {.byte = 0x0};
25 25
 
26 26
 	/* Configure the AVR pins for the nrf24l01 */
27
-	/* Set up the NRF24L01 */
28
-	NRF_CE_DDR |= (1 << NRF_CE_PIN);
29
-	NRF_CSN_DDR |= (1 << NRF_CSN_PIN);
30
-
31
-	/* Set the chip select pin to not selected */
32
-	NRF_CSN_PORT |= (1 << NRF_CSN_PIN);
33
-
34
-	/* Ensure that the CE pin is set to 0*/
35
-	NRF_CE_PORT &= ~(1 << NRF_CE_PIN);
27
+	Set_NRF24L01_Pins();
36 28
 
37 29
 	/* Wait more than 10.3 ms to make sure the nrf24l01 is running */
38 30
 	_delay_ms(11);
@@ -48,6 +40,19 @@ void Initialize_NRF24L01(void)
48 40
 	/* The NRF24L01 is now in the mode Standby-I */
49 41
 }
50 42
 
43
+void Set_NRF24L01_Pins(void)
44
+{
45
+	/* Set up the NRF24L01 */
46
+	NRF_CE_DDR |= (1 << NRF_CE_PIN);
47
+	NRF_CSN_DDR |= (1 << NRF_CSN_PIN);
48
+
49
+	/* Set the chip select pin to not selected */
50
+	NRF_CSN_PORT |= (1 << NRF_CSN_PIN);
51
+
52
+	/* Ensure that the CE pin is set to 0*/
53
+	NRF_CE_PORT &= ~(1 << NRF_CE_PIN);
54
+}
55
+
51 56
 void Configure_Transmission(void)
52 57
 {
53 58
 	FEATURE_REGISTER featureRegisterContents = {.byte = 0x0};
@@ -138,6 +143,10 @@ void NRF24L01_Send_Message(uint8_t *buffer, uint8_t length)
138 143
 	do
139 144
 	{
140 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
+		 */
141 150
 		statusRegisterContents.byte = Read_NRF_Status_Register();
142 151
 
143 152
 		if (statusRegisterContents.bits.TX_DS == 1)

+ 1
- 0
weather-sensor/firmware/nrf24l01.h Parādīt failu

@@ -13,6 +13,7 @@
13 13
 #define NRF_CSN_PIN   PB6
14 14
 
15 15
 void Initialize_NRF24L01(void);
16
+void Set_NRF24L01_Pins(void);
16 17
 void Configure_Transmission(void);
17 18
 uint8_t Read_NRF_Status_Register(void);
18 19
 uint8_t Read_NRF_Register(uint8_t address, uint8_t * registerContents);

Notiek ielāde…
Atcelt
Saglabāt