7 typedef unsigned int uint;
12 void debug_putc(int c)
14 while (!LL_USART_IsActiveFlag_TXE(USART2))
16 LL_USART_TransmitData8(USART2, c);
19 void debug_puts(const char *s)
33 static void printf_string(const char *s, uint width, uint flags)
36 uint pad = (len < width) ? width - len : 0;
37 char pad_char = (flags & PF_ZERO_PAD) ? '0' : ' ';
43 if (!(flags & PF_LEFT))
47 static void printf_number(uint i, uint width, uint flags, uint base)
50 char *w = buf + sizeof(buf);
52 if (flags & PF_SIGNED)
64 uint digit = i % base;
68 *--w = ((flags & PF_UPPERCASE) ? 'A' : 'a') + digit - 10;
73 if (flags & PF_NEGATIVE)
76 printf_string(w, width, flags);
79 void debug_printf(const char *fmt, ...)
105 flags |= PF_ZERO_PAD;
108 while (*fmt >= '0' && *fmt <= '9')
109 width = 10*width + *fmt++ - '0';
115 printf_number(va_arg(args, int), width, flags | PF_SIGNED, 10);
118 printf_number(va_arg(args, int), width, flags, 10);
121 flags |= PF_UPPERCASE;
124 printf_number(va_arg(args, int), width, flags, 16);
127 printf_string(va_arg(args, char *), width, flags);
140 static uint bmp_read(uint reg, uint bytes)
142 LL_I2C_ClearFlag_STOP(I2C1);
143 LL_I2C_ClearFlag_BERR(I2C1);
144 LL_I2C_HandleTransfer(I2C1, 0xee, LL_I2C_ADDRSLAVE_7BIT, 1, LL_I2C_MODE_SOFTEND, LL_I2C_GENERATE_START_WRITE);
145 while (!LL_I2C_IsActiveFlag_TXE(I2C1))
147 LL_I2C_TransmitData8(I2C1, reg);
148 while (!LL_I2C_IsActiveFlag_TC(I2C1))
150 LL_I2C_HandleTransfer(I2C1, 0xef, LL_I2C_ADDRSLAVE_7BIT, bytes, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_RESTART_7BIT_READ);
153 for (uint i=0; i<bytes; i++)
155 while (!LL_I2C_IsActiveFlag_RXNE(I2C1))
157 d = (d << 8) | LL_I2C_ReceiveData8(I2C1);
163 static uint bmp_measure(uint type, uint bytes)
165 LL_I2C_HandleTransfer(I2C1, 0xee, LL_I2C_ADDRSLAVE_7BIT, 2, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_WRITE);
166 while (!LL_I2C_IsActiveFlag_TXE(I2C1))
168 LL_I2C_TransmitData8(I2C1, 0xf4);
169 while (!LL_I2C_IsActiveFlag_TXE(I2C1))
171 LL_I2C_TransmitData8(I2C1, type);
172 while (!LL_I2C_IsActiveFlag_STOP(I2C1))
175 while (!LL_GPIO_IsInputPinSet(BMP_DONE_GPIO_Port, BMP_DONE_Pin))
178 return bmp_read(0xf6, bytes);
181 // Formulae from BMP085 specs
182 void bmp_recalc(uint UT, uint UP, uint oss, u16 cc[11], int *tt, int *pp)
197 int X1 = (UT-AC6)*AC5 / (1<<15);
198 int X2 = MC*(1<<11) / (X1+MD);
200 int T = (B5+8) / (1<<4);
204 X1 = (B2*(B6*B6/(1<<12))) / (1<<11);
205 X2 = AC2 * B6 / (1<<11);
207 int B3 = (((AC1*4 + X3) << oss) + 2) / 4;
208 X1 = AC3 * B6 / (1<<13);
209 X2 = (B1*(B6*B6/(1<<12))) / (1<<16);
210 X3 = ((X1+X2) + 2) / (1<<2);
211 uint B4 = (uint)(AC4 * (X3 + 32768)) / (1U<<15);
212 uint B7 = (uint)(UP-B3) * (uint)(50000>>oss);
218 X1 = (p/(1<<8)) * (p/(1<<8));
219 X1 = (X1*3038) / (1<<16);
220 X2 = (-7357*p) / (1<<16);
221 p = p + (X1 + X2 + 3791) / (1<<4);
229 LL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
231 debug_puts("Constants:");
233 for (uint i=0; i<11; i++)
235 cc[i] = bmp_read(0xaa + 2*i, 2);
236 debug_printf(" %04x", cc[i]);
240 uint raw_temp = bmp_measure(0x2e, 2);
241 debug_printf("Raw temperature: %04x\r\n", raw_temp);
243 uint oss = 3; // Over-sampling setting
244 uint raw_press = bmp_measure(0xf4 | (oss<<6), 3);
245 debug_printf("Raw pressure: %06x\r\n", raw_press);
248 bmp_recalc(raw_temp, raw_press, oss, cc, &temp, &press);
249 debug_printf("Temperature: %d ddegC\r\n", temp);
250 debug_printf("Pressure: %d Pa\r\n", press);
258 static const byte Gentium23x32[] = {
259 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0x03, 0xF0, 0xFF, 0xFF, 0x0F, 0xF8, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFE, 0x01, 0xE0, 0x3F, 0x3E, 0x00, 0x00, 0x7F, 0x1F, 0x00, 0x00, 0x7C, 0x0F, 0x00, 0x00, 0x78, 0x0F, 0x00, 0x00, 0x78, 0x1F, 0x00, 0x00, 0x78, 0x3F, 0x00, 0x00, 0x78, 0x7F, 0x00, 0x00, 0x3E, 0xFE, 0x07, 0xC0, 0x3F, 0xFE, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x0F, 0xF8, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0x03, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xFC, 0x0F, 0x00, // Code for char 0
260 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x78, 0x00, 0x00, 0x70, 0x78, 0x00, 0x00, 0x78, 0x78, 0x00, 0x00, 0x78, 0x7C, 0x00, 0x00, 0x78, 0x3C, 0x00, 0x00, 0x78, 0xFE, 0xFF, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, // Code for char 1
261 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x80, 0x01, 0x00, 0x78, 0xE0, 0x03, 0x00, 0x7C, 0xF0, 0x03, 0x00, 0x7E, 0xF8, 0x03, 0x80, 0x7F, 0xFC, 0x01, 0xC0, 0x7F, 0xFE, 0x01, 0xE0, 0x7F, 0x3E, 0x00, 0xF0, 0x7F, 0x1E, 0x00, 0xFC, 0x7F, 0x0F, 0x00, 0xFE, 0x79, 0x0F, 0x00, 0xFF, 0x78, 0x0F, 0xC0, 0x7F, 0x78, 0x1F, 0xE0, 0x3F, 0x78, 0x3F, 0xF8, 0x0F, 0x78, 0xFF, 0xFF, 0x07, 0x78, 0xFE, 0xFF, 0x03, 0x78, 0xFE, 0xFF, 0x00, 0x7C, 0xFC, 0x7F, 0x80, 0x7F, 0xF8, 0x1F, 0x80, 0x7F, 0xE0, 0x07, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 2
262 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xC0, 0x00, 0x00, 0x1F, 0xF0, 0x01, 0x00, 0x1E, 0xF8, 0x01, 0x00, 0x3E, 0xFC, 0x01, 0x00, 0x3C, 0xFE, 0x00, 0x00, 0x7C, 0xFE, 0x00, 0x00, 0x78, 0x1E, 0xE0, 0x00, 0x78, 0x0F, 0xF0, 0x00, 0x78, 0x0F, 0xF0, 0x00, 0x78, 0x0F, 0xF0, 0x00, 0x78, 0x1F, 0xF8, 0x01, 0x7C, 0x3F, 0xFC, 0x01, 0x7C, 0xFF, 0xFF, 0x07, 0x3F, 0xFE, 0xFF, 0xFF, 0x3F, 0xFE, 0xFF, 0xFF, 0x1F, 0xFC, 0xCF, 0xFF, 0x0F, 0xF8, 0xC7, 0xFF, 0x07, 0xE0, 0x83, 0xFF, 0x03, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 3
263 0x17, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0xFE, 0x3D, 0x00, 0x00, 0xFF, 0x3C, 0x70, 0xC0, 0x3F, 0x3C, 0x70, 0xE0, 0x1F, 0x3C, 0x70, 0xF8, 0x07, 0x3C, 0x78, 0xFC, 0x03, 0x3C, 0x78, 0xFE, 0xFF, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x3C, 0x78, 0x00, 0x00, 0x3C, 0x70, 0x00, 0x00, 0x1C, 0x70, 0x00, 0x00, 0x08, 0x00, // Code for char 4
264 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xC0, 0x00, 0x1F, 0x00, 0xFE, 0x01, 0x1E, 0xFC, 0xFF, 0x01, 0x3E, 0xFC, 0xFF, 0x00, 0x3C, 0xFC, 0xFF, 0x00, 0x3C, 0xFC, 0x7F, 0x00, 0x78, 0x3C, 0x78, 0x00, 0x78, 0x3C, 0x78, 0x00, 0x78, 0x3C, 0x78, 0x00, 0x78, 0x3C, 0x78, 0x00, 0x78, 0x3C, 0xF8, 0x00, 0x7C, 0x3C, 0xF8, 0x00, 0x7E, 0x3C, 0xF0, 0x03, 0x3F, 0x3C, 0xF0, 0xFF, 0x3F, 0x3C, 0xF0, 0xFF, 0x1F, 0x1E, 0xE0, 0xFF, 0x0F, 0x0F, 0xC0, 0xFF, 0x07, 0x06, 0x80, 0xFF, 0x03, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 5
265 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x07, 0x80, 0xFF, 0xFF, 0x0F, 0xC0, 0xFF, 0xFF, 0x1F, 0xE0, 0xFF, 0xFF, 0x3F, 0xF0, 0xFF, 0xC1, 0x3F, 0xF8, 0xF7, 0x00, 0x7E, 0xF8, 0x71, 0x00, 0x7C, 0xFC, 0x78, 0x00, 0x78, 0x7C, 0x78, 0x00, 0x78, 0x3E, 0x78, 0x00, 0x78, 0x1E, 0xF8, 0x00, 0x7C, 0x1E, 0xF8, 0x03, 0x3E, 0x0F, 0xF0, 0xFF, 0x3F, 0x0F, 0xF0, 0xFF, 0x1F, 0x0F, 0xE0, 0xFF, 0x0F, 0x06, 0xE0, 0xFF, 0x07, 0x00, 0x80, 0xFF, 0x03, 0x00, 0x00, 0x7E, 0x00, // Code for char 6
266 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x20, 0x7C, 0x00, 0x00, 0x78, 0x3C, 0x00, 0x00, 0x7E, 0x3C, 0x00, 0x80, 0x7F, 0x3C, 0x00, 0xE0, 0x3F, 0x3C, 0x00, 0xF8, 0x3F, 0x3C, 0x00, 0xFE, 0x1F, 0x3C, 0x80, 0xFF, 0x0F, 0x3C, 0xE0, 0xFF, 0x01, 0x3C, 0xF8, 0x7F, 0x00, 0x3C, 0xFE, 0x0F, 0x00, 0xFC, 0xFF, 0x03, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x07, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, // Code for char 7
267 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x03, 0xC0, 0x07, 0xFC, 0x07, 0xF0, 0x1F, 0xFE, 0x1F, 0xF8, 0x3F, 0xFF, 0x1F, 0xFC, 0xBF, 0xFF, 0x3F, 0xFE, 0xFF, 0xFF, 0x3F, 0xFE, 0xFF, 0x0F, 0x7E, 0x1F, 0xFE, 0x03, 0x7C, 0x0F, 0xFC, 0x01, 0x78, 0x0F, 0xF8, 0x01, 0x78, 0x0F, 0xF8, 0x01, 0x78, 0x0F, 0xF8, 0x03, 0x78, 0x1F, 0xFC, 0x07, 0x7C, 0xFF, 0xFF, 0x0F, 0x3E, 0xFE, 0xFF, 0xFF, 0x3F, 0xFE, 0xDF, 0xFF, 0x1F, 0xFC, 0xCF, 0xFF, 0x0F, 0xF8, 0x87, 0xFF, 0x07, 0xF0, 0x01, 0xFF, 0x03, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 8
268 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0xF0, 0xFF, 0x01, 0x60, 0xF8, 0xFF, 0x03, 0xE0, 0xFC, 0xFF, 0x07, 0xF0, 0xFC, 0xFF, 0x07, 0xF0, 0x7E, 0xE0, 0x0F, 0xF8, 0x1E, 0x80, 0x0F, 0x78, 0x0F, 0x00, 0x0F, 0x7C, 0x0F, 0x00, 0x0F, 0x7C, 0x0F, 0x00, 0x0F, 0x3E, 0x0F, 0x00, 0x0F, 0x3F, 0x1F, 0x00, 0x87, 0x1F, 0x3F, 0x80, 0xE7, 0x1F, 0xFE, 0xC1, 0xFB, 0x0F, 0xFE, 0xFF, 0xFF, 0x07, 0xFC, 0xFF, 0xFF, 0x03, 0xF8, 0xFF, 0xFF, 0x01, 0xF0, 0xFF, 0x7F, 0x00, 0xC0, 0xFF, 0x1F, 0x00, 0x00, 0xFF, 0x03, 0x00, // Code for char 9
269 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x07, 0xF0, 0x07, 0xE0, 0x0F, 0xF8, 0x07, 0xF0, 0x0F, 0xF8, 0x07, 0xF0, 0x0F, 0xF8, 0x07, 0xF0, 0x0F, 0xF8, 0x07, 0xF0, 0x0F, 0xF8, 0x03, 0xF0, 0x07, 0xF0, 0x01, 0xE0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Code for char :
272 // Based on https://github.com/adafruit/Adafruit_SSD1306
274 #define SSD1306_SETLOWCOLUMN 0x00
275 #define SSD1306_SETHIGHCOLUMN 0x10
276 #define SSD1306_MEMORYMODE 0x20
277 #define SSD1306_SETSTARTLINE 0x40
278 #define SSD1306_SETCONTRAST 0x81
279 #define SSD1306_CHARGEPUMP 0x8D
280 #define SSD1306_SEGREMAP 0xA0
281 #define SSD1306_DISPLAYALLON_RESUME 0xA4
282 #define SSD1306_DISPLAYALLON 0xA5
283 #define SSD1306_NORMALDISPLAY 0xA6
284 #define SSD1306_INVERTDISPLAY 0xA7
285 #define SSD1306_SETMULTIPLEX 0xA8
286 #define SSD1306_DISPLAYOFF 0xAE
287 #define SSD1306_DISPLAYON 0xAF
288 #define SSD1306_SETSTARTPAGE 0xB0
289 #define SSD1306_COMSCANINC 0xC0
290 #define SSD1306_COMSCANDEC 0xC8
291 #define SSD1306_SETDISPLAYOFFSET 0xD3
292 #define SSD1306_SETCOMPINS 0xDA
293 #define SSD1306_SETVCOMDETECT 0xDB
294 #define SSD1306_SETDISPLAYCLOCKDIV 0xD5
295 #define SSD1306_SETPRECHARGE 0xD9
296 #define SSD1306_NOP 0xE3
298 static const byte display_init_cmds[] = {
300 SSD1306_SETDISPLAYCLOCKDIV, 0x80, // the suggested ratio 0x80
301 SSD1306_SETMULTIPLEX, 0x1F, // ratio 32
302 SSD1306_SETDISPLAYOFFSET,0x0, // no offset
303 SSD1306_SETSTARTLINE | 0x0, // line #0
304 SSD1306_CHARGEPUMP, 0x14, // internal vcc
305 SSD1306_MEMORYMODE, 0x02, // page mode
306 SSD1306_SEGREMAP | 0x0, // column 0 mapped to SEG0
307 SSD1306_COMSCANINC, // column scan direction not reversed
308 SSD1306_SETCOMPINS, 0x02, // sequential COM pins, disable remap
309 SSD1306_SETCONTRAST, 0x7F, // contrast level 127
310 SSD1306_SETPRECHARGE, 0xF1, // pre-charge period (1, 15)
311 SSD1306_SETVCOMDETECT, 0x40, // vcomh regulator level-
312 SSD1306_DISPLAYALLON_RESUME,
313 SSD1306_NORMALDISPLAY,
317 static void display_cmd(byte cmd)
319 LL_I2C_ClearFlag_STOP(I2C1);
320 LL_I2C_HandleTransfer(I2C1, 0x79, LL_I2C_ADDRSLAVE_7BIT, 2, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_WRITE);
321 while (!LL_I2C_IsActiveFlag_TXE(I2C1))
323 LL_I2C_TransmitData8(I2C1, 0x00); // Will send a command
324 while (!LL_I2C_IsActiveFlag_TXE(I2C1))
326 LL_I2C_TransmitData8(I2C1, cmd);
327 while (!LL_I2C_IsActiveFlag_STOP(I2C1))
331 static void display_data_start(uint cnt)
333 LL_I2C_ClearFlag_STOP(I2C1);
334 LL_I2C_HandleTransfer(I2C1, 0x79, LL_I2C_ADDRSLAVE_7BIT, cnt + 1, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_WRITE);
335 while (!LL_I2C_IsActiveFlag_TXE(I2C1))
337 LL_I2C_TransmitData8(I2C1, 0x40); // Will send data
340 static void display_data(byte d)
342 while (!LL_I2C_IsActiveFlag_TXE(I2C1))
344 LL_I2C_TransmitData8(I2C1, d);
347 static void display_data_end(void)
349 while (!LL_I2C_IsActiveFlag_STOP(I2C1))
353 static void display_init(void)
355 for (uint i=0; i < sizeof(display_init_cmds); i++)
356 display_cmd(display_init_cmds[i]);
358 for (uint p=0; p<4; p++)
360 display_cmd(SSD1306_SETSTARTPAGE + p);
361 display_cmd(SSD1306_SETHIGHCOLUMN);
362 display_cmd(SSD1306_SETLOWCOLUMN);
363 display_data_start(128);
364 for (uint i=0; i<128; i++)
367 // x = Gentium23x32[(23*4+1)*(i/23) + 1 + 4*(i%23) + p];
374 static void counter(uint cnt)
377 for (uint i=0; i<5; i++)
383 for (uint p=0; p<4; p++)
385 display_cmd(SSD1306_SETSTARTPAGE + p);
386 display_cmd(SSD1306_SETHIGHCOLUMN);
387 display_cmd(SSD1306_SETLOWCOLUMN);
388 display_data_start(5*24);
389 for (uint i=0; i<5; i++)
391 for (uint j=0; j<23; j++)
393 byte x = Gentium23x32[(23*4+1)*d[i] + 1 + 4*j + p];
406 debug_puts("Init\r\n");
411 LL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
413 debug_printf("Tick tock: %d\r\n", cnt);
424 // DS18B20 Temperature Sensor
426 static volatile uint32_t ds_dma_buffer;
428 static void ds_reset(void)
430 // debug_puts("DS18B20: Reset\r\n");
431 LL_TIM_DisableCounter(TIM3);
432 LL_TIM_SetOnePulseMode(TIM3, LL_TIM_ONEPULSEMODE_SINGLE);
434 // DMA for reading pin state
435 ds_dma_buffer = 0xdeadbeef;
436 LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_4, (uint32_t) &ds_dma_buffer);
437 LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_4, (uint32_t) &THERMO_GPIO_Port->IDR);
438 LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, 1);
439 LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4);
441 LL_TIM_OC_InitTypeDef oc;
443 // CC1 is used to drive the DMA (read line state at specified time)
444 LL_TIM_OC_StructInit(&oc);
445 oc.OCMode = LL_TIM_OCMODE_FROZEN;
446 oc.CompareValue = 560;
447 LL_TIM_OC_Init(TIM3, LL_TIM_CHANNEL_CH1, &oc);
448 LL_TIM_EnableDMAReq_CC1(TIM3);
449 LL_TIM_CC_SetDMAReqTrigger(TIM3, LL_TIM_CCDMAREQUEST_CC);
451 // CC2 is used to generate pulses (return line to idle state at specified time)
452 LL_TIM_OC_StructInit(&oc);
453 oc.OCMode = LL_TIM_OCMODE_FORCED_ACTIVE;
454 oc.OCState = LL_TIM_OCSTATE_ENABLE;
455 oc.CompareValue = 480;
456 oc.OCPolarity = LL_TIM_OCPOLARITY_LOW;
457 LL_TIM_OC_Init(TIM3, LL_TIM_CHANNEL_CH2, &oc);
459 // Set timer period to the length of the whole transaction
460 LL_TIM_SetAutoReload(TIM3, 999);
462 // Pull line down and start timer
463 LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_INACTIVE);
464 LL_TIM_EnableCounter(TIM3);
466 // Wait until the timer expires
467 while (LL_TIM_IsEnabledCounter(TIM3))
469 // Counter is automatically disabled at the end of cycle
472 LL_TIM_DisableDMAReq_CC1(TIM3);
473 LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_4);
475 // debug_printf("Init DMA: %08x [%u] (%u remains)\r\n", ds_dma_buffer, !!(ds_dma_buffer & THERMO_Pin), LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_4));
478 static void ds_send_byte(byte b)
480 // debug_printf("DS write: %02x\r\n", b);
481 LL_TIM_SetAutoReload(TIM3, 99); // Each write slot takes 100μs
482 for (uint m=1; m < 0x100; m <<= 1)
484 LL_TIM_OC_SetCompareCH2(TIM3, ((b & m) ? 1 : 89)); // 1: 1μs pulse, 0: 89μs pulse
485 LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_FORCED_ACTIVE);
486 LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_INACTIVE);
487 LL_TIM_EnableCounter(TIM3);
488 while (LL_TIM_IsEnabledCounter(TIM3))
493 static byte ds_recv_byte(void)
495 LL_TIM_SetAutoReload(TIM3, 79); // Each read slot takes 80μs
496 LL_TIM_OC_SetCompareCH2(TIM3, 1); // Generate 1μs pulse to start read slot
497 LL_TIM_OC_SetCompareCH1(TIM3, 8); // Sample data 8μs after start of slot
498 LL_TIM_EnableDMAReq_CC1(TIM3);
501 for (uint m=1; m < 0x100; m <<= 1)
503 ds_dma_buffer = 0xdeadbeef;
504 LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, 1);
505 LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4);
506 LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_FORCED_ACTIVE);
507 LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_INACTIVE);
508 LL_TIM_EnableCounter(TIM3);
509 while (LL_TIM_IsEnabledCounter(TIM3))
511 // FIXME: Using the Pin constant directly is fragile!
512 // debug_printf("XXX %08x\r\n", ds_dma_buffer);
513 if (ds_dma_buffer & THERMO_Pin)
515 LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_4);
518 LL_TIM_DisableDMAReq_CC1(TIM3);
519 // debug_printf("DS read: %02x\r\n", out);
523 static byte ds_buf[10];
525 static int ds_recv_block(uint n)
528 for (uint i=0; i<n; i++)
530 uint b = ds_recv_byte();
532 for (uint j=0; j<8; j++)
534 uint k = (b & 1) ^ (crc >> 7);
535 crc = (crc << 1) & 0xff;
544 debug_printf("WARNING: Invalid CRC %02x\r\n", crc);
554 debug_puts("Init\r\n");
555 NVIC_DisableIRQ(TIM3_IRQn); // One day, we will handle everything from interrupts...
562 // FIXME: Configure precision
566 LL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
567 // debug_printf("Tick tock: %d\r\n", cnt);
573 while (ds_recv_byte() != 0xff)
581 int t = (int16_t)(ds_buf[0] | (ds_buf[1] << 8));
583 debug_printf("Temp: %d.%03d degC\r\n", t/1000, t%1000);