Merge branch 'master' into TweakTS80

This commit is contained in:
Ben V. Brown
2019-10-07 16:40:42 +11:00
262 changed files with 106266 additions and 307801 deletions

View File

@@ -0,0 +1,44 @@
/*
* FRToSI2C.hpp
*
* Created on: 14Apr.,2018
* Author: Ralim
*/
#ifndef FRTOSI2C_HPP_
#define FRTOSI2C_HPP_
#include "stm32f1xx_hal.h"
#include "cmsis_os.h"
class FRToSI2C {
public:
static void init(I2C_HandleTypeDef *i2chandle) {
i2c = i2chandle;
I2CSemaphore = nullptr;
}
static void FRToSInit() {
I2CSemaphore = xSemaphoreCreateBinaryStatic(&xSemaphoreBuffer);
xSemaphoreGive(I2CSemaphore);
}
static void CpltCallback(); //Normal Tx Callback
static void Mem_Read(uint16_t DevAddress, uint16_t MemAddress,
uint16_t MemAddSize, uint8_t *pData, uint16_t Size);
static void Mem_Write(uint16_t DevAddress, uint16_t MemAddress,
uint16_t MemAddSize, uint8_t *pData, uint16_t Size);
static void Transmit(uint16_t DevAddress, uint8_t *pData, uint16_t Size);
static void I2C_RegisterWrite(uint8_t address, uint8_t reg, uint8_t data);
static uint8_t I2C_RegisterRead(uint8_t address, uint8_t reg);
private:
static I2C_HandleTypeDef *i2c;
static void I2C1_ClearBusyFlagErratum();
static SemaphoreHandle_t I2CSemaphore;
static StaticSemaphore_t xSemaphoreBuffer;
};
#endif /* FRTOSI2C_HPP_ */

View File

@@ -0,0 +1,192 @@
/*
* Font.h
*
* Created on: 17 Sep 2016
* Author: Ralim
*
* ... This file contains the font...
*/
#ifndef FONT_H_
#define FONT_H_
#include "Translation.h"
#define FONT_12_WIDTH 12
// FONTS ARE NO LONGER HERE, MOVED TO PYTHON AUTO GEN
const uint8_t ExtraFontChars[] = {
//width = 12
//height = 16
0x00,0x18,0x24,0x24,0x18,0xC0,0x40,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x02,0x02,0x02,0x00,0x00,0x00, // Degrees F
0x00,0x18,0x24,0x24,0x18,0x80,0x40,0x20,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x08,0x10,0x10,0x10,0x00,0x00, // Degrees C
0x00,0x00,0x20,0x30,0x38,0xFC,0xFE,0xFC,0x38,0x30,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x7F,0x7F,0x00,0x00,0x00,0x00, // UP arrow
0x00,0xF0,0x08,0x0E,0x02,0x02,0x02,0x02,0x0E,0x08,0xF0,0x00,0x00,0x3F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x3F,0x00, // Battery Empty
0x00,0xF0,0x08,0x0E,0x02,0x02,0x02,0x02,0x0E,0x08,0xF0,0x00,0x00,0x3F,0x40,0x50,0x50,0x50,0x50,0x50,0x50,0x40,0x3F,0x00, // Battery 1*/
0x00,0xF0,0x08,0x0E,0x02,0x02,0x02,0x02,0x0E,0x08,0xF0,0x00,0x00,0x3F,0x40,0x58,0x58,0x58,0x58,0x58,0x58,0x40,0x3F,0x00, // Battery 2*/
0x00,0xF0,0x08,0x0E,0x02,0x02,0x02,0x02,0x0E,0x08,0xF0,0x00,0x00,0x3F,0x40,0x5C,0x5C,0x5C,0x5C,0x5C,0x5C,0x40,0x3F,0x00, // Battery 3*/
0x00,0xF0,0x08,0x0E,0x02,0x02,0x02,0x02,0x0E,0x08,0xF0,0x00,0x00,0x3F,0x40,0x5E,0x5E,0x5E,0x5E,0x5E,0x5E,0x40,0x3F,0x00, // Battery 4*/
0x00,0xF0,0x08,0x0E,0x02,0x02,0x02,0x02,0x0E,0x08,0xF0,0x00,0x00,0x3F,0x40,0x5F,0x5F,0x5F,0x5F,0x5F,0x5F,0x40,0x3F,0x00, // Battery 5*/
0x00,0xF0,0x08,0x8E,0x82,0x82,0x82,0x82,0x8E,0x08,0xF0,0x00,0x00,0x3F,0x40,0x5F,0x5F,0x5F,0x5F,0x5F,0x5F,0x40,0x3F,0x00, // Battery 6*/
0x00,0xF0,0x08,0xCE,0xC2,0xC2,0xC2,0xC2,0xCE,0x08,0xF0,0x00,0x00,0x3F,0x40,0x5F,0x5F,0x5F,0x5F,0x5F,0x5F,0x40,0x3F,0x00, // Battery 7*/
0x00,0xF0,0x08,0xEE,0xE2,0xE2,0xE2,0xE2,0xEE,0x08,0xF0,0x00,0x00,0x3F,0x40,0x5F,0x5F,0x5F,0x5F,0x5F,0x5F,0x40,0x3F,0x00, // Battery 8*/
0x00,0xF0,0x08,0xEE,0xE2,0xF2,0xF2,0xE2,0xEE,0x08,0xF0,0x00,0x00,0x3F,0x40,0x5F,0x5F,0x5F,0x5F,0x5F,0x5F,0x40,0x3F,0x00, // Battery 9*/
0x00,0xF0,0x08,0xEE,0xE2,0xFA,0xFA,0xE2,0xEE,0x08,0xF0,0x00,0x00,0x3F,0x40,0x5F,0x5F,0x5F,0x5F,0x5F,0x5F,0x40,0x3F,0x00, // Battery 10*/
0x00,0x00,0x38,0xC4,0x00,0x38,0xC4,0x00,0x38,0xC4,0x00,0x00,0x00,0x38,0x3A,0x39,0x38,0x3A,0x39,0x38,0x3A,0x39,0x10,0x10, // heating
0x00,0x60,0xE0,0xFE,0xE0,0xE0,0xE0,0xE0,0xFE,0xE0,0x60,0x00,0x00,0x00,0x00,0x01,0x03,0xFF,0xFF,0x03,0x01,0x00,0x00,0x00, // AC
0xFC,0x02,0x02,0x02,0x02,0x02,0x02,0x82,0x62,0x1A,0x02,0xFC,0x3F,0x40,0x42,0x46,0x4C,0x58,0x46,0x41,0x40,0x40,0x40,0x3F, // ☑ (check box on, menu true)
0xFC,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0xFC,0x3F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x3F, // ☐ (check box off, menu false)
/*
0x00,0x00,0x00,0x80,0x80,0xFE,0xFF,0x83,0x87,0x06,0x00,0x00,0x00,0x00,0x30,0x70,0x60,0x7F,0x3F,0x00,0x00,0x00,0x00,0x00, // Function?
0x00,0x70,0xFA,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xFF,0xFE,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x00,0x00, // a_
0x00,0x3C,0x7E,0xE7,0xC3,0xC3,0xC3,0xC3,0xE7,0x7E,0x3C,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x00,0x00, // 0_
0x55,0x00,0xAA,0x00,0x55,0x00,0xAA,0x00,0x55,0x00,0xAA,0x00,0x55,0x00,0xAA,0x00,0x55,0x00,0xAA,0x00,0x55,0x00,0xAA,0x00, // 25% block
0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55, // 50% pipe
0xAA,0xFF,0x55,0xFF,0xAA,0xFF,0x55,0xFF,0xAA,0xFF,0x55,0xFF,0xAA,0xFF,0x55,0xFF,0xAA,0xFF,0x55,0xFF,0xAA,0xFF,0x55,0xFF, // 75% block
0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00, // | pipe
0x80,0x80,0x80,0x80,0x80,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00, // T pipe ,|
0xC0,0xC0,0xFF,0xFF,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x06,0x06,0xFE,0xFE,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00, // ,| double pipe
0x00,0x00,0xFF,0xFF,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00, // || double pipe
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x06,0x06,0xFE,0xFE,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00, // #NAME?//#NAME?
0xC0,0xC0,0xFF,0xFF,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x00,0x00,0x00,0x00,0x00, // ,^ double pupe
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00, // #NAME?//#NAME?
0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01, // ,> pipe
0x80,0x80,0x80,0x80,0x80,0xFF,0xFF,0x80,0x80,0x80,0x80,0x80,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, // _|_ pipe
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x01,0x01,0x01,0x01,0x01,0xFF,0xFF,0x01,0x01,0x01,0x01,0x01, // ,|, pipe
0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x01,0x01,0x01,0x01,0x01, // |, pipe
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, // #NAME?//#NAME?
0x80,0x80,0x80,0x80,0x80,0xFF,0xFF,0x80,0x80,0x80,0x80,0x80,0x01,0x01,0x01,0x01,0x01,0xFF,0xFF,0x01,0x01,0x01,0x01,0x01, // #NAME?//#NAME?
0x00,0x00,0xFF,0xFF,0x00,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x07,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, // ,> double pipe
0x00,0x00,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0xFF,0xFF,0x00,0xFE,0xFE,0x06,0x06,0x06,0x06,0x06, // ^, double pipe
0xC0,0xC0,0xFF,0xFF,0x00,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xC0,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, // _|_ double pipe
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x06,0x06,0xFE,0xFE,0x00,0xFE,0xFE,0x06,0x06,0x06,0x06,0x06, // ,|, double pipe
0x00,0x00,0xFF,0xFF,0x00,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0xFF,0xFF,0x00,0xFE,0xFE,0x06,0x06,0x06,0x06,0x06, // |, double pipe
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, // == double pipe
0xC0,0xC0,0xFF,0xFF,0x00,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xC0,0x06,0x06,0xFE,0xFE,0x00,0xFE,0xFE,0x06,0x06,0x06,0x06,0x06, // #NAME?//#NAME?
0x00,0x00,0x00,0x78,0xFC,0xCC,0x8C,0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x3E,0x33,0x33,0x3F,0x1E,0x00,0x00,0x00, // Delta lowercase
0x00,0x00,0x00,0x00,0x00,0x7E,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 27 (')
0x80,0x80,0x80,0x80,0x80,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00, // ,^ pipe
0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x01,0x01,0x01,0x01,0x01, // | , pipe
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // solid block
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // half block bottom
0x00,0x00,0x00,0x00,0x00,0xBF,0xBF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x3F,0x00,0x00,0x00,0x00,0x00, // 7C (|)
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // top half solid block
0x00,0x00,0x0C,0xFC,0xFC,0x6C,0x60,0x60,0xE0,0xC0,0x00,0x00,0x00,0x00,0x30,0x3F,0x3F,0x36,0x06,0x06,0x07,0x03,0x00,0x00, // DE small
0x00,0x00,0x03,0xFF,0xFF,0x1B,0x18,0x18,0xF8,0xF0,0x00,0x00,0x00,0x00,0x30,0x3F,0x3F,0x36,0x06,0x06,0x07,0x03,0x00,0x00, // DE large
0x00,0x00,0x00,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ? (,)
0x00,0x00,0x00,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x06,0x06,0x00,0x00,0x00, // =
0x00,0x00,0x00,0x40,0x80,0x80,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // sideways comma
0x00,0x00,0x80,0xC0,0x80,0x00,0x00,0x80,0xC0,0x80,0x00,0x00,0x00,0x00,0x01,0x03,0x01,0x00,0x00,0x01,0x03,0x01,0x00,0x00, // ..
0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x01,0x00,0x00,0x00,0x00, // .
0x00,0x00,0x02,0x1F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // tiny 1
0x00,0x00,0x00,0x00,0xF0,0xF0,0xF0,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x03,0x03,0x00,0x00,0x00,0x00, // small block
*/
};
const uint8_t FontSymbols[] = {
0x00,0x00,0x00,0xFC,0xF8,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x0F,0x07,0x03,0x01,0x00,0x00,0x00,0x00, // Right block
0x00,0x00,0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x07,0x0F,0x1F,0x00,0x00,0x00, // left block
0x00,0x00,0x00,0x10,0x18,0x1C,0xFE,0x1C,0x18,0x10,0x00,0x00,0x00,0x00,0x00,0x04,0x0C,0x1C,0x3F,0x1C,0x0C,0x04,0x00,0x00, // UD arrow
0x00,0x00,0x00,0xFE,0xFE,0x00,0x00,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x37,0x00,0x00,0x37,0x37,0x00,0x00,0x00, // !!
0x00,0x38,0x7C,0xC6,0x82,0xFE,0xFE,0x02,0xFE,0xFE,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x3F,0x00,0x3F,0x3F,0x00,0x00, // paragraph
0x00,0x00,0xDC,0xFE,0x22,0x22,0x22,0x22,0xE6,0xC4,0x00,0x00,0x00,0x00,0x08,0x19,0x11,0x11,0x11,0x11,0x1F,0x0E,0x00,0x00, // section
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x00, // cursor
0x00,0x00,0x00,0x08,0x0C,0x0E,0xFF,0x0E,0x0C,0x08,0x00,0x00,0x00,0x00,0x00,0x44,0x4C,0x5C,0x7F,0x5C,0x4C,0x44,0x00,0x00, // UD arrow
0x00,0x00,0x00,0x10,0x18,0x1C,0xFE,0x1C,0x18,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,0x00, // UP arrow
0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0C,0x1C,0x3F,0x1C,0x0C,0x04,0x00,0x00, // Down arrow
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x03,0x01,0x00,0x00, // right arrow
0x00,0x00,0x80,0xC0,0xE0,0xF0,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x01,0x03,0x07,0x00,0x00,0x00,0x00,0x00,0x00, // left arrow
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,
0x00,0x80,0xC0,0xE0,0xF0,0x80,0x80,0x80,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x01,0x03,0x07,0x00,0x00,0x00,0x07,0x03,0x01,0x00, // LR arrow
0x00,0x00,0x00,0x00,0x80,0xC0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x04,0x06,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x06,0x04, // UP block
0x00,0x20,0x60,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0x60,0x20,0x00,0x00,0x00,0x00,0x01,0x03,0x07,0x03,0x01,0x00,0x00,0x00 // Down block
};
const uint8_t WarningBlock24[] = {
//width = 24
//height = 16
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x30,0x0C,0x02,0xF1,0xF1,0xF1,0x02,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xC0,0xB0,0x8C,0x83,0x80,0x80,0x80,0x80,0xB3,0xB3,0xB3,0x80,0x80,0x80,0x80,0x83,0x8C,0xB0,0xC0,0x00,0x00
};
const uint8_t idleScreenBG[] = {
//width = 84
//height = 16
0x00,0xE0,0x18,0x04,0x02,0x02,0x01,0x41,0x61,0x61,0x61,0xE1,0xC1,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
0x81,0x81,0x81,0x81,0xC1,0xE1,0x61,0x61,0x61,0x41,0x01,0x01,0x02,0x02,0x04,0x18,0xE0,0x00,0x00,0xE0,0x18,0x04,0x02,0x02,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x99,0x65,0x01,0x01,0x81,0x41,0x01,0x02,0x02,0x04,0x18,0xE0,
0x00,0x07,0x18,0x20,0x40,0x40,0x80,0x82,0x86,0x86,0x86,0x87,0x83,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
0x81,0x81,0x81,0x81,0x83,0x87,0x86,0x86,0x86,0x82,0x80,0x80,0x40,0x40,0x20,0x18,0x07,0x00,0x00,0x07,0x18,0x20,0x40,0x40,
0x80,0x82,0x87,0x85,0x85,0x85,0x85,0x87,0x87,0x85,0x87,0x85,0x87,0x87,0x82,0x82,0x82,0x80,0x82,0x80,0x82,0x82,0x82,0x92,
0x8A,0x84,0x82,0x81,0x80,0x80,0x80,0x40,0x40,0x20,0x18,0x07
};
const uint8_t idleScreenBGF[] = {
//width = 84
//height = 16
0xE0,0x18,0x04,0x02,0x02,0x01,0x41,0x81,0x01,0x01,0x65,0x99,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x02,0x04,0x18,0xE0,0x00,0x00,0xE0,0x18,0x04,0x02,0x02,
0x01,0x01,0x41,0x61,0x61,0x61,0xE1,0xC1,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0xC1,
0xE1,0x61,0x61,0x61,0x41,0x01,0x02,0x02,0x04,0x18,0xE0,0x00,
0x07,0x18,0x20,0x40,0x40,0x80,0x80,0x80,0x81,0x82,0x84,0x8A,0x92,0x82,0x82,0x82,0x80,0x82,0x80,0x82,0x82,0x82,0x87,0x87,
0x85,0x87,0x85,0x87,0x87,0x85,0x85,0x85,0x85,0x87,0x82,0x80,0x40,0x40,0x20,0x18,0x07,0x00,0x00,0x07,0x18,0x20,0x40,0x40,
0x80,0x80,0x82,0x86,0x86,0x86,0x87,0x83,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x83,
0x87,0x86,0x86,0x86,0x82,0x80,0x40,0x40,0x20,0x18,0x07,0x00
};
/*
* 16x16 icons
* */
const uint8_t SettingsMenuIcons[] = {
// Soldering
//width = 16
//height = 16
0x00, 0x02, 0x04, 0x08, 0x12, 0x24, 0xC4, 0x42, 0x82, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x02, 0x07, 0x0A, 0x14, 0x28, 0x50,
0x60, 0x00,
//Sleep
//width = 16
//height = 16
0x00, 0xC6, 0xE6, 0xF6, 0xBE, 0x9E, 0x8E, 0x86, 0x00, 0x00,
0x40, 0x40, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x01, 0x01, 0x01,
0x45, 0x65, 0x75, 0x5D, 0x4C, 0x00, 0x06, 0x07, 0x07, 0x05,
0x04, 0x00,
//Menu
//width = 16
//height = 16
0x00,0x80,0x06,0x86,0x46,0x06,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x00,
0x00,0x00,0x61,0x60,0x00,0x00,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x00,
//Wrench
///width = 16
//height = 16
0x00, 0x18, 0x30, 0x32, 0x7E, 0x7C, 0xF0, 0xC0, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x03, 0x0F, 0x3E, 0x7E, 0x4C, 0x0C,
0x18, 0x00,
#ifdef NOTUSED
//Calibration (Not used, kept for future menu layouts)
//width = 16
//height = 16
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE8, 0x70,
0x7A, 0x5E, 0x8E, 0x1C, 0x30, 0x00, 0x00, 0x10, 0x38, 0x1C,
0x0E, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
#endif
};
#endif /* FONT_H_ */

View File

@@ -0,0 +1,173 @@
/*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
This file is part of the FreeRTOS distribution.
FreeRTOS is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License (version 2) as published by the
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
***************************************************************************
>>! NOTE: The modification to the GPL is included to allow you to !<<
>>! distribute a combined work that includes FreeRTOS without being !<<
>>! obliged to provide the source code for proprietary components !<<
>>! outside of the FreeRTOS kernel. !<<
***************************************************************************
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. Full license text is available on the following
link: http://www.freertos.org/a00114.html
***************************************************************************
* *
* FreeRTOS provides completely free yet professionally developed, *
* robust, strictly quality controlled, supported, and cross *
* platform software that is more than just the market leader, it *
* is the industry's de facto standard. *
* *
* Help yourself get started quickly while simultaneously helping *
* to support the FreeRTOS project by purchasing a FreeRTOS *
* tutorial book, reference manual, or both: *
* http://www.FreeRTOS.org/Documentation *
* *
***************************************************************************
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
the FAQ page "My application does not run, what could be wrong?". Have you
defined configASSERT()?
http://www.FreeRTOS.org/support - In return for receiving this top quality
embedded software for free we request you assist our global community by
participating in the support forum.
http://www.FreeRTOS.org/training - Investing in training allows your team to
be as productive as possible as early as possible. Now you can receive
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
Ltd, and the world's leading authority on the world's leading RTOS.
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
compatible FAT file system, and our tiny thread aware UDP/IP stack.
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
licenses offer ticketed support, indemnification and commercial middleware.
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
engineered and independently SIL3 certified version for use in safety and
mission critical applications that require provable dependability.
1 tab == 4 spaces!
*/
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html.
*----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* Section where include file can be added */
/* USER CODE END Includes */
/* Ensure stdint is only used by the compiler, and not the assembler. */
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
#include <stdint.h>
extern uint32_t SystemCoreClock;
#endif
#define configUSE_PREEMPTION 1
#define configSUPPORT_STATIC_ALLOCATION 1
#define configSUPPORT_DYNAMIC_ALLOCATION 0
#define configUSE_IDLE_HOOK 1
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ( SystemCoreClock )
#define configTICK_RATE_HZ ((TickType_t)100)
#define configMAX_PRIORITIES ( 4 )
#define configMINIMAL_STACK_SIZE ((uint16_t)256)
#define configTOTAL_HEAP_SIZE ((size_t)1024*14) /*Currently use about 9000*/
#define configMAX_TASK_NAME_LEN ( 24 )
#define configUSE_16_BIT_TICKS 0
#define configUSE_MUTEXES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#define configCHECK_FOR_STACK_OVERFLOW 2 /*Bump this to 2 during development and bug hunting*/
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 0
#define INCLUDE_vTaskDelete 0
#define INCLUDE_vTaskCleanUpResources 0
#define INCLUDE_vTaskSuspend 0
#define INCLUDE_vTaskDelayUntil 0
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#define configPRIO_BITS 4
#endif
/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
/* Interrupt priorities used by the kernel port layer itself. These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
/* USER CODE BEGIN 1 */
#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}
/* USER CODE END 1 */
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names. */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
/* IMPORTANT: This define MUST be commented when used with STM32Cube firmware,
to prevent overwriting SysTick_Handler defined within STM32Cube HAL */
/* #define xPortSysTickHandler SysTick_Handler */
/* USER CODE BEGIN Defines */
/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */
/* USER CODE END Defines */
#endif /* FREERTOS_CONFIG_H */

View File

@@ -0,0 +1,42 @@
/*
* LIS2DH12.hpp
*
* Created on: 27Feb.,2018
* Author: Ralim
*/
#ifndef LIS2DH12_HPP_
#define LIS2DH12_HPP_
#include "stm32f1xx_hal.h"
#include "FRToSI2C.hpp"
#include "LIS2DH12_defines.hpp"
#include "hardware.h"
class LIS2DH12 {
public:
static void initalize();
//1 = rh, 2,=lh, 8=flat
static Orientation getOrientation() {
#ifdef MODEL_TS80
uint8_t val = (FRToSI2C::I2C_RegisterRead(LIS2DH_I2C_ADDRESS,
LIS_INT2_SRC) >> 2);
if (val == 8)
val = 3;
else if (val == 1)
val = 1;
else if (val == 2)
val = 0;
else
val = 3;
return static_cast<Orientation>(val);
#endif
#ifdef MODEL_TS100
return static_cast<Orientation>((FRToSI2C::I2C_RegisterRead(LIS2DH_I2C_ADDRESS,LIS_INT2_SRC) >> 2) - 1);
#endif
}
static void getAxisReadings(int16_t& x, int16_t& y, int16_t& z);
private:
};
#endif /* LIS2DH12_HPP_ */

View File

@@ -0,0 +1,28 @@
/*
* LIS2DH12_defines.hpp
*
* Created on: 27Feb.,2018
* Author: Ralim
*/
#ifndef LIS2DH12_DEFINES_HPP_
#define LIS2DH12_DEFINES_HPP_
#define LIS2DH_I2C_ADDRESS (25<<1)
#define LIS_CTRL_REG1 0x20|0x80
#define LIS_CTRL_REG2 0x21|0x80
#define LIS_CTRL_REG3 0x22|0x80
#define LIS_CTRL_REG4 0x23|0x80
#define LIS_CTRL_REG5 0x24|0x80
#define LIS_CTRL_REG6 0x25|0x80
#define LIS_INT1_CFG 0xB0|0x80
#define LIS_INT2_CFG 0xB4|0x80
#define LIS_INT1_DURATION 0x33|0x80
#define LIS_INT1_THS 0x32|0x80
#define LIS_INT1_SRC 0x31|0x80
#define LIS_INT2_DURATION 0x37|0x80
#define LIS_INT2_THS 0x36|0x80
#define LIS_INT2_SRC 0x35|0x80
#endif /* LIS2DH12_DEFINES_HPP_ */

View File

@@ -0,0 +1,27 @@
/*
* MMA8652FC.h
*
* Created on: 31Aug.,2017
* Author: Ben V. Brown
*/
#ifndef MMA8652FC_HPP_
#define MMA8652FC_HPP_
#include "stm32f1xx_hal.h"
#include "MMA8652FC_defines.h"
#include "FRToSI2C.hpp"
#include "hardware.h"
class MMA8652FC {
public:
static void initalize(); // Initalize the system
static Orientation getOrientation();// Reads the I2C register and returns the orientation (true == left)
static void getAxisReadings(int16_t& x, int16_t& y, int16_t& z);
private:
};
#endif /* MMA8652FC_HPP_ */

View File

@@ -0,0 +1,124 @@
/*
* MMA8652FC_defines.h
*
* Created on: 31Aug.,2017
* Author: Ben V. Brown
*/
#ifndef MMA8652FC_DEFINES_H_
#define MMA8652FC_DEFINES_H_
//--------------MMA8652 Registers-------------------------------------------//
#define STATUS_REG 0x00 // STATUS Register
#define OUT_X_MSB_REG 0x01 // [7:0] are 8 MSBs of the 14-bit X-axis sample
#define OUT_X_LSB_REG 0x02 // [7:2] are the 6 LSB of 14-bit X-axis sample
#define OUT_Y_MSB_REG 0x03 // [7:0] are 8 MSBs of the 14-bit Y-axis sample
#define OUT_Y_LSB_REG 0x04 // [7:2] are the 6 LSB of 14-bit Y-axis sample
#define OUT_Z_MSB_REG 0x05 // [7:0] are 8 MSBs of the 14-bit Z-axis sample
#define OUT_Z_LSB_REG 0x06 // [7:2] are the 6 LSB of 14-bit Z-axis sample
#define F_SETUP_REG 0x09 // F_SETUP FIFO Setup Register
#define TRIG_CFG_REG 0x0A // TRIG_CFG Map of FIFO data capture events
#define SYSMOD_REG 0x0B // SYSMOD System Mode Register
#define INT_SOURCE_REG 0x0C // INT_SOURCE System Interrupt Status Register
#define WHO_AM_I_REG 0x0D // WHO_AM_I Device ID Register
#define XYZ_DATA_CFG_REG 0x0E // XYZ_DATA_CFG Sensor Data Configuration Register
#define HP_FILTER_CUTOFF_REG 0x0F // HP_FILTER_CUTOFF High Pass Filter Register
#define PL_STATUS_REG 0x10 // PL_STATUS Portrait/Landscape Status Register
#define PL_CFG_REG 0x11 // PL_CFG Portrait/Landscape Configuration Register
#define PL_COUNT_REG 0x12 // PL_COUNT Portrait/Landscape Debounce Register
#define PL_BF_ZCOMP_REG 0x13 // PL_BF_ZCOMP Back/Front and Z Compensation Register
#define P_L_THS_REG 0x14 // P_L_THS Portrait to Landscape Threshold Register
#define FF_MT_CFG_REG 0x15 // FF_MT_CFG Freefall and Motion Configuration Register
#define FF_MT_SRC_REG 0x16 // FF_MT_SRC Freefall and Motion Source Register
#define FF_MT_THS_REG 0x17 // FF_MT_THS Freefall and Motion Threshold Register
#define FF_MT_COUNT_REG 0x18 // FF_MT_COUNT Freefall Motion Count Register
#define TRANSIENT_CFG_REG 0x1D // TRANSIENT_CFG Transient Configuration Register
#define TRANSIENT_SRC_REG 0x1E // TRANSIENT_SRC Transient Source Register
#define TRANSIENT_THS_REG 0x1F // TRANSIENT_THS Transient Threshold Register
#define TRANSIENT_COUNT_REG 0x20 // TRANSIENT_COUNT Transient Debounce Counter Register
#define PULSE_CFG_REG 0x21 // PULSE_CFG Pulse Configuration Register
#define PULSE_SRC_REG 0x22 // PULSE_SRC Pulse Source Register
#define PULSE_THSX_REG 0x23 // PULSE_THS XYZ Pulse Threshold Registers
#define PULSE_THSY_REG 0x24
#define PULSE_THSZ_REG 0x25
#define PULSE_TMLT_REG 0x26 // PULSE_TMLT Pulse Time Window Register
#define PULSE_LTCY_REG 0x27 // PULSE_LTCY Pulse Latency Timer Register
#define PULSE_WIND_REG 0x28 // PULSE_WIND Second Pulse Time Window Register
#define ASLP_COUNT_REG 0x29 // ASLP_COUNT Auto Sleep Inactivity Timer Register
#define CTRL_REG1 0x2A // CTRL_REG1 System Control 1 Register
#define CTRL_REG2 0x2B // CTRL_REG2 System Control 2 Register
#define CTRL_REG3 0x2C // CTRL_REG3 Interrupt Control Register
#define CTRL_REG4 0x2D // CTRL_REG4 Interrupt Enable Register
#define CTRL_REG5 0x2E // CTRL_REG5 Interrupt Configuration Register
#define OFF_X_REG 0x2F // XYZ Offset Correction Registers
#define OFF_Y_REG 0x30
#define OFF_Z_REG 0x31
//MMA8652FC 7-bit I2C address
#define MMA8652FC_I2C_ADDRESS (0x1D<<1)
//MMA8652FC Sensitivity
#define SENSITIVITY_2G 1024
#define SENSITIVITY_4G 512
#define SENSITIVITY_8G 256
#define STATUS_REG 0x00
#define X_MSB_REG 0X01
#define X_LSB_REG 0X02
#define Y_MSB_REG 0X03
#define Y_LSB_REG 0X04
#define Z_MSB_REG 0X05
#define Z_LSB_REG 0X06
#define TRIG_CFG 0X0A
#define SYSMOD 0X0B
#define INT_SOURCE 0X0C
#define DEVICE_ID 0X0D
//-----STATUS_REG(0X00)-----Bit Define----------------------------------------//
#define ZYXDR_BIT 0X08
//----XYZ_DATA_CFG_REG(0xE)-Bit Define----------------------------------------//
#define FS_MASK 0x03
#define FULL_SCALE_2G 0x00 //2g=0x0,4g=0x1,8g=0x2
#define FULL_SCALE_4G 0x01
#define FULL_SCALE_8G 0x02
//---------CTRL_REG1(0X2A)Bit Define------------------------------------------//
#define ACTIVE_MASK 1<<0 //bit0
#define DR_MASK 0x38 //bit D5,D4,D3
#define FHZ800 0x0 //800hz
#define FHZ400 0x1 //400hz
#define FHZ200 0x2 //200hz
#define FHZ100 0x3 //100hz
#define FHZ50 0x4 //50hz
#define FHZ2 0x5 //12.5hz
#define FHZ1 0x6 //6.25hz
#define FHZ0 0x7 //1.563hz
//---------CTRL_REG2(0X2B)Bit Define------------------------------------------//
#define MODS_MASK 0x03 //Oversampling Mode 4
#define Normal_Mode 0x0 //Normal=0,Low Noise Low Power MODS=1,
//HI RESOLUTION=2,LOW POWER MODS = 11
//----CTRL_REG4---Interrupt Enable BIT ---------------------------------------//
//0 interrupt is disabled (default)
//1 interrupt is enabled
#define INT_EN_ASLP 1<<7 //Auto-SLEEP/WAKE Interrupt Enable
#define INT_EN_FIFO 1<<6 //FIFO Interrupt Enable
#define INT_EN_TRANS 1<<5 //Transient Interrupt Enable
#define INT_EN_LNDPRT 1<<4 //Orientation(Landscape/Portrait)Interrupt Enable
#define INT_EN_PULSE 1<<3 //Pulse Detection Interrupt Enable
#define INT_EN_FF_MT 1<<2 //Freefall/Motion Interrupt Enable
#define INT_EN_DRDY 1<<0 //Data Ready Interrupt Enable
#endif /* MMA8652FC_DEFINES_H_ */

View File

@@ -0,0 +1,112 @@
/*
* OLED.hpp
*
* Created on: 20Jan.,2017
* Author: Ben V. Brown <Ralim>
* Designed for the SSD1307
* Cleared for release for TS100 2017/08/20
*/
#ifndef OLED_HPP_
#define OLED_HPP_
#include <hardware.h>
#include "stm32f1xx_hal.h"
#include <stdbool.h>
#include <string.h>
#include "FRToSI2C.hpp"
#include "Font.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "FreeRTOS.h"
#ifdef __cplusplus
}
#endif
#define DEVICEADDR_OLED (0x3c<<1)
#define OLED_WIDTH 96
#define FRAMEBUFFER_START 17
class OLED {
public:
enum DisplayState : bool {
OFF = false,
ON = true
};
static void initialize(); // Startup the I2C coms (brings screen out of reset etc)
// Draw the buffer out to the LCD using the DMA Channel
static void refresh() {
FRToSI2C::Transmit( DEVICEADDR_OLED, screenBuffer,
FRAMEBUFFER_START + (OLED_WIDTH * 2));
//DMA tx time is ~ 20mS Ensure after calling this you delay for at least 25ms
//or we need to goto double buffering
}
static void setDisplayState(DisplayState state) {
displayState = state;
screenBuffer[1] = (state == ON) ? 0xAF : 0xAE;
}
static void setRotation(bool leftHanded); // Set the rotation for the screen
// Get the current rotation of the LCD
static bool getRotation() {
return inLeftHandedMode;
}
static int16_t getCursorX() {
return cursor_x;
}
static void print(const char* string);// Draw a string to the current location, with current font
// Set the cursor location by pixels
static void setCursor(int16_t x, int16_t y) {
cursor_x = x;
cursor_y = y;
}
//Set cursor location by chars in current font
static void setCharCursor(int16_t x, int16_t y) {
cursor_x = x * fontWidth;
cursor_y = y * fontHeight;
}
static void setFont(uint8_t fontNumber); // (Future) Set the font that is being used
static void drawImage(const uint8_t* buffer, uint8_t x, uint8_t width) {
drawArea(x, 0, width, 16, buffer);
}
// Draws an image to the buffer, at x offset from top to bottom (fixed height renders)
static void printNumber(uint16_t number, uint8_t places);
// Draws a number at the current cursor location
// Clears the buffer
static void clearScreen() {
memset(&screenBuffer[FRAMEBUFFER_START], 0, OLED_WIDTH * 2);
}
// Draws the battery level symbol
static void drawBattery(uint8_t state) {
drawSymbol(3 + (state > 10 ? 10 : state));
}
// Draws a checkbox
static void drawCheckbox(bool state) {
drawSymbol((state) ? 16 : 17);
}
static void debugNumber(int32_t val);
static void drawSymbol(uint8_t symbolID);//Used for drawing symbols of a predictable width
static void drawArea(int16_t x, int8_t y, uint8_t wide, uint8_t height,
const uint8_t* ptr); //Draw an area, but y must be aligned on 0/8 offset
static void fillArea(int16_t x, int8_t y, uint8_t wide, uint8_t height,
const uint8_t value); //Fill an area, but y must be aligned on 0/8 offset
static void drawFilledRect(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1,
bool clear);
static void drawHeatSymbol(uint8_t state);
private:
static void drawChar(char c); // Draw a character to a specific location
static const uint8_t* currentFont;// Pointer to the current font used for rendering to the buffer
static uint8_t* firstStripPtr; // Pointers to the strips to allow for buffer having extra content
static uint8_t* secondStripPtr; //Pointers to the strips
static bool inLeftHandedMode; // Whether the screen is in left or not (used for offsets in GRAM)
static DisplayState displayState;
static uint8_t fontWidth, fontHeight;
static int16_t cursor_x, cursor_y;
static uint8_t displayOffset;
static uint8_t screenBuffer[16 + (OLED_WIDTH * 2) + 10]; // The data buffer
};
#endif /* OLED_HPP_ */

View File

@@ -0,0 +1,65 @@
/*
* Settings.h
*
* Created on: 29 Sep 2016
* Author: Ralim
*
* Houses the system settings and allows saving / restoring from flash
*/
#ifndef SETTINGS_H_
#define SETTINGS_H_
#include <stdint.h>
#include "stm32f1xx_hal.h"
#define SETTINGSVERSION ( 0x19 )
/*Change this if you change the struct below to prevent people getting \
out of sync*/
/*
* This struct must be a multiple of 2 bytes as it is saved / restored from
* flash in uint16_t chunks
*/
typedef struct {
uint16_t SolderingTemp; // current set point for the iron
uint16_t SleepTemp; // temp to drop to in sleep
uint8_t SleepTime; // minutes timeout to sleep
uint8_t cutoutSetting; // The voltage we cut out at for under voltage OR Power level for TS80
uint8_t OrientationMode :2; // If true we want to invert the display for lefties
uint8_t sensitivity :4; // Sensitivity of accelerometer (5 bits)
uint8_t autoStartMode :2; // Should the unit automatically jump straight
// into soldering mode when power is applied
uint8_t ShutdownTime; // Time until unit shuts down if left alone
uint8_t boostModeEnabled :1; // Boost mode swaps BUT_A in soldering mode to
// temporary soldering temp over-ride
uint8_t coolingTempBlink :1; // Should the temperature blink on the cool
// down screen until its <50C
uint8_t detailedIDLE :1; // Detailed idle screen
uint8_t detailedSoldering :1; // Detailed soldering screens
uint8_t temperatureInF; // Should the temp be in F or C (true is F)
uint8_t descriptionScrollSpeed :1; // Description scroll speed
uint16_t voltageDiv; // Voltage divisor factor
uint16_t BoostTemp; // Boost mode set point for the iron
int16_t CalibrationOffset; // This stores the temperature offset for this tip
// in the iron.
uint8_t PID_P; // PID P Term
uint8_t PID_I; // PID I Term
uint8_t PID_D; // PID D Term
uint8_t version; // Used to track if a reset is needed on firmware upgrade
uint8_t customTipGain; // Tip gain value if custom tuned, or 0 if using a
// tipType param
uint8_t tipType;
#ifdef MODEL_TS80
uint8_t pidPowerLimit;
#endif
uint32_t padding; // This is here for in case we are not an even divisor so
// that nothing gets cut off
} systemSettingsType;
extern volatile systemSettingsType systemSettings;
void saveSettings();
void restoreSettings();
uint8_t lookupVoltageLevel(uint8_t level);
void resetSettings();
bool showBootLogoIfavailable();
#endif /* SETTINGS_H_ */

View File

@@ -0,0 +1,38 @@
/*
* Setup.h
*
* Created on: 29Aug.,2017
* Author: Ben V. Brown
*/
#ifndef SETUP_H_
#define SETUP_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <hardware.h>
#include "stm32f1xx_hal.h"
extern ADC_HandleTypeDef hadc1;
extern ADC_HandleTypeDef hadc2;
extern DMA_HandleTypeDef hdma_adc1;
extern DMA_HandleTypeDef hdma_i2c1_rx;
extern DMA_HandleTypeDef hdma_i2c1_tx;
extern I2C_HandleTypeDef hi2c1;
extern IWDG_HandleTypeDef hiwdg;
extern TIM_HandleTypeDef htim2;
extern TIM_HandleTypeDef htim3;
void Setup_HAL();
uint16_t getADC(uint8_t channel);
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim); //Since the hal header file does not define this one
#ifdef __cplusplus
}
#endif
#endif /* SETUP_H_ */

View File

@@ -0,0 +1,72 @@
/*
* Translation.h
*
* Created on: 31Aug.,2017
* Author: Ben V. Brown
*/
#ifndef TRANSLATION_H_
#define TRANSLATION_H_
#include "stm32f1xx_hal.h"
enum ShortNameType {
SHORT_NAME_SINGLE_LINE = 1, SHORT_NAME_DOUBLE_LINE = 2,
};
extern const uint8_t USER_FONT_12[];
extern const uint8_t USER_FONT_6x8[];
/*
* When SettingsShortNameType is SHORT_NAME_SINGLE_LINE
* use SettingsShortNames as SettingsShortNames[16][1].. second column undefined
*/
extern const enum ShortNameType SettingsShortNameType;
extern const char* SettingsShortNames[21][2];
extern const char* SettingsDescriptions[21];
extern const char* SettingsMenuEntries[4];
extern const char* SettingsCalibrationDone;
extern const char* SettingsCalibrationWarning;
extern const char* SettingsResetWarning;
extern const char* UVLOWarningString;
extern const char* UndervoltageString;
extern const char* InputVoltageString;
extern const char* WarningTipTempString;
extern const char* BadTipString;
extern const char* SleepingSimpleString;
extern const char* SleepingAdvancedString;
extern const char* WarningSimpleString;
extern const char* WarningAdvancedString;
extern const char* SleepingTipAdvancedString;
extern const char* IdleTipString;
extern const char* IdleSetString;
extern const char* TipDisconnectedString;
extern const char* SolderingAdvancedPowerPrompt;
extern const char* OffString;
extern const char* ResetOKMessage;
extern const char* YourGainMessage;
extern const char* SettingTrueChar;
extern const char* SettingFalseChar;
extern const char* SettingRightChar;
extern const char* SettingLeftChar;
extern const char* SettingAutoChar;
extern const char* SettingFastChar;
extern const char* SettingSlowChar;
extern const char* TipModelStrings[];
extern const char* DebugMenu[];
extern const char* SymbolPlus;
extern const char* SymbolMinus;
extern const char* SymbolSpace;
extern const char* SymbolDot;
extern const char* SymbolDegC;
extern const char* SymbolDegF;
extern const char* SymbolMinutes;
extern const char* SymbolSeconds;
extern const char* SymbolWatts;
extern const char* SymbolVolts;
extern const char* SymbolDC;
extern const char* SymbolCellCount;
extern const char* SymbolVersionNumber;
extern const char* DebugMenu[];
#endif /* TRANSLATION_H_ */

View File

@@ -0,0 +1,38 @@
/*
* gui.h
*
* Created on: 3Sep.,2017
* Author: Ben V. Brown
*/
#ifndef GUI_HPP_
#define GUI_HPP_
#include "Translation.h"
#include "Settings.h"
#include "hardware.h"
#define PRESS_ACCEL_STEP 3
#define PRESS_ACCEL_INTERVAL_MIN 10
#define PRESS_ACCEL_INTERVAL_MAX 30
//GUI holds the menu structure and all its methods for the menu itself
//Declarations for all the methods for the settings menu (at end of this file)
//Wrapper for holding a function pointer
typedef struct state_func_t {
void (*func)(void);
} state_func;
//Struct for holding the function pointers and descriptions
typedef struct {
const char *description;
const state_func incrementHandler;
const state_func draw;
} menuitem;
void enterSettingsMenu();
extern const menuitem rootSettingsMenu[];
#endif /* GUI_HPP_ */

View File

@@ -0,0 +1,139 @@
/*
* Hardware.h
*
* Created on: 29Aug.,2017
* Author: Ben V. Brown
*/
#ifndef HARDWARE_H_
#define HARDWARE_H_
#include "Setup.h"
#include "stm32f1xx_hal.h"
#ifdef __cplusplus
extern "C" {
#endif
enum Orientation {
ORIENTATION_LEFT_HAND = 0, ORIENTATION_RIGHT_HAND = 1, ORIENTATION_FLAT = 3
};
#define PID_TIM_HZ (8)
#if defined(MODEL_TS100) + defined(MODEL_TS80) > 1
#error "Multiple models defined!"
#elif defined(MODEL_TS100) + defined(MODEL_TS80) == 0
#error "No model defined!"
#endif
#ifdef MODEL_TS100
#define KEY_B_Pin GPIO_PIN_6
#define KEY_B_GPIO_Port GPIOA
#define TMP36_INPUT_Pin GPIO_PIN_7
#define TMP36_INPUT_GPIO_Port GPIOA
#define TMP36_ADC1_CHANNEL ADC_CHANNEL_7
#define TIP_TEMP_Pin GPIO_PIN_0
#define TIP_TEMP_GPIO_Port GPIOB
#define TIP_TEMP_ADC1_CHANNEL ADC_CHANNEL_8
#define TIP_TEMP_ADC2_CHANNEL ADC_CHANNEL_8
#define VIN_Pin GPIO_PIN_1
#define VIN_GPIO_Port GPIOB
#define VIN_ADC1_CHANNEL ADC_CHANNEL_9
#define VIN_ADC2_CHANNEL ADC_CHANNEL_9
#define OLED_RESET_Pin GPIO_PIN_8
#define OLED_RESET_GPIO_Port GPIOA
#define KEY_A_Pin GPIO_PIN_9
#define KEY_A_GPIO_Port GPIOA
#define INT_Orientation_Pin GPIO_PIN_3
#define INT_Orientation_GPIO_Port GPIOB
#define PWM_Out_Pin GPIO_PIN_4
#define PWM_Out_GPIO_Port GPIOB
#define PWM_Out_CHANNEL TIM_CHANNEL_1
#define PWM_Out_CCR
#define INT_Movement_Pin GPIO_PIN_5
#define INT_Movement_GPIO_Port GPIOB
#define SCL_Pin GPIO_PIN_6
#define SCL_GPIO_Port GPIOB
#define SDA_Pin GPIO_PIN_7
#define SDA_GPIO_Port GPIOB
#else
// TS80 pin map
#define KEY_B_Pin GPIO_PIN_0
#define KEY_B_GPIO_Port GPIOB
#define TMP36_INPUT_Pin GPIO_PIN_4
#define TMP36_INPUT_GPIO_Port GPIOA
#define TMP36_ADC1_CHANNEL ADC_CHANNEL_4
#define TIP_TEMP_Pin GPIO_PIN_3
#define TIP_TEMP_GPIO_Port GPIOA
#define TIP_TEMP_ADC1_CHANNEL ADC_CHANNEL_3
#define TIP_TEMP_ADC2_CHANNEL ADC_CHANNEL_3
#define VIN_Pin GPIO_PIN_2
#define VIN_GPIO_Port GPIOA
#define VIN_ADC1_CHANNEL ADC_CHANNEL_2
#define VIN_ADC2_CHANNEL ADC_CHANNEL_2
#define OLED_RESET_Pin GPIO_PIN_15
#define OLED_RESET_GPIO_Port GPIOA
#define KEY_A_Pin GPIO_PIN_1
#define KEY_A_GPIO_Port GPIOB
#define INT_Orientation_Pin GPIO_PIN_4
#define INT_Orientation_GPIO_Port GPIOB
#define PWM_Out_Pin GPIO_PIN_6
#define PWM_Out_GPIO_Port GPIOA
#define PWM_Out_CHANNEL TIM_CHANNEL_1
#define INT_Movement_Pin GPIO_PIN_5
#define INT_Movement_GPIO_Port GPIOB
#define SCL_Pin GPIO_PIN_6
#define SCL_GPIO_Port GPIOB
#define SDA_Pin GPIO_PIN_7
#define SDA_GPIO_Port GPIOB
#endif
/*
* Keep in a uint8_t range for the ID's
*/
#ifdef MODEL_TS100
enum TipType {
TS_B2 = 0,
TS_D24 = 1,
TS_BC2 = 2,
TS_C1 = 3,
Tip_MiniWare = 4,
HAKKO_BC2 = 4,
Tip_Hakko = 5,
Tip_Custom = 5,
};
#endif
#ifdef MODEL_TS80
enum TipType {
TS_B02 = 0, TS_D25 = 1, Tip_MiniWare = 2, Tip_Custom = 3,
};
#endif
extern uint16_t tipGainCalValue ;
uint16_t lookupTipDefaultCalValue(enum TipType tipID);
uint16_t getHandleTemperature();
uint16_t getTipRawTemp(uint8_t refresh);
uint16_t getInputVoltageX10(uint16_t divisor,uint8_t sample);
void setTipPWM(uint8_t pulse);
uint16_t ctoTipMeasurement(uint16_t temp);
uint16_t tipMeasurementToC(uint16_t raw);
uint16_t ftoTipMeasurement(uint16_t temp);
uint16_t tipMeasurementToF(uint16_t raw);
void seekQC(int16_t Vx10, uint16_t divisor);
void setCalibrationOffset(int16_t offSet);
void setTipType(enum TipType tipType, uint8_t manualCalGain);
uint32_t calculateTipR();
int16_t calculateMaxVoltage(uint8_t useHP);
void startQC(uint16_t divisor); // Tries to negotiate QC for highest voltage, must be run after
// RToS
// This will try for 12V, failing that 9V, failing that 5V
// If input is over 12V returns -1
// If the input is [5-12] Will return the value.
#ifdef __cplusplus
}
#endif
#endif /* HARDWARE_H_ */

View File

@@ -0,0 +1,41 @@
/*
* history.hpp
*
* Created on: 28 Oct, 2018
* Authors: Ben V. Brown, David Hilton
*/
#ifndef HISTORY_HPP_
#define HISTORY_HPP_
#include <stdint.h>
// max size = 127
template <class T, uint8_t SIZE>
struct history {
static const uint8_t size = SIZE;
T buf[size];
int32_t sum;
uint8_t loc;
void update(T const val) {
// step backwards so i+1 is the previous value.
loc = (size+loc-1) % size;
sum -= buf[loc];
sum += val;
buf[loc] = val;
}
T operator[] (uint8_t i) const {
// 0 = newest, size-1 = oldest.
i = (i+loc) % size;
return buf[i];
}
T average() const {
return sum / size;
}
};
#endif /* HISTORY_HPP_ */

View File

@@ -0,0 +1,45 @@
#ifndef __MAIN_H
#define __MAIN_H
#include <MMA8652FC.hpp>
#include "OLED.hpp"
#include "Setup.h"
extern uint8_t PCBVersion;
extern uint32_t currentlyActiveTemperatureTarget;
enum ButtonState {
BUTTON_NONE = 0, /* No buttons pressed / < filter time*/
BUTTON_F_SHORT = 1, /* User has pressed the front button*/
BUTTON_B_SHORT = 2, /* User has pressed the back button*/
BUTTON_F_LONG = 4, /* User is holding the front button*/
BUTTON_B_LONG = 8, /* User is holding the back button*/
BUTTON_BOTH = 16, /* User has pressed both buttons*/
/*
* Note:
* Pressed means press + release, we trigger on a full \__/ pulse
* holding means it has gone low, and been low for longer than filter time
*/
};
ButtonState getButtonState();
void waitForButtonPressOrTimeout(uint32_t timeout);
void waitForButtonPress();
void GUIDelay();
#ifdef __cplusplus
extern "C" {
#endif
void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef *hadc);
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c);
void vApplicationStackOverflowHook(xTaskHandle *pxTask,
signed portCHAR *pcTaskName);
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */

View File

@@ -0,0 +1,39 @@
/*
* Power.hpp
*
* Created on: 28 Oct, 2018
* Authors: Ben V. Brown, David Hilton (David's Idea)
*/
#include "stdint.h"
#include <history.hpp>
#include "hardware.h"
#ifndef POWER_HPP_
#define POWER_HPP_
// thermal mass = 1690 milliJ/*C for my tip.
// -> Wattsx10*Seconds to raise Temp from room temp to +100*C, divided by 100*C.
// we divide mass by 20 to let the I term dominate near the set point.
// This is necessary because of the temp noise and thermal lag in the system.
// Once we have feed-forward temp estimation we should be able to better tune this.
#ifdef MODEL_TS100
const uint16_t tipMass = 450; // divide here so division is compile-time.
const uint8_t tipResistance = 85; //x10 ohms, 8.5 typical for ts100, 4.5 typical for ts80
#endif
#ifdef MODEL_TS80
const uint16_t tipMass = 450;
const uint8_t tipResistance = 45; //x10 ohms, 8.5 typical for ts100, 4.5 typical for ts80
#endif
const uint8_t oscillationPeriod = 6 * PID_TIM_HZ; // I term look back value
extern history<uint32_t, oscillationPeriod> milliWattHistory;
int32_t tempToMilliWatts(int32_t rawTemp, uint8_t rawC);
void setTipMilliWatts(int32_t mw);
uint8_t milliWattsToPWM(int32_t milliWatts, uint8_t divisor,
uint8_t sample = 0);
int32_t PWMToMilliWatts(uint8_t pwm, uint8_t divisor, uint8_t sample = 0);
#endif /* POWER_HPP_ */

View File

@@ -0,0 +1,365 @@
/**
******************************************************************************
* @file stm32f1xx_hal_conf.h
* @brief HAL configuration file.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F1xx_HAL_CONF_H
#define __STM32F1xx_HAL_CONF_H
#ifdef __cplusplus
extern "C" {
#endif
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
*/
#define HAL_MODULE_ENABLED
#define HAL_ADC_MODULE_ENABLED
/*#define HAL_CRYP_MODULE_ENABLED */
/*#define HAL_CAN_MODULE_ENABLED */
/*#define HAL_CEC_MODULE_ENABLED */
/*#define HAL_CORTEX_MODULE_ENABLED */
/*#define HAL_CRC_MODULE_ENABLED */
/*#define HAL_DAC_MODULE_ENABLED */
#define HAL_DMA_MODULE_ENABLED
/*#define HAL_ETH_MODULE_ENABLED */
/*#define HAL_FLASH_MODULE_ENABLED */
#define HAL_GPIO_MODULE_ENABLED
#define HAL_I2C_MODULE_ENABLED
/*#define HAL_I2S_MODULE_ENABLED */
/*#define HAL_IRDA_MODULE_ENABLED */
#define HAL_IWDG_MODULE_ENABLED
/*#define HAL_NOR_MODULE_ENABLED */
/*#define HAL_NAND_MODULE_ENABLED */
/*#define HAL_PCCARD_MODULE_ENABLED */
/*#define HAL_PCD_MODULE_ENABLED */
/*#define HAL_HCD_MODULE_ENABLED */
/*#define HAL_PWR_MODULE_ENABLED */
/*#define HAL_RCC_MODULE_ENABLED */
/*#define HAL_RTC_MODULE_ENABLED */
/*#define HAL_SD_MODULE_ENABLED */
/*#define HAL_MMC_MODULE_ENABLED */
/*#define HAL_SDRAM_MODULE_ENABLED */
/*#define HAL_SMARTCARD_MODULE_ENABLED */
/*#define HAL_SPI_MODULE_ENABLED */
/*#define HAL_SRAM_MODULE_ENABLED */
#define HAL_TIM_MODULE_ENABLED
/*#define HAL_UART_MODULE_ENABLED */
/*#define HAL_USART_MODULE_ENABLED */
/*#define HAL_WWDG_MODULE_ENABLED */
#define HAL_CORTEX_MODULE_ENABLED
#define HAL_DMA_MODULE_ENABLED
#define HAL_FLASH_MODULE_ENABLED
#define HAL_GPIO_MODULE_ENABLED
#define HAL_PWR_MODULE_ENABLED
#define HAL_RCC_MODULE_ENABLED
/* ########################## Oscillator Values adaptation ####################*/
/**
* @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
* This value is used by the RCC HAL module to compute the system frequency
* (when HSE is used as system clock source, directly or through the PLL).
*/
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
#if !defined (HSE_STARTUP_TIMEOUT)
#define HSE_STARTUP_TIMEOUT ((uint32_t)100) /*!< Time out for HSE start up, in ms */
#endif /* HSE_STARTUP_TIMEOUT */
/**
* @brief Internal High Speed oscillator (HSI) value.
* This value is used by the RCC HAL module to compute the system frequency
* (when HSI is used as system clock source, directly or through the PLL).
*/
#if !defined (HSI_VALUE)
#define HSI_VALUE ((uint32_t)8000000) /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */
/**
* @brief Internal Low Speed oscillator (LSI) value.
*/
#if !defined (LSI_VALUE)
#define LSI_VALUE 40000U /*!< LSI Typical Value in Hz */
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
The real value may vary depending on the variations
in voltage and temperature. */
/**
* @brief External Low Speed oscillator (LSE) value.
* This value is used by the UART, RTC HAL module to compute the system frequency
*/
#if !defined (LSE_VALUE)
#define LSE_VALUE ((uint32_t)32768) /*!< Value of the External oscillator in Hz*/
#endif /* LSE_VALUE */
#if !defined (LSE_STARTUP_TIMEOUT)
#define LSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for LSE start up, in ms */
#endif /* LSE_STARTUP_TIMEOUT */
/* Tip: To avoid modifying this file each time you need to use different HSE,
=== you can define the HSE value in your toolchain compiler preprocessor. */
/* ########################### System Configuration ######################### */
/**
* @brief This is the HAL system configuration section
*/
#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */
#define TICK_INT_PRIORITY ((uint32_t)0) /*!< tick interrupt priority (lowest by default) */
#define USE_RTOS 0
#define PREFETCH_ENABLE 1
/* ########################## Assert Selection ############################## */
/**
* @brief Uncomment the line below to expanse the "assert_param" macro in the
* HAL drivers code
*/
/* #define USE_FULL_ASSERT 1 */
/* ################## Ethernet peripheral configuration ##################### */
/* Section 1 : Ethernet peripheral configuration */
/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */
#define MAC_ADDR0 2
#define MAC_ADDR1 0
#define MAC_ADDR2 0
#define MAC_ADDR3 0
#define MAC_ADDR4 0
#define MAC_ADDR5 0
/* Definition of the Ethernet driver buffers size and count */
#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */
#define ETH_RXBUFNB ((uint32_t)8) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
/* Section 2: PHY configuration section */
/* DP83848_PHY_ADDRESS Address*/
#define DP83848_PHY_ADDRESS 0x01U
/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
/* PHY Configuration delay */
#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
#define PHY_READ_TO ((uint32_t)0x0000FFFF)
#define PHY_WRITE_TO ((uint32_t)0x0000FFFF)
/* Section 3: Common PHY Registers */
#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */
#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */
#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */
#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */
#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */
#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */
#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */
#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */
#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */
#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */
#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */
#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */
#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */
#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */
#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */
/* Section 4: Extended PHY Registers */
#define PHY_SR ((uint16_t)0x10U) /*!< PHY status register Offset */
#define PHY_SPEED_STATUS ((uint16_t)0x0002U) /*!< PHY Speed mask */
#define PHY_DUPLEX_STATUS ((uint16_t)0x0004U) /*!< PHY Duplex mask */
/* Includes ------------------------------------------------------------------*/
/**
* @brief Include module's header file
*/
#ifdef HAL_RCC_MODULE_ENABLED
#include "stm32f1xx_hal_rcc.h"
#endif /* HAL_RCC_MODULE_ENABLED */
#ifdef HAL_GPIO_MODULE_ENABLED
#include "stm32f1xx_hal_gpio.h"
#endif /* HAL_GPIO_MODULE_ENABLED */
#ifdef HAL_DMA_MODULE_ENABLED
#include "stm32f1xx_hal_dma.h"
#endif /* HAL_DMA_MODULE_ENABLED */
#ifdef HAL_ETH_MODULE_ENABLED
#include "stm32f1xx_hal_eth.h"
#endif /* HAL_ETH_MODULE_ENABLED */
#ifdef HAL_CAN_MODULE_ENABLED
#include "stm32f1xx_hal_can.h"
#endif /* HAL_CAN_MODULE_ENABLED */
#ifdef HAL_CEC_MODULE_ENABLED
#include "stm32f1xx_hal_cec.h"
#endif /* HAL_CEC_MODULE_ENABLED */
#ifdef HAL_CORTEX_MODULE_ENABLED
#include "stm32f1xx_hal_cortex.h"
#endif /* HAL_CORTEX_MODULE_ENABLED */
#ifdef HAL_ADC_MODULE_ENABLED
#include "stm32f1xx_hal_adc.h"
#endif /* HAL_ADC_MODULE_ENABLED */
#ifdef HAL_CRC_MODULE_ENABLED
#include "stm32f1xx_hal_crc.h"
#endif /* HAL_CRC_MODULE_ENABLED */
#ifdef HAL_DAC_MODULE_ENABLED
#include "stm32f1xx_hal_dac.h"
#endif /* HAL_DAC_MODULE_ENABLED */
#ifdef HAL_FLASH_MODULE_ENABLED
#include "stm32f1xx_hal_flash.h"
#endif /* HAL_FLASH_MODULE_ENABLED */
#ifdef HAL_SRAM_MODULE_ENABLED
#include "stm32f1xx_hal_sram.h"
#endif /* HAL_SRAM_MODULE_ENABLED */
#ifdef HAL_NOR_MODULE_ENABLED
#include "stm32f1xx_hal_nor.h"
#endif /* HAL_NOR_MODULE_ENABLED */
#ifdef HAL_I2C_MODULE_ENABLED
#include "stm32f1xx_hal_i2c.h"
#endif /* HAL_I2C_MODULE_ENABLED */
#ifdef HAL_I2S_MODULE_ENABLED
#include "stm32f1xx_hal_i2s.h"
#endif /* HAL_I2S_MODULE_ENABLED */
#ifdef HAL_IWDG_MODULE_ENABLED
#include "stm32f1xx_hal_iwdg.h"
#endif /* HAL_IWDG_MODULE_ENABLED */
#ifdef HAL_PWR_MODULE_ENABLED
#include "stm32f1xx_hal_pwr.h"
#endif /* HAL_PWR_MODULE_ENABLED */
#ifdef HAL_RTC_MODULE_ENABLED
#include "stm32f1xx_hal_rtc.h"
#endif /* HAL_RTC_MODULE_ENABLED */
#ifdef HAL_PCCARD_MODULE_ENABLED
#include "stm32f1xx_hal_pccard.h"
#endif /* HAL_PCCARD_MODULE_ENABLED */
#ifdef HAL_SD_MODULE_ENABLED
#include "stm32f1xx_hal_sd.h"
#endif /* HAL_SD_MODULE_ENABLED */
#ifdef HAL_MMC_MODULE_ENABLED
#include "stm32f1xx_hal_mmc.h"
#endif /* HAL_MMC_MODULE_ENABLED */
#ifdef HAL_NAND_MODULE_ENABLED
#include "stm32f1xx_hal_nand.h"
#endif /* HAL_NAND_MODULE_ENABLED */
#ifdef HAL_SPI_MODULE_ENABLED
#include "stm32f1xx_hal_spi.h"
#endif /* HAL_SPI_MODULE_ENABLED */
#ifdef HAL_TIM_MODULE_ENABLED
#include "stm32f1xx_hal_tim.h"
#endif /* HAL_TIM_MODULE_ENABLED */
#ifdef HAL_UART_MODULE_ENABLED
#include "stm32f1xx_hal_uart.h"
#endif /* HAL_UART_MODULE_ENABLED */
#ifdef HAL_USART_MODULE_ENABLED
#include "stm32f1xx_hal_usart.h"
#endif /* HAL_USART_MODULE_ENABLED */
#ifdef HAL_IRDA_MODULE_ENABLED
#include "stm32f1xx_hal_irda.h"
#endif /* HAL_IRDA_MODULE_ENABLED */
#ifdef HAL_SMARTCARD_MODULE_ENABLED
#include "stm32f1xx_hal_smartcard.h"
#endif /* HAL_SMARTCARD_MODULE_ENABLED */
#ifdef HAL_WWDG_MODULE_ENABLED
#include "stm32f1xx_hal_wwdg.h"
#endif /* HAL_WWDG_MODULE_ENABLED */
#ifdef HAL_PCD_MODULE_ENABLED
#include "stm32f1xx_hal_pcd.h"
#endif /* HAL_PCD_MODULE_ENABLED */
#ifdef HAL_HCD_MODULE_ENABLED
#include "stm32f1xx_hal_hcd.h"
#endif /* HAL_HCD_MODULE_ENABLED */
/* Exported macro ------------------------------------------------------------*/
#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr: If expr is false, it calls assert_failed function
* which reports the name of the source file and the source
* line number of the call that failed.
* If expr is true, it returns no value.
* @retval None
*/
#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */
#ifdef __cplusplus
}
#endif
#endif /* __STM32F1xx_HAL_CONF_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,67 @@
/**
******************************************************************************
* @file stm32f1xx_it.h
* @brief This file contains the headers of the interrupt handlers.
******************************************************************************
*
* COPYRIGHT(c) 2017 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F1xx_IT_H
#define __STM32F1xx_IT_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void NMI_Handler(void);
void HardFault_Handler(void);
void MemManage_Handler(void);
void BusFault_Handler(void);
void UsageFault_Handler(void);
void DebugMon_Handler(void);
void SysTick_Handler(void);
void DMA1_Channel1_IRQHandler(void);
void DMA1_Channel6_IRQHandler(void);
void DMA1_Channel7_IRQHandler(void);
void ADC1_2_IRQHandler(void);
void TIM1_UP_IRQHandler(void);
#ifdef __cplusplus
}
#endif
#endif /* __STM32F1xx_IT_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,189 @@
/*
* FRToSI2C.cpp
*
* Created on: 14Apr.,2018
* Author: Ralim
*/
#include "hardware.h"
#include "FRToSI2C.hpp"
#define I2CUSESDMA
I2C_HandleTypeDef* FRToSI2C::i2c;
SemaphoreHandle_t FRToSI2C::I2CSemaphore;
StaticSemaphore_t FRToSI2C::xSemaphoreBuffer;
void FRToSI2C::CpltCallback() {
i2c->State = HAL_I2C_STATE_READY; // Force state reset (even if tx error)
if (I2CSemaphore) {
xSemaphoreGiveFromISR(I2CSemaphore, NULL);
}
}
void FRToSI2C::Mem_Read(uint16_t DevAddress, uint16_t MemAddress,
uint16_t MemAddSize, uint8_t* pData, uint16_t Size) {
if (I2CSemaphore == NULL) {
// no RToS, run blocking code
HAL_I2C_Mem_Read(i2c, DevAddress, MemAddress, MemAddSize, pData, Size,
5000);
} else {
// RToS is active, run threading
// Get the mutex so we can use the I2C port
// Wait up to 1 second for the mutex
if (xSemaphoreTake(I2CSemaphore, (TickType_t)50) == pdTRUE) {
#ifdef I2CUSESDMA
if (HAL_I2C_Mem_Read(i2c, DevAddress, MemAddress, MemAddSize, pData,
Size, 500) != HAL_OK) {
I2C1_ClearBusyFlagErratum();
xSemaphoreGive(I2CSemaphore);
}
xSemaphoreGive(I2CSemaphore);
#else
HAL_I2C_Mem_Read(i2c, DevAddress, MemAddress, MemAddSize, pData, Size,
5000);
xSemaphoreGive(I2CSemaphore);
#endif
} else {
}
}
}
void FRToSI2C::I2C_RegisterWrite(uint8_t address, uint8_t reg, uint8_t data) {
Mem_Write(address, reg, I2C_MEMADD_SIZE_8BIT, &data, 1);
}
uint8_t FRToSI2C::I2C_RegisterRead(uint8_t add, uint8_t reg) {
uint8_t tx_data[1];
Mem_Read(add, reg, I2C_MEMADD_SIZE_8BIT, tx_data, 1);
return tx_data[0];
}
void FRToSI2C::Mem_Write(uint16_t DevAddress, uint16_t MemAddress,
uint16_t MemAddSize, uint8_t* pData, uint16_t Size) {
if (I2CSemaphore == NULL) {
// no RToS, run blocking code
HAL_I2C_Mem_Write(i2c, DevAddress, MemAddress, MemAddSize, pData, Size,
5000);
} else {
// RToS is active, run threading
// Get the mutex so we can use the I2C port
// Wait up to 1 second for the mutex
if (xSemaphoreTake(I2CSemaphore, (TickType_t)50) == pdTRUE) {
#ifdef I2CUSESDMA
if (HAL_I2C_Mem_Write(i2c, DevAddress, MemAddress, MemAddSize,
pData, Size, 500) != HAL_OK) {
I2C1_ClearBusyFlagErratum();
xSemaphoreGive(I2CSemaphore);
}
xSemaphoreGive(I2CSemaphore);
#else
if (HAL_I2C_Mem_Write(i2c, DevAddress, MemAddress, MemAddSize, pData,
Size, 5000) != HAL_OK) {
}
xSemaphoreGive(I2CSemaphore);
#endif
} else {
}
}
}
void FRToSI2C::Transmit(uint16_t DevAddress, uint8_t* pData, uint16_t Size) {
if (I2CSemaphore == NULL) {
// no RToS, run blocking code
HAL_I2C_Master_Transmit(i2c, DevAddress, pData, Size, 5000);
} else {
// RToS is active, run threading
// Get the mutex so we can use the I2C port
// Wait up to 1 second for the mutex
if (xSemaphoreTake(I2CSemaphore, (TickType_t)50) == pdTRUE) {
#ifdef I2CUSESDMA
if (HAL_I2C_Master_Transmit_DMA(i2c, DevAddress, pData, Size)
!= HAL_OK) {
I2C1_ClearBusyFlagErratum();
xSemaphoreGive(I2CSemaphore);
}
#else
HAL_I2C_Master_Transmit(i2c, DevAddress, pData, Size, 5000);
xSemaphoreGive(I2CSemaphore);
#endif
} else {
}
}
}
void FRToSI2C::I2C1_ClearBusyFlagErratum() {
GPIO_InitTypeDef GPIO_InitStruct;
int timeout = 100;
int timeout_cnt = 0;
// 1. Clear PE bit.
i2c->Instance->CR1 &= ~(0x0001);
/**I2C1 GPIO Configuration
PB6 ------> I2C1_SCL
PB7 ------> I2C1_SDA
*/
// 2. Configure the SCL and SDA I/Os as General Purpose Output Open-Drain, High level (Write 1 to GPIOx_ODR).
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Pin = SCL_Pin;
HAL_GPIO_Init(SCL_GPIO_Port, &GPIO_InitStruct);
HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_SET);
GPIO_InitStruct.Pin = SDA_Pin;
HAL_GPIO_Init(SDA_GPIO_Port, &GPIO_InitStruct);
HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_SET);
while (GPIO_PIN_SET != HAL_GPIO_ReadPin(SDA_GPIO_Port, SDA_Pin)) {
//Move clock to release I2C
HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_RESET);
asm("nop");
asm("nop");
asm("nop");
asm("nop");
HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_SET);
timeout_cnt++;
if (timeout_cnt > timeout)
return;
}
// 12. Configure the SCL and SDA I/Os as Alternate function Open-Drain.
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Pin = SCL_Pin;
HAL_GPIO_Init(SCL_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = SDA_Pin;
HAL_GPIO_Init(SDA_GPIO_Port, &GPIO_InitStruct);
HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_SET);
// 13. Set SWRST bit in I2Cx_CR1 register.
i2c->Instance->CR1 |= 0x8000;
asm("nop");
// 14. Clear SWRST bit in I2Cx_CR1 register.
i2c->Instance->CR1 &= ~0x8000;
asm("nop");
// 15. Enable the I2C peripheral by setting the PE bit in I2Cx_CR1 register
i2c->Instance->CR1 |= 0x0001;
// Call initialization function.
HAL_I2C_Init(i2c);
}

View File

@@ -0,0 +1,843 @@
/*
* GUIThread.cpp
*
* Created on: 19 Aug 2019
* Author: ralim
*/
#include <MMA8652FC.hpp>
#include <gui.hpp>
#include <main.hpp>
#include "LIS2DH12.hpp"
#include <history.hpp>
#include <power.hpp>
#include "Settings.h"
#include "Translation.h"
#include "cmsis_os.h"
#include "stdlib.h"
#include "stm32f1xx_hal.h"
#include "string.h"
extern uint8_t PCBVersion;
// File local variables
extern uint32_t currentlyActiveTemperatureTarget;
extern uint32_t lastMovementTime;
extern int16_t idealQCVoltage;
uint32_t lastButtonTime = 0;
extern osThreadId GUITaskHandle;
extern osThreadId MOVTaskHandle;
extern osThreadId PIDTaskHandle;
// TODO: express time constants in terms of dividends of portTICK_RATE_MS
#define MOVEMENT_INACTIVITY_TIME 6000
#define BUTTON_INACTIVITY_TIME 6000
static uint16_t min(uint16_t a, uint16_t b) {
if (a > b)
return b;
else
return a;
}
void printVoltage() {
uint32_t volt = getInputVoltageX10(systemSettings.voltageDiv, 0);
OLED::printNumber(volt / 10, 2);
OLED::print(SymbolDot);
OLED::printNumber(volt % 10, 1);
}
void GUIDelay() {
// Called in all UI looping tasks,
// This limits the re-draw rate to the LCD and also lets the DMA run
// As the gui task can very easily fill this bus with transactions, which will
// prevent the movement detection from running
osDelay(50);
}
void gui_drawTipTemp(bool symbol) {
// Draw tip temp handling unit conversion & tolerance near setpoint
uint16_t Temp = getTipRawTemp(0);
if (systemSettings.temperatureInF)
Temp = tipMeasurementToF(Temp);
else
Temp = tipMeasurementToC(Temp);
OLED::printNumber(Temp, 3); // Draw the tip temp out finally
if (symbol) {
if (systemSettings.temperatureInF)
OLED::print(SymbolDegF);
else
OLED::print(SymbolDegC);
}
}
ButtonState getButtonState() {
/*
* Read in the buttons and then determine if a state change needs to occur
*/
/*
* If the previous state was 00 Then we want to latch the new state if
* different & update time
* If the previous state was !00 Then we want to search if we trigger long
* press (buttons still down), or if release we trigger press
* (downtime>filter)
*/
static uint8_t previousState = 0;
static uint32_t previousStateChange = 0;
const uint16_t timeout = 40;
uint8_t currentState;
currentState = (
HAL_GPIO_ReadPin(KEY_A_GPIO_Port, KEY_A_Pin) == GPIO_PIN_RESET ?
1 : 0) << 0;
currentState |= (
HAL_GPIO_ReadPin(KEY_B_GPIO_Port, KEY_B_Pin) == GPIO_PIN_RESET ?
1 : 0) << 1;
if (currentState)
lastButtonTime = xTaskGetTickCount();
if (currentState == previousState) {
if (currentState == 0)
return BUTTON_NONE;
if ((xTaskGetTickCount() - previousStateChange) > timeout) {
// User has been holding the button down
// We want to send a buttong is held message
if (currentState == 0x01)
return BUTTON_F_LONG;
else if (currentState == 0x02)
return BUTTON_B_LONG;
else
return BUTTON_NONE; // Both being held case, we dont long hold this
} else
return BUTTON_NONE;
} else {
// A change in button state has occurred
ButtonState retVal = BUTTON_NONE;
if (currentState) {
// User has pressed a button down (nothing done on down)
if (currentState != previousState) {
// There has been a change in the button states
// If there is a rising edge on one of the buttons from double press we
// want to mask that out As users are having issues with not release
// both at once
if (previousState == 0x03)
currentState = 0x03;
}
} else {
// User has released buttons
// If they previously had the buttons down we want to check if they were <
// long hold and trigger a press
if ((xTaskGetTickCount() - previousStateChange) < timeout) {
// The user didn't hold the button for long
// So we send button press
if (previousState == 0x01)
retVal = BUTTON_F_SHORT;
else if (previousState == 0x02)
retVal = BUTTON_B_SHORT;
else
retVal = BUTTON_BOTH; // Both being held case
}
}
previousState = currentState;
previousStateChange = xTaskGetTickCount();
return retVal;
}
return BUTTON_NONE;
}
void waitForButtonPress() {
// we are just lazy and sleep until user confirms button press
// This also eats the button press event!
ButtonState buttons = getButtonState();
while (buttons) {
buttons = getButtonState();
GUIDelay();
}
while (!buttons) {
buttons = getButtonState();
GUIDelay();
}
}
void waitForButtonPressOrTimeout(uint32_t timeout) {
timeout += xTaskGetTickCount();
// calculate the exit point
ButtonState buttons = getButtonState();
while (buttons) {
buttons = getButtonState();
GUIDelay();
if (xTaskGetTickCount() > timeout)
return;
}
while (!buttons) {
buttons = getButtonState();
GUIDelay();
if (xTaskGetTickCount() > timeout)
return;
}
}
#ifdef MODEL_TS100
// returns true if undervoltage has occured
static bool checkVoltageForExit() {
uint16_t v = getInputVoltageX10(systemSettings.voltageDiv, 0);
//Dont check for first 1.5 seconds while the ADC stabilizes and the DMA fills the buffer
if (xTaskGetTickCount() > 150) {
if ((v < lookupVoltageLevel(systemSettings.cutoutSetting))) {
GUIDelay();
OLED::clearScreen();
OLED::setCursor(0, 0);
if (systemSettings.detailedSoldering) {
OLED::setFont(1);
OLED::print(UndervoltageString);
OLED::setCursor(0, 8);
OLED::print(InputVoltageString);
printVoltage();
OLED::print("V");
} else {
OLED::setFont(0);
OLED::print(UVLOWarningString);
}
OLED::refresh();
currentlyActiveTemperatureTarget = 0;
waitForButtonPress();
return true;
}
}
return false;
}
#endif
static void gui_drawBatteryIcon() {
#ifdef MODEL_TS100
if (systemSettings.cutoutSetting) {
// User is on a lithium battery
// we need to calculate which of the 10 levels they are on
uint8_t cellCount = systemSettings.cutoutSetting + 2;
uint32_t cellV = getInputVoltageX10(systemSettings.voltageDiv, 0)
/ cellCount;
// Should give us approx cell voltage X10
// Range is 42 -> 33 = 9 steps therefore we will use battery 1-10
if (cellV < 33)
cellV = 33;
cellV -= 33;// Should leave us a number of 0-9
if (cellV > 9)
cellV = 9;
OLED::drawBattery(cellV + 1);
} else
OLED::drawSymbol(15); // Draw the DC Logo
#else
// On TS80 we replace this symbol with the voltage we are operating on
// If <9V then show single digit, if not show duals
uint8_t V = getInputVoltageX10(systemSettings.voltageDiv, 0);
if (V % 10 >= 5)
V = V / 10 + 1; // round up
else
V = V / 10;
if (V >= 10) {
int16_t xPos = OLED::getCursorX();
OLED::setFont(1);
OLED::printNumber(1, 1);
OLED::setCursor(xPos, 8);
OLED::printNumber(V % 10, 1);
OLED::setFont(0);
OLED::setCursor(xPos + 12, 0); // need to reset this as if we drew a wide char
} else {
OLED::printNumber(V, 1);
}
#endif
}
static void gui_solderingTempAdjust() {
uint32_t lastChange = xTaskGetTickCount();
currentlyActiveTemperatureTarget = 0;
uint32_t autoRepeatTimer = 0;
uint8_t autoRepeatAcceleration = 0;
for (;;) {
OLED::setCursor(0, 0);
OLED::clearScreen();
OLED::setFont(0);
ButtonState buttons = getButtonState();
if (buttons)
lastChange = xTaskGetTickCount();
switch (buttons) {
case BUTTON_NONE:
// stay
break;
case BUTTON_BOTH:
// exit
return;
break;
case BUTTON_B_LONG:
if (xTaskGetTickCount() - autoRepeatTimer
+ autoRepeatAcceleration> PRESS_ACCEL_INTERVAL_MAX) {
systemSettings.SolderingTemp -= 10; // sub 10
autoRepeatTimer = xTaskGetTickCount();
autoRepeatAcceleration += PRESS_ACCEL_STEP;
}
break;
case BUTTON_F_LONG:
if (xTaskGetTickCount() - autoRepeatTimer
+ autoRepeatAcceleration> PRESS_ACCEL_INTERVAL_MAX) {
systemSettings.SolderingTemp += 10;
autoRepeatTimer = xTaskGetTickCount();
autoRepeatAcceleration += PRESS_ACCEL_STEP;
}
break;
case BUTTON_F_SHORT:
systemSettings.SolderingTemp += 10; // add 10
break;
case BUTTON_B_SHORT:
systemSettings.SolderingTemp -= 10; // sub 10
break;
default:
break;
}
if ((PRESS_ACCEL_INTERVAL_MAX - autoRepeatAcceleration)
< PRESS_ACCEL_INTERVAL_MIN) {
autoRepeatAcceleration = PRESS_ACCEL_INTERVAL_MAX
- PRESS_ACCEL_INTERVAL_MIN;
}
// constrain between 50-450 C
if (systemSettings.temperatureInF) {
if (systemSettings.SolderingTemp > 850)
systemSettings.SolderingTemp = 850;
if (systemSettings.SolderingTemp < 120)
systemSettings.SolderingTemp = 120;
} else {
if (systemSettings.SolderingTemp > 450)
systemSettings.SolderingTemp = 450;
if (systemSettings.SolderingTemp < 50)
systemSettings.SolderingTemp = 50;
}
if (xTaskGetTickCount() - lastChange > 200)
return; // exit if user just doesn't press anything for a bit
#ifdef MODEL_TS80
if (!OLED::getRotation())
#else
if (OLED::getRotation())
#endif
OLED::print(SymbolMinus);
else
OLED::print(SymbolPlus);
OLED::print(SymbolSpace);
OLED::printNumber(systemSettings.SolderingTemp, 3);
if (systemSettings.temperatureInF)
OLED::drawSymbol(0);
else
OLED::drawSymbol(1);
OLED::print(SymbolSpace);
#ifdef MODEL_TS80
if (!OLED::getRotation())
#else
if (OLED::getRotation())
#endif
OLED::print(SymbolPlus);
else
OLED::print(SymbolMinus);
OLED::refresh();
GUIDelay();
}
}
static int gui_SolderingSleepingMode() {
// Drop to sleep temperature and display until movement or button press
for (;;) {
ButtonState buttons = getButtonState();
if (buttons)
return 0;
if ((xTaskGetTickCount() - lastMovementTime < 100)
|| (xTaskGetTickCount() - lastButtonTime < 100))
return 0; // user moved or pressed a button, go back to soldering
#ifdef MODEL_TS100
if (checkVoltageForExit())
return 1; // return non-zero on error
#endif
if (systemSettings.temperatureInF) {
currentlyActiveTemperatureTarget = ftoTipMeasurement(
min(systemSettings.SleepTemp,
systemSettings.SolderingTemp));
} else {
currentlyActiveTemperatureTarget = ctoTipMeasurement(
min(systemSettings.SleepTemp,
systemSettings.SolderingTemp));
}
// draw the lcd
uint16_t tipTemp;
if (systemSettings.temperatureInF)
tipTemp = tipMeasurementToF(getTipRawTemp(0));
else
tipTemp = tipMeasurementToC(getTipRawTemp(0));
OLED::clearScreen();
OLED::setCursor(0, 0);
if (systemSettings.detailedSoldering) {
OLED::setFont(1);
OLED::print(SleepingAdvancedString);
OLED::setCursor(0, 8);
OLED::print(SleepingTipAdvancedString);
OLED::printNumber(tipTemp, 3);
if (systemSettings.temperatureInF)
OLED::print(SymbolDegF);
else
OLED::print(SymbolDegC);
OLED::print(SymbolSpace);
printVoltage();
OLED::print(SymbolVolts);
} else {
OLED::setFont(0);
OLED::print(SleepingSimpleString);
OLED::printNumber(tipTemp, 3);
if (systemSettings.temperatureInF)
OLED::drawSymbol(0);
else
OLED::drawSymbol(1);
}
if (systemSettings.ShutdownTime) // only allow shutdown exit if time > 0
if (lastMovementTime)
if (((uint32_t) (xTaskGetTickCount() - lastMovementTime))
> (uint32_t) (systemSettings.ShutdownTime * 60 * 100)) {
// shutdown
currentlyActiveTemperatureTarget = 0;
return 1; // we want to exit soldering mode
}
OLED::refresh();
GUIDelay();
}
return 0;
}
static void display_countdown(int sleepThres) {
/*
* Print seconds or minutes (if > 99 seconds) until sleep
* mode is triggered.
*/
int lastEventTime =
lastButtonTime < lastMovementTime ?
lastMovementTime : lastButtonTime;
int downCount = sleepThres - xTaskGetTickCount() + lastEventTime;
if (downCount > 9900) {
OLED::printNumber(downCount / 6000 + 1, 2);
OLED::print(SymbolMinutes);
} else {
OLED::printNumber(downCount / 100 + 1, 2);
OLED::print(SymbolSeconds);
}
}
static void gui_solderingMode(uint8_t jumpToSleep) {
/*
* * Soldering (gui_solderingMode)
* -> Main loop where we draw temp, and animations
* --> User presses buttons and they goto the temperature adjust screen
* ---> Display the current setpoint temperature
* ---> Use buttons to change forward and back on temperature
* ---> Both buttons or timeout for exiting
* --> Long hold front button to enter boost mode
* ---> Just temporarily sets the system into the alternate temperature for
* PID control
* --> Long hold back button to exit
* --> Double button to exit
*/
bool boostModeOn = false;
uint8_t badTipCounter = 0;
uint32_t sleepThres = 0;
if (systemSettings.SleepTime < 6)
sleepThres = systemSettings.SleepTime * 10 * 100;
else
sleepThres = (systemSettings.SleepTime - 5) * 60 * 100;
if (jumpToSleep) {
if (gui_SolderingSleepingMode()) {
lastButtonTime = xTaskGetTickCount();
return; // If the function returns non-0 then exit
}
}
for (;;) {
ButtonState buttons = getButtonState();
switch (buttons) {
case BUTTON_NONE:
// stay
boostModeOn = false;
break;
case BUTTON_BOTH:
// exit
return;
break;
case BUTTON_B_LONG:
return; // exit on back long hold
break;
case BUTTON_F_LONG:
// if boost mode is enabled turn it on
if (systemSettings.boostModeEnabled)
boostModeOn = true;
break;
case BUTTON_F_SHORT:
case BUTTON_B_SHORT: {
uint16_t oldTemp = systemSettings.SolderingTemp;
gui_solderingTempAdjust(); // goto adjust temp mode
if (oldTemp != systemSettings.SolderingTemp) {
saveSettings(); // only save on change
}
}
break;
default:
break;
}
// else we update the screen information
OLED::setCursor(0, 0);
OLED::clearScreen();
OLED::setFont(0);
uint16_t tipTemp = getTipRawTemp(0);
if (tipTemp > 32700) {
badTipCounter++; // Use a counter so that error has to persist for > 1 second continious so that peak errors dont trip it
} else {
badTipCounter = 0;
}
//Draw in the screen details
if (systemSettings.detailedSoldering) {
OLED::setFont(1);
OLED::print(SolderingAdvancedPowerPrompt); // Power:
OLED::printNumber(milliWattHistory[0] / 1000, 2);
OLED::print(SymbolDot);
OLED::printNumber(milliWattHistory[0] / 100 % 10, 1);
OLED::print(SymbolWatts);
if (systemSettings.sensitivity && systemSettings.SleepTime) {
OLED::print(SymbolSpace);
display_countdown(sleepThres);
}
OLED::setCursor(0, 8);
OLED::print(SleepingTipAdvancedString);
gui_drawTipTemp(true);
OLED::print(SymbolSpace);
printVoltage();
OLED::print(SymbolVolts);
} else {
// We switch the layout direction depending on the orientation of the
// OLED::
if (OLED::getRotation()) {
// battery
gui_drawBatteryIcon();
OLED::print(SymbolSpace); // Space out gap between battery <-> temp
gui_drawTipTemp(true); // Draw current tip temp
// We draw boost arrow if boosting, or else gap temp <-> heat
// indicator
if (boostModeOn)
OLED::drawSymbol(2);
else
OLED::print(SymbolSpace);
// Draw heating/cooling symbols
OLED::drawHeatSymbol(
milliWattsToPWM(milliWattHistory[0],
systemSettings.voltageDiv));
} else {
// Draw heating/cooling symbols
OLED::drawHeatSymbol(
milliWattsToPWM(milliWattHistory[0],
systemSettings.voltageDiv));
// We draw boost arrow if boosting, or else gap temp <-> heat
// indicator
if (boostModeOn)
OLED::drawSymbol(2);
else
OLED::print(SymbolSpace);
gui_drawTipTemp(true); // Draw current tip temp
OLED::print(SymbolSpace); // Space out gap between battery <-> temp
gui_drawBatteryIcon();
}
}
if (badTipCounter > 128) {
OLED::print(BadTipString);
OLED::refresh();
currentlyActiveTemperatureTarget = 0;
waitForButtonPress();
currentlyActiveTemperatureTarget = 0;
return;
}
OLED::refresh();
// Update the setpoints for the temperature
if (boostModeOn) {
if (systemSettings.temperatureInF)
currentlyActiveTemperatureTarget = ftoTipMeasurement(
systemSettings.BoostTemp);
else
currentlyActiveTemperatureTarget = ctoTipMeasurement(
systemSettings.BoostTemp);
} else {
if (systemSettings.temperatureInF)
currentlyActiveTemperatureTarget = ftoTipMeasurement(
systemSettings.SolderingTemp);
else
currentlyActiveTemperatureTarget = ctoTipMeasurement(
systemSettings.SolderingTemp);
}
#ifdef MODEL_TS100
// Undervoltage test
if (checkVoltageForExit()) {
lastButtonTime = xTaskGetTickCount();
return;
}
#else
// on the TS80 we only want to check for over voltage to prevent tip damage
/*if (getInputVoltageX10(systemSettings.voltageDiv, 1) > 150) {
lastButtonTime = xTaskGetTickCount();
currentlyActiveTemperatureTarget = 0;
return; // Over voltage
}*/
#endif
if (systemSettings.sensitivity && systemSettings.SleepTime)
if (xTaskGetTickCount() - lastMovementTime > sleepThres
&& xTaskGetTickCount() - lastButtonTime > sleepThres) {
if (gui_SolderingSleepingMode()) {
return; // If the function returns non-0 then exit
}
}
//slow down ui update rate
GUIDelay();
}
}
void showDebugMenu(void) {
uint8_t screen = 0;
ButtonState b;
for (;;) {
OLED::clearScreen(); // Ensure the buffer starts clean
OLED::setCursor(0, 0); // Position the cursor at the 0,0 (top left)
OLED::setFont(1); // small font
OLED::print(SymbolVersionNumber); // Print version number
OLED::setCursor(0, 8); // second line
OLED::print(DebugMenu[screen]);
switch (screen) {
case 0: //Just prints date
break;
case 1:
//High water mark for GUI
OLED::printNumber(uxTaskGetStackHighWaterMark(GUITaskHandle), 5);
break;
case 2:
//High water mark for the Movement task
OLED::printNumber(uxTaskGetStackHighWaterMark(MOVTaskHandle), 5);
break;
case 3:
//High water mark for the PID task
OLED::printNumber(uxTaskGetStackHighWaterMark(PIDTaskHandle), 5);
break;
case 4:
//system up time stamp
OLED::printNumber(xTaskGetTickCount() / 100, 5);
break;
case 5:
//Movement time stamp
OLED::printNumber(lastMovementTime / 100, 5);
break;
case 6:
//Raw Tip
OLED::printNumber(getTipRawTemp(0), 6);
break;
case 7:
//Temp in C
OLED::printNumber(tipMeasurementToC(getTipRawTemp(0)), 5);
break;
case 8:
//Handle Temp
OLED::printNumber(getHandleTemperature(), 3);
break;
case 9:
//Voltage input
printVoltage();
break;
case 10:
// Print PCB ID number
OLED::printNumber(PCBVersion, 1);
break;
default:
break;
}
OLED::refresh();
b = getButtonState();
if (b == BUTTON_B_SHORT)
return;
else if (b == BUTTON_F_SHORT) {
screen++;
screen = screen % 11;
}
GUIDelay();
}
}
/* StartGUITask function */
void startGUITask(void const *argument __unused) {
FRToSI2C::FRToSInit();
uint8_t tempWarningState = 0;
bool buttonLockout = false;
bool tempOnDisplay = false;
getTipRawTemp(1); // reset filter
OLED::setRotation(systemSettings.OrientationMode & 1);
uint32_t ticks = xTaskGetTickCount();
ticks += 400; // 4 seconds from now
while (xTaskGetTickCount() < ticks) {
if (showBootLogoIfavailable() == false)
ticks = xTaskGetTickCount();
ButtonState buttons = getButtonState();
if (buttons)
ticks = xTaskGetTickCount(); // make timeout now so we will exit
GUIDelay();
}
if (systemSettings.autoStartMode) {
// jump directly to the autostart mode
if (systemSettings.autoStartMode == 1)
gui_solderingMode(0);
if (systemSettings.autoStartMode == 2)
gui_solderingMode(1);
}
#if ACCELDEBUG
for (;;) {
HAL_IWDG_Refresh(&hiwdg);
osDelay(100);
}
//^ Kept here for a way to block this thread
#endif
for (;;) {
ButtonState buttons = getButtonState();
if (buttons != BUTTON_NONE) {
OLED::setDisplayState(OLED::DisplayState::ON);
OLED::setFont(0);
}
if (tempWarningState == 2)
buttons = BUTTON_F_SHORT;
if (buttons != BUTTON_NONE && buttonLockout)
buttons = BUTTON_NONE;
else
buttonLockout = false;
switch (buttons) {
case BUTTON_NONE:
// Do nothing
break;
case BUTTON_BOTH:
// Not used yet
// In multi-language this might be used to reset language on a long hold
// or some such
break;
case BUTTON_B_LONG:
// Show the version information
showDebugMenu();
break;
case BUTTON_F_LONG:
gui_solderingTempAdjust();
saveSettings();
break;
case BUTTON_F_SHORT:
gui_solderingMode(0); // enter soldering mode
buttonLockout = true;
break;
case BUTTON_B_SHORT:
enterSettingsMenu(); // enter the settings menu
saveSettings();
buttonLockout = true;
setCalibrationOffset(systemSettings.CalibrationOffset); // ensure cal offset is applied
break;
default:
break;
}
currentlyActiveTemperatureTarget = 0; // ensure tip is off
getInputVoltageX10(systemSettings.voltageDiv, 0);
uint16_t tipTemp = tipMeasurementToC(getTipRawTemp(0));
// Preemptively turn the display on. Turn it off if and only if
// the tip temperature is below 50 degrees C *and* motion sleep
// detection is enabled *and* there has been no activity (movement or
// button presses) in a while.
OLED::setDisplayState(OLED::DisplayState::ON);
if ((tipTemp < 50) && systemSettings.sensitivity &&
(((xTaskGetTickCount() - lastMovementTime) > MOVEMENT_INACTIVITY_TIME) &&
((xTaskGetTickCount() - lastButtonTime) > BUTTON_INACTIVITY_TIME))) {
OLED::setDisplayState(OLED::DisplayState::OFF);
}
// Clear the lcd buffer
OLED::clearScreen();
OLED::setCursor(0, 0);
if (systemSettings.detailedIDLE) {
OLED::setFont(1);
if (tipTemp > 470) {
OLED::print(TipDisconnectedString);
} else {
OLED::print(IdleTipString);
gui_drawTipTemp(false);
OLED::print(IdleSetString);
OLED::printNumber(systemSettings.SolderingTemp, 3);
}
OLED::setCursor(0, 8);
OLED::print(InputVoltageString);
printVoltage();
} else {
OLED::setFont(0);
#ifdef MODEL_TS80
if (!OLED::getRotation()) {
#else
if (OLED::getRotation()) {
#endif
OLED::drawArea(12, 0, 84, 16, idleScreenBG);
OLED::setCursor(0, 0);
gui_drawBatteryIcon();
} else {
OLED::drawArea(0, 0, 84, 16, idleScreenBGF); // Needs to be flipped so button ends up
// on right side of screen
OLED::setCursor(84, 0);
gui_drawBatteryIcon();
}
if (tipTemp > 55)
tempOnDisplay = true;
else if (tipTemp < 45)
tempOnDisplay = false;
if (tempOnDisplay) {
// draw temp over the start soldering button
// Location changes on screen rotation
#ifdef MODEL_TS80
if (!OLED::getRotation()) {
#else
if (OLED::getRotation()) {
#endif
// in right handed mode we want to draw over the first part
OLED::fillArea(55, 0, 41, 16, 0); // clear the area for the temp
OLED::setCursor(56, 0);
} else {
OLED::fillArea(0, 0, 41, 16, 0); // clear the area
OLED::setCursor(0, 0);
}
// draw in the temp
if (!(systemSettings.coolingTempBlink
&& (xTaskGetTickCount() % 25 < 16)))
gui_drawTipTemp(false); // draw in the temp
}
}
OLED::refresh();
GUIDelay();
}
}

View File

@@ -0,0 +1,50 @@
/*
* LIS2DH12.cpp
*
* Created on: 27Feb.,2018
* Author: Ralim
*/
#include <array>
#include "LIS2DH12.hpp"
#include "cmsis_os.h"
typedef struct {
const uint8_t reg;
const uint8_t value;
} LIS_REG;
static const LIS_REG i2c_registers[] = {
{LIS_CTRL_REG1, 0x17}, // 25Hz
{LIS_CTRL_REG2, 0b00001000}, // Highpass filter off
{LIS_CTRL_REG3, 0b01100000}, // Setup interrupt pins
{LIS_CTRL_REG4, 0b00001000}, // Block update mode off, HR on
{LIS_CTRL_REG5, 0b00000010},
{LIS_CTRL_REG6, 0b01100010},
//Basically setup the unit to run, and enable 4D orientation detection
{LIS_INT2_CFG, 0b01111110}, //setup for movement detection
{LIS_INT2_THS, 0x28},
{LIS_INT2_DURATION, 64},
{LIS_INT1_CFG, 0b01111110},
{LIS_INT1_THS, 0x28},
{LIS_INT1_DURATION, 64}
};
void LIS2DH12::initalize() {
for (size_t index = 0; index < (sizeof(i2c_registers) / sizeof(i2c_registers[0])); index++) {
FRToSI2C::I2C_RegisterWrite(LIS2DH_I2C_ADDRESS,i2c_registers[index].reg, i2c_registers[index].value);
}
}
void LIS2DH12::getAxisReadings(int16_t& x, int16_t& y, int16_t& z) {
std::array<int16_t, 3> sensorData;
FRToSI2C::Mem_Read(LIS2DH_I2C_ADDRESS, 0xA8, I2C_MEMADD_SIZE_8BIT,
reinterpret_cast<uint8_t*>(sensorData.begin()),
sensorData.size() * sizeof(int16_t));
x = sensorData[0];
y = sensorData[1];
z = sensorData[2];
}

View File

@@ -0,0 +1,78 @@
/*
* MMA8652FC.cpp
*
* Created on: 31Aug.,2017
* Author: Ben V. Brown
*/
#include <array>
#include "MMA8652FC.hpp"
#include "cmsis_os.h"
typedef struct {
const uint8_t reg;
const uint8_t val;
} MMA_REG;
static const MMA_REG i2c_registers[] = { { CTRL_REG2, 0 }, //Normal mode
{ CTRL_REG2, 0x40 }, // Reset all registers to POR values
{ FF_MT_CFG_REG, 0x78 }, // Enable motion detection for X, Y, Z axis, latch disabled
{ PL_CFG_REG, 0x40 }, //Enable the orientation detection
{ PL_COUNT_REG, 200 }, //200 count debounce
{ PL_BF_ZCOMP_REG, 0b01000111 }, //Set the threshold to 42 degrees
{ P_L_THS_REG, 0b10011100 }, //Up the trip angles
{ CTRL_REG4, 0x01 | (1 << 4) }, // Enable dataready interrupt & orientation interrupt
{ CTRL_REG5, 0x01 }, // Route data ready interrupts to INT1 ->PB5 ->EXTI5, leaving orientation routed to INT2
{ CTRL_REG2, 0x12 }, //Set maximum resolution oversampling
{ XYZ_DATA_CFG_REG, (1 << 4) }, //select high pass filtered data
{ HP_FILTER_CUTOFF_REG, 0x03 }, //select high pass filtered data
{ CTRL_REG1, 0x19 } // ODR=12 Hz, Active mode
};
void MMA8652FC::initalize() {
size_t index = 0;
//send all the init commands to the unit
FRToSI2C::I2C_RegisterWrite(MMA8652FC_I2C_ADDRESS,i2c_registers[index].reg, i2c_registers[index].val);
index++;
FRToSI2C::I2C_RegisterWrite(MMA8652FC_I2C_ADDRESS,i2c_registers[index].reg, i2c_registers[index].val);
index++;
HAL_Delay(2); // ~1ms delay
while (index < (sizeof(i2c_registers) / sizeof(i2c_registers[0]))) {
FRToSI2C::I2C_RegisterWrite(MMA8652FC_I2C_ADDRESS,i2c_registers[index].reg, i2c_registers[index].val);
index++;
}
}
Orientation MMA8652FC::getOrientation() {
//First read the PL_STATUS register
uint8_t plStatus = FRToSI2C::I2C_RegisterRead(MMA8652FC_I2C_ADDRESS,PL_STATUS_REG);
if ((plStatus & 0b10000000) == 0b10000000) {
plStatus >>= 1; //We don't need the up/down bit
plStatus &= 0x03; //mask to the two lower bits
//0 == left handed
//1 == right handed
return static_cast<Orientation>(plStatus);
}
return ORIENTATION_FLAT;
}
void MMA8652FC::getAxisReadings(int16_t& x, int16_t& y, int16_t& z) {
std::array<int16_t, 3> sensorData;
FRToSI2C::Mem_Read(MMA8652FC_I2C_ADDRESS, OUT_X_MSB_REG, I2C_MEMADD_SIZE_8BIT,
reinterpret_cast<uint8_t*>(sensorData.begin()),
sensorData.size() * sizeof(int16_t));
x = static_cast<int16_t>(__builtin_bswap16(*reinterpret_cast<uint16_t*>(&sensorData[0])));
y = static_cast<int16_t>(__builtin_bswap16(*reinterpret_cast<uint16_t*>(&sensorData[1])));
z = static_cast<int16_t>(__builtin_bswap16(*reinterpret_cast<uint16_t*>(&sensorData[2])));
}

View File

@@ -0,0 +1,324 @@
/*
* OLED.cpp
*
* Created on: 29Aug.,2017
* Author: Ben V. Brown
*/
#include <string.h>
#include <OLED.hpp>
#include <stdlib.h>
#include "Translation.h"
#include "cmsis_os.h"
const uint8_t* OLED::currentFont; // Pointer to the current font used for
// rendering to the buffer
uint8_t* OLED::firstStripPtr; // Pointers to the strips to allow for buffer
// having extra content
uint8_t* OLED::secondStripPtr; // Pointers to the strips
bool OLED::inLeftHandedMode; // Whether the screen is in left or not (used for
// offsets in GRAM)
OLED::DisplayState OLED::displayState;
uint8_t OLED::fontWidth, OLED::fontHeight;
int16_t OLED::cursor_x, OLED::cursor_y;
uint8_t OLED::displayOffset;
uint8_t OLED::screenBuffer[16 + (OLED_WIDTH * 2) + 10]; // The data buffer
/*Setup params for the OLED screen*/
/*http://www.displayfuture.com/Display/datasheet/controller/SSD1307.pdf*/
/*All commands are prefixed with 0x80*/
/*Data packets are prefixed with 0x40*/
uint8_t OLED_Setup_Array[] = {
/**/
0x80, 0xAE, /*Display off*/
0x80, 0xD5, /*Set display clock divide ratio / osc freq*/
0x80, 0x52, /*Divide ratios*/
0x80, 0xA8, /*Set Multiplex Ratio*/
0x80, 0x0F, /*16 == max brightness,39==dimmest*/
0x80, 0xC0, /*Set COM Scan direction*/
0x80, 0xD3, /*Set vertical Display offset*/
0x80, 0x00, /*0 Offset*/
0x80, 0x40, /*Set Display start line to 0*/
0x80, 0xA0, /*Set Segment remap to normal*/
0x80, 0x8D, /*Charge Pump*/
0x80, 0x14, /*Charge Pump settings*/
0x80, 0xDA, /*Set VCOM Pins hardware config*/
0x80, 0x02, /*Combination 2*/
0x80, 0x81, /*Contrast*/
0x80, 0x33, /*^51*/
0x80, 0xD9, /*Set pre-charge period*/
0x80, 0xF1, /*Pre charge period*/
0x80, 0xDB, /*Adjust VCOMH regulator ouput*/
0x80, 0x30, /*VCOM level*/
0x80, 0xA4, /*Enable the display GDDR*/
0x80, 0XA6, /*Normal display*/
0x80, 0x20, /*Memory Mode*/
0x80, 0x00, /*Wrap memory*/
0x80, 0xAF /*Display on*/
};
// Setup based on the SSD1307 and modified for the SSD1306
const uint8_t REFRESH_COMMANDS[17] = { 0x80, 0xAF, 0x80, 0x21, 0x80, 0x20, 0x80,
0x7F, 0x80, 0xC0, 0x80, 0x22, 0x80, 0x00, 0x80, 0x01, 0x40 };
void OLED::initialize() {
cursor_x = cursor_y = 0;
currentFont = USER_FONT_12;
fontWidth = 12;
inLeftHandedMode = false;
firstStripPtr = &screenBuffer[FRAMEBUFFER_START];
secondStripPtr = &screenBuffer[FRAMEBUFFER_START + OLED_WIDTH];
fontHeight = 16;
displayOffset = 0;
memcpy(&screenBuffer[0], &REFRESH_COMMANDS[0], sizeof(REFRESH_COMMANDS));
HAL_Delay(50);
HAL_GPIO_WritePin(OLED_RESET_GPIO_Port, OLED_RESET_Pin, GPIO_PIN_SET);
HAL_Delay(50);
// Set the display to be ON once the settings block is sent and send the
// initialisation data to the OLED.
setDisplayState(DisplayState::ON);
FRToSI2C::Transmit(DEVICEADDR_OLED, &OLED_Setup_Array[0],
sizeof(OLED_Setup_Array));
}
/*
* Prints a char to the screen.
* UTF font handling is done using the two input chars.
* Precursor is the command char that is used to select the table.
*/
void OLED::drawChar(char c) {
if (c == '\x01' && cursor_y == 0) { // 0x01 is used as new line char
cursor_x = 0;
cursor_y = 8;
return;
} else if (c == 0) {
return;
}
uint16_t index = c - 2; //First index is \x02
uint8_t* charPointer;
charPointer = ((uint8_t*) currentFont)
+ ((fontWidth * (fontHeight / 8)) * index);
drawArea(cursor_x, cursor_y, fontWidth, fontHeight, charPointer);
cursor_x += fontWidth;
}
void OLED::setRotation(bool leftHanded) {
#ifdef MODEL_TS80
leftHanded = !leftHanded;
#endif
if (inLeftHandedMode == leftHanded) {
return;
}
// send command struct again with changes
if (leftHanded) {
OLED_Setup_Array[11] = 0xC8; // c1?
OLED_Setup_Array[19] = 0xA1;
} else {
OLED_Setup_Array[11] = 0xC0;
OLED_Setup_Array[19] = 0xA0;
}
FRToSI2C::Transmit(DEVICEADDR_OLED, (uint8_t*) OLED_Setup_Array,
sizeof(OLED_Setup_Array));
inLeftHandedMode = leftHanded;
screenBuffer[5] = inLeftHandedMode ? 0 : 32; // display is shifted by 32 in left handed
// mode as driver ram is 128 wide
screenBuffer[7] = inLeftHandedMode ? 95 : 0x7F; // End address of the ram segment we are writing to (96 wide)
screenBuffer[9] = inLeftHandedMode ? 0xC8 : 0xC0;
}
// print a string to the current cursor location
void OLED::print(const char* str) {
while (str[0]) {
drawChar(str[0]);
str++;
}
}
void OLED::setFont(uint8_t fontNumber) {
if (fontNumber == 1) {
// small font
currentFont = USER_FONT_6x8;
fontHeight = 8;
fontWidth = 6;
} else if (fontNumber == 2) {
currentFont = ExtraFontChars;
fontHeight = 16;
fontWidth = 12;
} else {
currentFont = USER_FONT_12;
fontHeight = 16;
fontWidth = 12;
}
}
// maximum places is 5
void OLED::printNumber(uint16_t number, uint8_t places) {
char buffer[7] = { 0 };
if (places >= 5) {
buffer[5] = 2 + number % 10;
number /= 10;
}
if (places > 4) {
buffer[4] = 2 + number % 10;
number /= 10;
}
if (places > 3) {
buffer[3] = 2 + number % 10;
number /= 10;
}
if (places > 2) {
buffer[2] = 2 + number % 10;
number /= 10;
}
if (places > 1) {
buffer[1] = 2 + number % 10;
number /= 10;
}
buffer[0] = 2 + number % 10;
number /= 10;
print(buffer);
}
void OLED::debugNumber(int32_t val) {
if (abs(val) > 99999) {
OLED::print(SymbolSpace); // out of bounds
return;
}
if (val >= 0) {
OLED::print(SymbolSpace);
OLED::printNumber(val, 5);
} else {
OLED::print(SymbolMinus);
OLED::printNumber(-val, 5);
}
}
void OLED::drawSymbol(uint8_t symbolID) {
// draw a symbol to the current cursor location
setFont(2);
drawChar(symbolID + 2);
setFont(0);
}
// Draw an area, but y must be aligned on 0/8 offset
void OLED::drawArea(int16_t x, int8_t y, uint8_t wide, uint8_t height,
const uint8_t* ptr) {
// Splat this from x->x+wide in two strides
if (x <= -wide)
return; // cutoffleft
if (x > 96)
return; // cutoff right
uint8_t visibleStart = 0;
uint8_t visibleEnd = wide;
// trimming to draw partials
if (x < 0) {
visibleStart -= x; // subtract negative value == add absolute value
}
if (x + wide > 96) {
visibleEnd = 96 - x;
}
if (y == 0) {
// Splat first line of data
for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) {
firstStripPtr[xx + x] = ptr[xx];
}
}
if (y == 8 || height == 16) {
// Splat the second line
for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) {
secondStripPtr[x + xx] = ptr[xx + (height == 16 ? wide : 0)];
}
}
}
void OLED::fillArea(int16_t x, int8_t y, uint8_t wide, uint8_t height,
const uint8_t value) {
// Splat this from x->x+wide in two strides
if (x <= -wide)
return; // cutoffleft
if (x > 96)
return; // cutoff right
uint8_t visibleStart = 0;
uint8_t visibleEnd = wide;
// trimming to draw partials
if (x < 0) {
visibleStart -= x; // subtract negative value == add absolute value
}
if (x + wide > 96) {
visibleEnd = 96 - x;
}
if (y == 0) {
// Splat first line of data
for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) {
firstStripPtr[xx + x] = value;
}
}
if (y == 8 || height == 16) {
// Splat the second line
for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) {
secondStripPtr[x + xx] = value;
}
}
}
void OLED::drawFilledRect(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1,
bool clear) {
// Draw this in 3 sections
// This is basically a N wide version of vertical line
// Step 1 : Draw in the top few pixels that are not /8 aligned
// LSB is at the top of the screen
uint8_t mask = 0xFF;
if (y0) {
mask = mask << (y0 % 8);
for (uint8_t col = x0; col < x1; col++)
if (clear)
firstStripPtr[(y0 / 8) * 96 + col] &= ~mask;
else
firstStripPtr[(y0 / 8) * 96 + col] |= mask;
}
// Next loop down the line the total number of solids
if (y0 / 8 != y1 / 8)
for (uint8_t col = x0; col < x1; col++)
for (uint8_t r = (y0 / 8); r < (y1 / 8); r++) {
// This gives us the row index r
if (clear)
firstStripPtr[(r * 96) + col] = 0;
else
firstStripPtr[(r * 96) + col] = 0xFF;
}
// Finally draw the tail
mask = ~(mask << (y1 % 8));
for (uint8_t col = x0; col < x1; col++)
if (clear)
firstStripPtr[(y1 / 8) * 96 + col] &= ~mask;
else
firstStripPtr[(y1 / 8) * 96 + col] |= mask;
}
void OLED::drawHeatSymbol(uint8_t state) {
// Draw symbol 14
// Then draw over it, the bottom 5 pixels always stay. 8 pixels above that are
// the levels masks the symbol nicely
state /= 31; // 0-> 8 range
// Then we want to draw down (16-(5+state)
uint8_t cursor_x_temp = cursor_x;
drawSymbol(14);
drawFilledRect(cursor_x_temp, 0, cursor_x_temp + 12, 2 + (8 - state), true);
}

View File

@@ -0,0 +1,121 @@
/*
* Settings.c
*
* Created on: 29 Sep 2016
* Author: Ralim
*
* This file holds the users settings and saves / restores them to the
* devices flash
*/
#include "Settings.h"
#include "Setup.h"
#define FLASH_ADDR \
(0x8000000 | \
0xFC00) /*Flash start OR'ed with the maximum amount of flash - 1024 bytes*/
#include "string.h"
volatile systemSettingsType systemSettings;
void saveSettings() {
// First we erase the flash
FLASH_EraseInitTypeDef pEraseInit;
pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
pEraseInit.Banks = FLASH_BANK_1;
pEraseInit.NbPages = 1;
pEraseInit.PageAddress = FLASH_ADDR;
uint32_t failingAddress = 0;
HAL_IWDG_Refresh(&hiwdg);
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR |
FLASH_FLAG_BSY);
HAL_FLASH_Unlock();
HAL_Delay(10);
HAL_IWDG_Refresh(&hiwdg);
HAL_FLASHEx_Erase(&pEraseInit, &failingAddress);
//^ Erase the page of flash (1024 bytes on this stm32)
// erased the chunk
// now we program it
uint16_t *data = (uint16_t *)&systemSettings;
HAL_FLASH_Unlock();
for (uint8_t i = 0; i < (sizeof(systemSettingsType) / 2); i++) {
HAL_IWDG_Refresh(&hiwdg);
HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, FLASH_ADDR + (i * 2),
data[i]);
}
HAL_FLASH_Lock();
}
void restoreSettings() {
// We read the flash
uint16_t *data = (uint16_t *)&systemSettings;
for (uint8_t i = 0; i < (sizeof(systemSettingsType) / 2); i++) {
data[i] = *((uint16_t *)(FLASH_ADDR + (i * 2)));
}
// if the version is correct were done
// if not we reset and save
if (systemSettings.version != SETTINGSVERSION) {
// probably not setup
resetSettings();
}
}
// Lookup function for cutoff setting -> X10 voltage
/*
* 0=DC
* 1=3S
* 2=4S
* 3=5S
* 4=6S
*/
uint8_t lookupVoltageLevel(uint8_t level) {
if (level == 0)
return 90; // 9V since iron does not function effectively below this
else
return (level * 33) + (33 * 2);
}
void resetSettings() {
memset((void *)&systemSettings, 0, sizeof(systemSettingsType));
systemSettings.SleepTemp =
150; // Temperature the iron sleeps at - default 150.0 C
systemSettings.SleepTime = 6; // How many seconds/minutes we wait until going
// to sleep - default 1 min
systemSettings.SolderingTemp = 320; // Default soldering temp is 320.0 C
systemSettings.cutoutSetting = 0; // default to no cut-off voltage (or 18W for TS80)
systemSettings.version =
SETTINGSVERSION; // Store the version number to allow for easier upgrades
systemSettings.detailedSoldering = 0; // Detailed soldering screen
systemSettings.detailedIDLE =
0; // Detailed idle screen (off for first time users)
systemSettings.OrientationMode = 2; // Default to automatic
systemSettings.sensitivity = 7; // Default high sensitivity
#ifdef MODEL_TS80
systemSettings.voltageDiv = 780; // Default divider from schematic
#else
systemSettings.voltageDiv = 467; // Default divider from schematic
#endif
systemSettings.ShutdownTime =
10; // How many minutes until the unit turns itself off
systemSettings.boostModeEnabled =
1; // Default to having boost mode on as most people prefer itF
systemSettings.BoostTemp = 420; // default to 400C
systemSettings.autoStartMode = 0; // Auto start off for safety
systemSettings.coolingTempBlink =
0; // Blink the temperature on the cooling screen when its > 50C
systemSettings.temperatureInF = 0; // default to 0
systemSettings.descriptionScrollSpeed = 0; // default to slow
systemSettings.PID_P = 42; // PID tuning constants
systemSettings.PID_I = 50;
systemSettings.PID_D = 15;
systemSettings.CalibrationOffset = 1400; // the adc offset
systemSettings.customTipGain =
0; // The tip type is either default or a custom gain
#ifdef MODEL_TS100
systemSettings.tipType = TS_B2; // Default to the B2 Tip
#endif
#ifdef MODEL_TS80
systemSettings.pidPowerLimit=24; // Sets the max pwm power limit
systemSettings.tipType = TS_B02; // Default to the B2 Tip
#endif
saveSettings(); // Save defaults
}

View File

@@ -0,0 +1,464 @@
/*
* Setup.c
*
* Created on: 29Aug.,2017
* Author: Ben V. Brown
*/
#include "Setup.h"
ADC_HandleTypeDef hadc1;
ADC_HandleTypeDef hadc2;
DMA_HandleTypeDef hdma_adc1;
I2C_HandleTypeDef hi2c1;
DMA_HandleTypeDef hdma_i2c1_rx;
DMA_HandleTypeDef hdma_i2c1_tx;
IWDG_HandleTypeDef hiwdg;
TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim3;
uint16_t ADCReadings[64]; // room for 32 lots of the pair of readings
// Functions
static void SystemClock_Config(void);
static void MX_ADC1_Init(void);
static void MX_I2C1_Init(void);
static void MX_IWDG_Init(void);
static void MX_TIM3_Init(void);
static void MX_TIM2_Init(void);
static void MX_DMA_Init(void);
static void MX_GPIO_Init(void);
static void MX_ADC2_Init(void);
void Setup_HAL() {
SystemClock_Config();
#ifndef LOCAL_BUILD
__HAL_AFIO_REMAP_SWJ_DISABLE()
;
#else
__HAL_AFIO_REMAP_SWJ_NOJTAG();
#endif
MX_GPIO_Init();
MX_DMA_Init();
MX_I2C1_Init();
MX_ADC1_Init();
MX_ADC2_Init();
MX_TIM3_Init();
MX_TIM2_Init();
MX_IWDG_Init();
HAL_ADC_Start(&hadc2);
HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*) ADCReadings, 64); // start DMA of normal readings
HAL_ADCEx_InjectedStart(&hadc1); // enable injected readings
HAL_ADCEx_InjectedStart(&hadc2); // enable injected readings
}
// channel 0 -> temperature sensor, 1-> VIN
uint16_t getADC(uint8_t channel) {
uint32_t sum = 0;
for (uint8_t i = 0; i < 32; i++)
sum += ADCReadings[channel + (i * 2)];
return sum >> 2;
}
/** System Clock Configuration
*/
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInit;
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType =
RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16; // 64MHz
HAL_RCC_OscConfig(&RCC_OscInitStruct);
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK |
RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV16; // TIM
// 2,3,4,5,6,7,12,13,14
RCC_ClkInitStruct.APB2CLKDivider =
RCC_HCLK_DIV1; // 64 mhz to some peripherals and adc
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection =
RCC_ADCPCLK2_DIV6; // 6 or 8 are the only non overclocked options
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
/**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000);
/**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 15, 0);
}
/* ADC1 init function */
static void MX_ADC1_Init(void) {
ADC_MultiModeTypeDef multimode;
ADC_ChannelConfTypeDef sConfig;
ADC_InjectionConfTypeDef sConfigInjected;
/**Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 2;
HAL_ADC_Init(&hadc1);
/**Configure the ADC multi-mode
*/
multimode.Mode = ADC_DUALMODE_REGSIMULT_INJECSIMULT;
HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode);
/**Configure Regular Channel
*/
sConfig.Channel = TMP36_ADC1_CHANNEL;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
/**Configure Regular Channel
*/
sConfig.Channel = VIN_ADC1_CHANNEL;
sConfig.Rank = 2;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
/**Configure Injected Channel
*/
// F in = 10.66 MHz
/*
* Injected time is 1 delay clock + (12 adc cycles*4)+4*sampletime =~217
* clocks = 0.2ms Charge time is 0.016 uS ideally So Sampling time must be >=
* 0.016uS 1/10.66MHz is 0.09uS, so 1 CLK is *should* be enough
* */
sConfigInjected.InjectedChannel = TIP_TEMP_ADC1_CHANNEL;
sConfigInjected.InjectedRank = 1;
sConfigInjected.InjectedNbrOfConversion = 4;
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_7CYCLES_5;
sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T2_CC1;
sConfigInjected.AutoInjectedConv = DISABLE;
sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
sConfigInjected.InjectedOffset = 0;
HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_1CYCLE_5;
sConfigInjected.InjectedRank = 2;
HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
sConfigInjected.InjectedRank = 3;
HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
sConfigInjected.InjectedRank = 4;
HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
SET_BIT(hadc1.Instance->CR1, (ADC_CR1_JEOCIE)); // Enable end of injected conv irq
// Run ADC internal calibration
while (HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK)
;
}
/* ADC2 init function */
static void MX_ADC2_Init(void) {
ADC_ChannelConfTypeDef sConfig;
ADC_InjectionConfTypeDef sConfigInjected;
/**Common config
*/
hadc2.Instance = ADC2;
hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc2.Init.ContinuousConvMode = ENABLE;
hadc2.Init.DiscontinuousConvMode = DISABLE;
hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc2.Init.NbrOfConversion = 2;
HAL_ADC_Init(&hadc2);
/**Configure Regular Channel
*/
sConfig.Channel = TIP_TEMP_ADC2_CHANNEL;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
HAL_ADC_ConfigChannel(&hadc2, &sConfig);
sConfig.Channel = VIN_ADC2_CHANNEL;
sConfig.Rank = ADC_REGULAR_RANK_2;
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
HAL_ADC_ConfigChannel(&hadc2, &sConfig);
/**Configure Injected Channel
*/
sConfigInjected.InjectedChannel = TIP_TEMP_ADC2_CHANNEL;
sConfigInjected.InjectedRank = ADC_INJECTED_RANK_1;
sConfigInjected.InjectedNbrOfConversion = 4;
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_7CYCLES_5;
sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T2_CC1;
sConfigInjected.AutoInjectedConv = DISABLE;
sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
sConfigInjected.InjectedOffset = 0;
HAL_ADCEx_InjectedConfigChannel(&hadc2, &sConfigInjected);
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_1CYCLE_5;
sConfigInjected.InjectedRank = ADC_INJECTED_RANK_2;
HAL_ADCEx_InjectedConfigChannel(&hadc2, &sConfigInjected);
sConfigInjected.InjectedRank = ADC_INJECTED_RANK_3;
HAL_ADCEx_InjectedConfigChannel(&hadc2, &sConfigInjected);
sConfigInjected.InjectedRank = ADC_INJECTED_RANK_4;
HAL_ADCEx_InjectedConfigChannel(&hadc2, &sConfigInjected);
// Run ADC internal calibration
while (HAL_ADCEx_Calibration_Start(&hadc2) != HAL_OK)
;
}
/* I2C1 init function */
static void MX_I2C1_Init(void) {
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 75000;
// OLED doesnt handle >100k when its asleep (off).
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
HAL_I2C_Init(&hi2c1);
}
/* IWDG init function */
static void MX_IWDG_Init(void) {
hiwdg.Instance = IWDG;
hiwdg.Init.Prescaler = IWDG_PRESCALER_256;
hiwdg.Init.Reload = 100;
#ifndef LOCAL_BUILD
HAL_IWDG_Init(&hiwdg);
#endif
}
/* TIM3 init function */
static void MX_TIM3_Init(void) {
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
TIM_OC_InitTypeDef sConfigOC;
htim3.Instance = TIM3;
htim3.Init.Prescaler = 8;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 100; // 5 Khz PWM freq
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4; // 4mhz before div
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; //Preload the ARR register (though we dont use this)
HAL_TIM_Base_Init(&htim3);
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig);
HAL_TIM_PWM_Init(&htim3);
HAL_TIM_OC_Init(&htim3);
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig);
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 80; //80% duty cycle, that is AC coupled through the cap
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;
HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, PWM_Out_CHANNEL);
GPIO_InitTypeDef GPIO_InitStruct;
/**TIM3 GPIO Configuration
PWM_Out_Pin ------> TIM3_CH1
*/
GPIO_InitStruct.Pin = PWM_Out_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; //We would like sharp rising edges
HAL_GPIO_Init(PWM_Out_GPIO_Port, &GPIO_InitStruct);
#ifdef MODEL_TS100
// Remap TIM3_CH1 to be on PB4
__HAL_AFIO_REMAP_TIM3_PARTIAL()
;
#else
// No re-map required
#endif
HAL_TIM_PWM_Start(&htim3, PWM_Out_CHANNEL);
}
/* TIM3 init function */
static void MX_TIM2_Init(void) {
/*
* We use the channel 1 to trigger the ADC at end of PWM period
* And we use the channel 4 as the PWM modulation source using Interrupts
* */
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
TIM_OC_InitTypeDef sConfigOC;
// Timer 2 is fairly slow as its being used to run the PWM and trigger the ADC
// in the PWM off time.
htim2.Instance = TIM2;
htim2.Init.Prescaler = 4000; //1mhz tick rate/800 = 1.25 KHz tick rate
// pwm out is 10k from tim3, we want to run our PWM at around 10hz or slower on the output stage
// These values give a rate of around 8Hz
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 255 + 17;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4; // 4mhz before divide
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
htim2.Init.RepetitionCounter = 0;
HAL_TIM_Base_Init(&htim2);
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig);
HAL_TIM_PWM_Init(&htim2);
HAL_TIM_OC_Init(&htim2);
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 255 + 13;//13 -> Delay of 5ms
//255 is the largest time period of the drive signal, and then offset ADC sample to be a bit delayed after this
/*
* It takes 4 milliseconds for output to be stable after PWM turns off.
* Assume ADC samples in 0.5ms
* We need to set this to 100% + 4.5ms
* */
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;
HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);
sConfigOC.Pulse = 0; //default to entirely off
HAL_TIM_OC_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_4);
HAL_TIM_Base_Start_IT(&htim2);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_PWM_Start_IT(&htim2, TIM_CHANNEL_4);
HAL_NVIC_SetPriority(TIM2_IRQn, 15, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void) {
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE()
;
/* DMA interrupt init */
/* DMA1_Channel1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
/* DMA1_Channel6_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);
/* DMA1_Channel7_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
}
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
* Free pins are configured automatically as Analog
PB0 ------> ADCx_IN8
PB1 ------> ADCx_IN9
*/
static void MX_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOD_CLK_ENABLE()
;
__HAL_RCC_GPIOA_CLK_ENABLE()
;
__HAL_RCC_GPIOB_CLK_ENABLE()
;
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(OLED_RESET_GPIO_Port, OLED_RESET_Pin, GPIO_PIN_RESET);
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
/*Configure GPIO pins : PD0 PD1 */
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/*Configure peripheral I/O remapping */
__HAL_AFIO_REMAP_PD01_ENABLE()
;
//^ remap XTAL so that pins can be analog (all input buffers off).
// reduces power consumption
/*
* Configure All pins as analog by default
*/
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 |
GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 |
GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 |
#ifdef MODEL_TS100
GPIO_PIN_3 |
#endif
GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 |
GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 |
GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
#ifdef MODEL_TS100
/* Pull USB lines low to disable, pull down debug too*/
GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_14 | GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_14, GPIO_PIN_RESET);
#else
/* TS80 */
/* Leave USB lines open circuit*/
#endif
/*Configure GPIO pins : KEY_B_Pin KEY_A_Pin */
GPIO_InitStruct.Pin = KEY_B_Pin | KEY_A_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(KEY_B_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : OLED_RESET_Pin */
GPIO_InitStruct.Pin = OLED_RESET_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(OLED_RESET_GPIO_Port, &GPIO_InitStruct);
HAL_GPIO_WritePin(OLED_RESET_GPIO_Port, OLED_RESET_Pin, GPIO_PIN_RESET);
// Pull down LCD reset
HAL_GPIO_WritePin(OLED_RESET_GPIO_Port, OLED_RESET_Pin, GPIO_PIN_RESET);
HAL_Delay(30);
HAL_GPIO_WritePin(OLED_RESET_GPIO_Port, OLED_RESET_Pin, GPIO_PIN_SET);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,52 @@
/**
******************************************************************************
* File Name : freertos.c
* Description : Code for freertos applications
******************************************************************************
* This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* Copyright (c) 2017 STMicroelectronics International N.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted, provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific written permission.
* 4. This software, including modifications and/or derivative works of this
* software, must execute solely and exclusively on microcontroller or
* microprocessor devices manufactured by or for STMicroelectronics.
* 5. Redistribution and use of this software other than as permitted under
* this license is void and will automatically terminate your rights under
* this license.
*
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,994 @@
/*
* gui.cpp
*
* Created on: 3Sep.,2017
* Author: Ben V. Brown
*/
#include "gui.hpp"
#include "Translation.h"
#include "cmsis_os.h"
#include "main.hpp"
#include "string.h"
extern uint32_t lastButtonTime;
void gui_Menu(const menuitem* menu);
#ifdef MODEL_TS100
static void settings_setInputVRange(void);
static void settings_displayInputVRange(void);
#else
static void settings_setInputPRange(void);
static void settings_displayInputPRange(void);
#endif
static void settings_setSleepTemp(void);
static void settings_displaySleepTemp(void);
static void settings_setSleepTime(void);
static void settings_displaySleepTime(void);
static void settings_setShutdownTime(void);
static void settings_displayShutdownTime(void);
static void settings_setSensitivity(void);
static void settings_displaySensitivity(void);
static void settings_setTempF(void);
static void settings_displayTempF(void);
static void settings_setAdvancedSolderingScreens(void);
static void settings_displayAdvancedSolderingScreens(void);
static void settings_setAdvancedIDLEScreens(void);
static void settings_displayAdvancedIDLEScreens(void);
static void settings_setScrollSpeed(void);
static void settings_displayScrollSpeed(void);
static void settings_setDisplayRotation(void);
static void settings_displayDisplayRotation(void);
static void settings_setBoostModeEnabled(void);
static void settings_displayBoostModeEnabled(void);
static void settings_setBoostTemp(void);
static void settings_displayBoostTemp(void);
static void settings_setAutomaticStartMode(void);
static void settings_displayAutomaticStartMode(void);
static void settings_setCoolingBlinkEnabled(void);
static void settings_displayCoolingBlinkEnabled(void);
static void settings_setResetSettings(void);
static void settings_displayResetSettings(void);
static void settings_setTipModel(void);
static void settings_displayTipModel(void);
static void settings_setCalibrate(void);
static void settings_displayCalibrate(void);
static void settings_setCalibrateVIN(void);
static void settings_displayCalibrateVIN(void);
// Calibration Menu
static void calibration_displaySimpleCal(void); // Hot water cal
static void calibration_enterSimpleCal(void);
static void calibration_displayAdvancedCal(void); // two point cal
static void calibration_enterAdvancedCal(void);
// Menu functions
static void settings_displaySolderingMenu(void);
static void settings_enterSolderingMenu(void);
static void settings_displayPowerMenu(void);
static void settings_enterPowerMenu(void);
static void settings_displayUIMenu(void);
static void settings_enterUIMenu(void);
static void settings_displayAdvancedMenu(void);
static void settings_enterAdvancedMenu(void);
/*
* Root Settings Menu
*
* Power Source
* Soldering
* Boost Mode Enabled
* Boost Mode Temp
* Auto Start
*
* Power Saving
* Sleep Temp
* Sleep Time
* Shutdown Time
* Motion Sensitivity
*
* UI
* // Language
* Scrolling Speed
* Temperature Unit
* Display orientation
* Cooldown blink
*
* Advanced
* Detailed IDLE
* Detailed Soldering
* Logo Time
* Calibrate Temperature
* Calibrate Input V
* Reset Settings
*
*/
const menuitem rootSettingsMenu[] {
/*
* Power Source
* Soldering Menu
* Power Saving Menu
* UI Menu
* Advanced Menu
* Exit
*/
#ifdef MODEL_TS100
{ (const char*)SettingsDescriptions[0],
{ settings_setInputVRange},
{ settings_displayInputVRange}}, /*Voltage input*/
#else
{ (const char*) SettingsDescriptions[20], { settings_setInputPRange }, {
settings_displayInputPRange } }, /*Voltage input*/
#endif
{ (const char*) NULL, { settings_enterSolderingMenu }, {
settings_displaySolderingMenu } }, /*Soldering*/
{ (const char*) NULL, { settings_enterPowerMenu }, {
settings_displayPowerMenu } }, /*Sleep Options Menu*/
{ (const char*) NULL, { settings_enterUIMenu },
{ settings_displayUIMenu } }, /*UI Menu*/
{ (const char*) NULL, { settings_enterAdvancedMenu }, {
settings_displayAdvancedMenu } }, /*Advanced Menu*/
{ NULL, { NULL }, { NULL } } // end of menu marker. DO NOT REMOVE
};
const menuitem solderingMenu[] = {
/*
* Boost Mode Enabled
* Boost Mode Temp
* Auto Start
*/
{ (const char*) SettingsDescriptions[8], { settings_setBoostModeEnabled }, {
settings_displayBoostModeEnabled } }, /*Enable Boost*/
{ (const char*) SettingsDescriptions[9], { settings_setBoostTemp }, {
settings_displayBoostTemp } }, /*Boost Temp*/
{ (const char*) SettingsDescriptions[10], { settings_setAutomaticStartMode }, {
settings_displayAutomaticStartMode } }, /*Auto start*/
{ NULL, { NULL }, { NULL } } // end of menu marker. DO NOT REMOVE
};
const menuitem UIMenu[] = {
/*
// Language
* Scrolling Speed
* Temperature Unit
* Display orientation
* Cooldown blink
*/
{ (const char*) SettingsDescriptions[5], { settings_setTempF }, {
settings_displayTempF } }, /* Temperature units*/
{ (const char*) SettingsDescriptions[7], { settings_setDisplayRotation }, {
settings_displayDisplayRotation } }, /*Display Rotation*/
{ (const char*) SettingsDescriptions[11], { settings_setCoolingBlinkEnabled }, {
settings_displayCoolingBlinkEnabled } }, /*Cooling blink warning*/
{ (const char*) SettingsDescriptions[16], { settings_setScrollSpeed }, {
settings_displayScrollSpeed } }, /*Scroll Speed for descriptions*/
{ NULL, { NULL }, { NULL } } // end of menu marker. DO NOT REMOVE
};
const menuitem PowerMenu[] = {
/*
* Sleep Temp
* Sleep Time
* Shutdown Time
* Motion Sensitivity
*/
{ (const char*) SettingsDescriptions[1], { settings_setSleepTemp }, {
settings_displaySleepTemp } }, /*Sleep Temp*/
{ (const char*) SettingsDescriptions[2], { settings_setSleepTime }, {
settings_displaySleepTime } }, /*Sleep Time*/
{ (const char*) SettingsDescriptions[3], { settings_setShutdownTime }, {
settings_displayShutdownTime } }, /*Shutdown Time*/
{ (const char*) SettingsDescriptions[4], { settings_setSensitivity }, {
settings_displaySensitivity } }, /* Motion Sensitivity*/
{ NULL, { NULL }, { NULL } } // end of menu marker. DO NOT REMOVE
};
const menuitem advancedMenu[] = {
/*
* Detailed IDLE
* Detailed Soldering
* Logo Time
* Calibrate Temperature
* Calibrate Input V
* Reset Settings
*/
{ (const char*) SettingsDescriptions[6], { settings_setAdvancedIDLEScreens }, {
settings_displayAdvancedIDLEScreens } }, /* Advanced idle screen*/
{ (const char*) SettingsDescriptions[15],
{ settings_setAdvancedSolderingScreens }, {
settings_displayAdvancedSolderingScreens } }, /* Advanced soldering screen*/
{ (const char*) SettingsDescriptions[13], { settings_setResetSettings }, {
settings_displayResetSettings } }, /*Resets settings*/
{ (const char*) SettingsDescriptions[17], { settings_setTipModel }, {
settings_displayTipModel } }, /*Select tip Model */
{ (const char*) SettingsDescriptions[12], { settings_setCalibrate }, {
settings_displayCalibrate } }, /*Calibrate tip*/
{ (const char*) SettingsDescriptions[14], { settings_setCalibrateVIN }, {
settings_displayCalibrateVIN } }, /*Voltage input cal*/
{ NULL, { NULL }, { NULL } } // end of menu marker. DO NOT REMOVE
};
const menuitem calibrationMenu[] { { (const char*) SettingsDescriptions[6], {
calibration_enterSimpleCal }, { calibration_displaySimpleCal } },
/* Simple Cal*/
{ (const char*) SettingsDescriptions[6], { calibration_enterAdvancedCal }, {
calibration_displayAdvancedCal } }, /* Advanced Cal */
{ NULL, { NULL }, { NULL } } };
static void printShortDescriptionSingleLine(uint32_t shortDescIndex) {
OLED::setFont(0);
OLED::setCharCursor(0, 0);
OLED::print(SettingsShortNames[shortDescIndex][0]);
}
static void printShortDescriptionDoubleLine(uint32_t shortDescIndex) {
OLED::setFont(1);
OLED::setCharCursor(0, 0);
OLED::print(SettingsShortNames[shortDescIndex][0]);
OLED::setCharCursor(0, 1);
OLED::print(SettingsShortNames[shortDescIndex][1]);
}
/**
* Prints two small lines of short description
* and prepares cursor in big font after it.
* @param shortDescIndex Index to of short description.
* @param cursorCharPosition Custom cursor char position to set after printing
* description.
*/
static void printShortDescription(uint32_t shortDescIndex,
uint16_t cursorCharPosition) {
// print short description (default single line, explicit double line)
if (SettingsShortNameType == SHORT_NAME_DOUBLE_LINE) {
printShortDescriptionDoubleLine(shortDescIndex);
} else {
printShortDescriptionSingleLine(shortDescIndex);
}
// prepare cursor for value
OLED::setFont(0);
OLED::setCharCursor(cursorCharPosition, 0);
}
static int userConfirmation(const char* message) {
uint16_t messageWidth = FONT_12_WIDTH * (strlen(message) + 7);
uint32_t messageStart = xTaskGetTickCount();
OLED::setFont(0);
OLED::setCursor(0, 0);
int16_t lastOffset = -1;
bool lcdRefresh = true;
for (;;) {
int16_t messageOffset = ((xTaskGetTickCount() - messageStart)
/ (systemSettings.descriptionScrollSpeed == 1 ? 1 : 2));
messageOffset %= messageWidth; // Roll around at the end
if (lastOffset != messageOffset) {
OLED::clearScreen();
//^ Rolling offset based on time
OLED::setCursor((OLED_WIDTH - messageOffset), 0);
OLED::print(message);
lastOffset = messageOffset;
lcdRefresh = true;
}
ButtonState buttons = getButtonState();
switch (buttons) {
case BUTTON_F_SHORT:
// User confirmed
return 1;
case BUTTON_NONE:
break;
default:
case BUTTON_BOTH:
case BUTTON_B_SHORT:
case BUTTON_F_LONG:
case BUTTON_B_LONG:
return 0;
}
if (lcdRefresh) {
OLED::refresh();
osDelay(40);
lcdRefresh = false;
}
}
return 0;
}
#ifdef MODEL_TS100
static void settings_setInputVRange(void) {
systemSettings.cutoutSetting = (systemSettings.cutoutSetting + 1) % 5;
}
static void settings_displayInputVRange(void) {
printShortDescription(0, 6);
if (systemSettings.cutoutSetting) {
OLED::printNumber(2 + systemSettings.cutoutSetting,1);
OLED::print(SymbolCellCount);
} else {
OLED::print(SymbolDC);
}
}
#else
static void settings_setInputPRange(void) {
systemSettings.cutoutSetting = (systemSettings.cutoutSetting + 1) % 2;
}
static void settings_displayInputPRange(void) {
printShortDescription(0, 5);
//0 = 9V, 1=12V (Fixed Voltages, these imply 1.5A limits)
//2 = 18W, 2=24W (Auto Adjusting V, estimated from the tip resistance???) # TODO
// Need to come back and look at these ^ as there were issues with voltage hunting
switch (systemSettings.cutoutSetting) {
case 0:
OLED::printNumber(9, 2);
OLED::print(SymbolVolts);
break;
case 1:
OLED::printNumber(12, 2);
OLED::print(SymbolVolts);
break;
default:
break;
}
}
#endif
static void settings_setSleepTemp(void) {
// If in C, 10 deg, if in F 20 deg
if (systemSettings.temperatureInF) {
systemSettings.SleepTemp += 20;
if (systemSettings.SleepTemp > 580)
systemSettings.SleepTemp = 120;
} else {
systemSettings.SleepTemp += 10;
if (systemSettings.SleepTemp > 300)
systemSettings.SleepTemp = 50;
}
}
static void settings_displaySleepTemp(void) {
printShortDescription(1, 5);
OLED::printNumber(systemSettings.SleepTemp, 3);
}
static void settings_setSleepTime(void) {
systemSettings.SleepTime++; // Go up 1 minute at a time
if (systemSettings.SleepTime >= 16) {
systemSettings.SleepTime = 0; // can't set time over 10 mins
}
// Remember that ^ is the time of no movement
if (PCBVersion == 3)
systemSettings.SleepTime = 0; // Disable sleep on no accel
}
static void settings_displaySleepTime(void) {
printShortDescription(2, 5);
if (systemSettings.SleepTime == 0) {
OLED::print(OffString);
} else if (systemSettings.SleepTime < 6) {
OLED::printNumber(systemSettings.SleepTime * 10, 2);
OLED::print(SymbolSeconds);
} else {
OLED::printNumber(systemSettings.SleepTime - 5, 2);
OLED::print(SymbolMinutes);
}
}
static void settings_setShutdownTime(void) {
systemSettings.ShutdownTime++;
if (systemSettings.ShutdownTime > 60) {
systemSettings.ShutdownTime = 0; // wrap to off
}
if (PCBVersion == 3)
systemSettings.ShutdownTime = 0; // Disable shutdown on no accel
}
static void settings_displayShutdownTime(void) {
printShortDescription(3, 5);
if (systemSettings.ShutdownTime == 0) {
OLED::print(OffString);
} else {
OLED::printNumber(systemSettings.ShutdownTime, 2);
OLED::print(SymbolMinutes);
}
}
static void settings_setTempF(void) {
systemSettings.temperatureInF = !systemSettings.temperatureInF;
if (systemSettings.temperatureInF) {
// Change sleep, boost and soldering temps to the F equiv
// C to F == F= ( (C*9) +160)/5
systemSettings.BoostTemp = ((systemSettings.BoostTemp * 9) + 160) / 5;
systemSettings.SolderingTemp =
((systemSettings.SolderingTemp * 9) + 160) / 5;
systemSettings.SleepTemp = ((systemSettings.SleepTemp * 9) + 160) / 5;
} else {
// Change sleep, boost and soldering temps to the C equiv
// F->C == C = ((F-32)*5)/9
systemSettings.BoostTemp = ((systemSettings.BoostTemp - 32) * 5) / 9;
systemSettings.SolderingTemp = ((systemSettings.SolderingTemp - 32) * 5)
/ 9;
systemSettings.SleepTemp = ((systemSettings.SleepTemp - 32) * 5) / 9;
}
// Rescale both to be multiples of 10
systemSettings.BoostTemp = systemSettings.BoostTemp / 10;
systemSettings.BoostTemp *= 10;
systemSettings.SolderingTemp = systemSettings.SolderingTemp / 10;
systemSettings.SolderingTemp *= 10;
systemSettings.SleepTemp = systemSettings.SleepTemp / 10;
systemSettings.SleepTemp *= 10;
}
static void settings_displayTempF(void) {
printShortDescription(5, 7);
OLED::print((systemSettings.temperatureInF) ? SymbolDegF : SymbolDegC);
}
static void settings_setSensitivity(void) {
systemSettings.sensitivity++;
systemSettings.sensitivity = systemSettings.sensitivity % 10;
}
static void settings_displaySensitivity(void) {
printShortDescription(4, 7);
OLED::printNumber(systemSettings.sensitivity, 1);
}
static void settings_setAdvancedSolderingScreens(void) {
systemSettings.detailedSoldering = !systemSettings.detailedSoldering;
}
static void settings_displayAdvancedSolderingScreens(void) {
printShortDescription(15, 7);
OLED::drawCheckbox(systemSettings.detailedSoldering);
}
static void settings_setAdvancedIDLEScreens(void) {
systemSettings.detailedIDLE = !systemSettings.detailedIDLE;
}
static void settings_displayAdvancedIDLEScreens(void) {
printShortDescription(6, 7);
OLED::drawCheckbox(systemSettings.detailedIDLE);
}
static void settings_setScrollSpeed(void) {
if (systemSettings.descriptionScrollSpeed == 0)
systemSettings.descriptionScrollSpeed = 1;
else
systemSettings.descriptionScrollSpeed = 0;
}
static void settings_displayScrollSpeed(void) {
printShortDescription(16, 7);
OLED::print(
(systemSettings.descriptionScrollSpeed) ?
SettingFastChar : SettingSlowChar);
}
static void settings_setDisplayRotation(void) {
systemSettings.OrientationMode++;
systemSettings.OrientationMode = systemSettings.OrientationMode % 3;
switch (systemSettings.OrientationMode) {
case 0:
OLED::setRotation(false);
break;
case 1:
OLED::setRotation(true);
break;
case 2:
// do nothing on auto
break;
default:
break;
}
}
static void settings_displayDisplayRotation(void) {
printShortDescription(7, 7);
switch (systemSettings.OrientationMode) {
case 0:
OLED::print(SettingRightChar);
break;
case 1:
OLED::print(SettingLeftChar);
break;
case 2:
OLED::print(SettingAutoChar);
break;
default:
OLED::print(SettingRightChar);
break;
}
}
static void settings_setBoostModeEnabled(void) {
systemSettings.boostModeEnabled = !systemSettings.boostModeEnabled;
}
static void settings_displayBoostModeEnabled(void) {
printShortDescription(8, 7);
OLED::drawCheckbox(systemSettings.boostModeEnabled);
}
static void settings_setBoostTemp(void) {
if (systemSettings.temperatureInF) {
systemSettings.BoostTemp += 20; // Go up 20F at a time
if (systemSettings.BoostTemp > 850) {
systemSettings.BoostTemp = 480; // loop back at 250
}
} else {
systemSettings.BoostTemp += 10; // Go up 10C at a time
if (systemSettings.BoostTemp > 450) {
systemSettings.BoostTemp = 250; // loop back at 250
}
}
}
static void settings_displayBoostTemp(void) {
printShortDescription(9, 5);
OLED::printNumber(systemSettings.BoostTemp, 3);
}
static void settings_setAutomaticStartMode(void) {
systemSettings.autoStartMode++;
systemSettings.autoStartMode %= 2;
}
static void settings_displayAutomaticStartMode(void) {
printShortDescription(10, 7);
OLED::drawCheckbox(systemSettings.autoStartMode);
}
static void settings_setCoolingBlinkEnabled(void) {
systemSettings.coolingTempBlink = !systemSettings.coolingTempBlink;
}
static void settings_displayCoolingBlinkEnabled(void) {
printShortDescription(11, 7);
OLED::drawCheckbox(systemSettings.coolingTempBlink);
}
static void settings_setResetSettings(void) {
if (userConfirmation(SettingsResetWarning)) {
resetSettings();
OLED::setFont(0);
OLED::setCursor(0, 0);
OLED::print(ResetOKMessage);
OLED::refresh();
waitForButtonPressOrTimeout(200); // 2 second timeout
}
}
static void settings_displayResetSettings(void) {
printShortDescription(13, 7);
}
static void settings_setTipModel(void) {
systemSettings.tipType++;
if(systemSettings.tipType==Tip_MiniWare)
systemSettings.tipType++;
#ifdef MODEL_TS100
if(systemSettings.tipType==Tip_Hakko)
systemSettings.tipType++;
#endif
systemSettings.tipType %= (Tip_Custom + 1); // Wrap after custom
}
static void settings_displayTipModel(void) {
printShortDescription(17, 4);
// Print in small text the tip model
OLED::setFont(1);
// set the cursor
// Print the mfg
OLED::setCursor(55, 0);
if (systemSettings.tipType == Tip_Custom) {
OLED::print(TipModelStrings[Tip_Custom]);
} else if (systemSettings.tipType < Tip_MiniWare) {
OLED::print(TipModelStrings[Tip_MiniWare]);
}
#ifdef MODEL_TS100
else if (systemSettings.tipType < Tip_Hakko) {
OLED::print(TipModelStrings[Tip_Hakko]);
}
#endif
OLED::setCursor(55, 8);
if (systemSettings.tipType != Tip_Custom)
OLED::print(TipModelStrings[systemSettings.tipType]);
}
static void calibration_displaySimpleCal(void) {
printShortDescription(18, 5);
}
static void setTipOffset() {
setCalibrationOffset(0); // turn off the current offset
// If the thermocouple at the end of the tip, and the handle are at
// equalibrium, then the output should be zero, as there is no temperature
// differential.
uint32_t offset = 0;
for (uint8_t i = 0; i < 15; i++) {
offset += getTipRawTemp(0);
// cycle through the filter a fair bit to ensure we're stable.
OLED::clearScreen();
OLED::setCursor(0, 0);
OLED::print(SymbolDot);
for (uint8_t x = 0; x < i / 4; x++)
OLED::print(SymbolDot);
OLED::refresh();
osDelay(100);
}
systemSettings.CalibrationOffset = offset / 15;
// Need to remove from this the ambient temperature offset
uint32_t ambientoffset = getHandleTemperature(); // Handle temp in C x10
ambientoffset *= 100;
ambientoffset /= tipGainCalValue;
systemSettings.CalibrationOffset -= ambientoffset;
setCalibrationOffset(systemSettings.CalibrationOffset); // store the error
OLED::clearScreen();
OLED::setCursor(0, 0);
OLED::drawCheckbox(true);
OLED::refresh();
osDelay(1000);
}
static void calibration_enterSimpleCal(void) {
// User has entered into the simple cal routine
if (userConfirmation(SettingsCalibrationWarning)) {
// User has confirmed their handle is at ambient
// So take the offset measurement
setTipOffset();
// Next we want the user to put the tip into 100C water so we can calculate
// their tip's gain Gain is the m term from rise/run plot of raw readings vs
// (tip-handle) Thus we want to calculate
// ([TipRawHot-TipRawCold])/(ActualHot-HandleHot)-(ActualCold-HandleCold)
// Thus we first need to store ->
// TiprawCold,HandleCold,ActualCold==HandleCold -> RawTipCold
uint32_t RawTipCold = getTipRawTemp(0) * 10;
OLED::clearScreen();
OLED::setCursor(0, 0);
OLED::setFont(1);
OLED::print("Please Insert Tip\nInto Boiling Water");
OLED::refresh();
osDelay(200);
waitForButtonPress();
// Now take the three hot measurements
// Assume water is boiling at 100C
uint32_t RawTipHot = getTipRawTemp(0) * 10;
uint32_t HandleTempHot = getHandleTemperature() / 10;
uint32_t gain = (RawTipHot - RawTipCold) / (100 - HandleTempHot);
// Show this to the user
OLED::clearScreen();
OLED::setCursor(0, 0);
OLED::print(YourGainMessage);
OLED::printNumber(gain, 6);
OLED::refresh();
osDelay(2000);
waitForButtonPress();
OLED::clearScreen();
OLED::setCursor(0, 0);
OLED::print(SymbolPlus);
OLED::printNumber(RawTipHot, 8);
OLED::setCursor(0, 8);
OLED::print(SymbolMinus);
OLED::printNumber(RawTipCold, 8);
OLED::refresh();
osDelay(2000);
waitForButtonPress();
}
}
static void calibration_displayAdvancedCal(void) {
printShortDescription(19, 5);
}
static void calibration_enterAdvancedCal(void) {
//Advanced cal
if (userConfirmation(SettingsCalibrationWarning)) {
//User has confirmed their handle is at ambient
//So take the offset measurement
setTipOffset();
//The tip now has a known ADC offset
//Head up until it is at 350C
//Then let the user adjust the gain value until it converges
systemSettings.customTipGain = 160; // start safe and high
bool exit = false;
while (exit == false) {
//Set tip to 350C
setTipType(Tip_Custom, systemSettings.customTipGain);
currentlyActiveTemperatureTarget = ctoTipMeasurement(350);
//Check if user has pressed button to change the gain
ButtonState buttons = getButtonState();
switch (buttons) {
case BUTTON_NONE:
break;
case BUTTON_BOTH:
case BUTTON_B_LONG:
case BUTTON_F_LONG:
exit = true;
break;
case BUTTON_F_SHORT:
systemSettings.customTipGain++;
break;
case BUTTON_B_SHORT: {
systemSettings.customTipGain--;
}
break;
default:
break;
}
if (systemSettings.customTipGain > 200)
systemSettings.customTipGain = 200;
else if (systemSettings.customTipGain <= 100)
systemSettings.customTipGain = 100;
OLED::setCursor(0, 0);
OLED::clearScreen();
OLED::setFont(0);
if (OLED::getRotation())
OLED::print(SymbolMinus);
else
OLED::print(SymbolPlus);
OLED::print(SymbolSpace);
OLED::printNumber(systemSettings.customTipGain, 4);
OLED::print(SymbolSpace);
if (OLED::getRotation())
OLED::print(SymbolPlus);
else
OLED::print(SymbolMinus);
OLED::refresh();
GUIDelay();
}
// Wait for the user to confirm the exit message that the calibration is done
userConfirmation(SettingsCalibrationDone);
}
}
//Provide the user the option to tune their own tip if custom is selected
//If not only do single point tuning as per usual
static void settings_setCalibrate(void) {
if (systemSettings.tipType == Tip_Custom) {
// Two types of calibration
// 1. Basic, idle temp + hot water (100C)
// 2. Advanced, 100C + 350C, we keep PID tracking to a temperature target
return gui_Menu(calibrationMenu);
}
// Else
// Ask user if handle is at the tip temperature
// Any error between handle and the tip will be a direct offset in the control
// loop
else if (userConfirmation(SettingsCalibrationWarning)) {
// User confirmed
// So we now perform the actual calculation
setTipOffset();
}
}
static void settings_displayCalibrate(void) {
printShortDescription(12, 5);
}
static void settings_setCalibrateVIN(void) {
// Jump to the voltage calibration subscreen
OLED::setFont(0);
OLED::clearScreen();
OLED::setCursor(0, 0);
for (;;) {
OLED::setCursor(0, 0);
OLED::printNumber(getInputVoltageX10(systemSettings.voltageDiv, 0) / 10,
2);
OLED::print(SymbolDot);
OLED::printNumber(getInputVoltageX10(systemSettings.voltageDiv, 0) % 10,
1);
OLED::print(SymbolVolts);
ButtonState buttons = getButtonState();
switch (buttons) {
case BUTTON_F_SHORT:
systemSettings.voltageDiv++;
break;
case BUTTON_B_SHORT:
systemSettings.voltageDiv--;
break;
case BUTTON_BOTH:
case BUTTON_F_LONG:
case BUTTON_B_LONG:
saveSettings();
return;
break;
case BUTTON_NONE:
default:
break;
}
OLED::refresh();
osDelay(40);
// Cap to sensible values
#ifdef MODEL_TS80
if (systemSettings.voltageDiv < 500) {
systemSettings.voltageDiv = 500;
} else if (systemSettings.voltageDiv > 900) {
systemSettings.voltageDiv = 900;
}
#else
if (systemSettings.voltageDiv < 360) {
systemSettings.voltageDiv = 360;
} else if (systemSettings.voltageDiv > 520) {
systemSettings.voltageDiv = 520;
}
#endif
}
}
static void displayMenu(size_t index) {
// Call into the menu
OLED::setFont(1);
OLED::setCursor(0, 0);
// Draw title
OLED::print(SettingsMenuEntries[index]);
// Draw symbol
// 16 pixel wide image
OLED::drawArea(96 - 16, 0, 16, 16, (&SettingsMenuIcons[(16 * 2) * index]));
}
static void settings_displayCalibrateVIN(void) {
printShortDescription(14, 5);
}
static void settings_displaySolderingMenu(void) {
displayMenu(0);
}
static void settings_enterSolderingMenu(void) {
gui_Menu(solderingMenu);
}
static void settings_displayPowerMenu(void) {
displayMenu(1);
}
static void settings_enterPowerMenu(void) {
gui_Menu(PowerMenu);
}
static void settings_displayUIMenu(void) {
displayMenu(2);
}
static void settings_enterUIMenu(void) {
gui_Menu(UIMenu);
}
static void settings_displayAdvancedMenu(void) {
displayMenu(3);
}
static void settings_enterAdvancedMenu(void) {
gui_Menu(advancedMenu);
}
void gui_Menu(const menuitem* menu) {
// Draw the settings menu and provide iteration support etc
uint8_t currentScreen = 0;
uint32_t autoRepeatTimer = 0;
uint8_t autoRepeatAcceleration = 0;
bool earlyExit = false;
uint32_t descriptionStart = 0;
int16_t lastOffset = -1;
bool lcdRefresh = true;
ButtonState lastButtonState = BUTTON_NONE;
while ((menu[currentScreen].draw.func != NULL) && earlyExit == false) {
OLED::setFont(0);
OLED::setCursor(0, 0);
// If the user has hesitated for >=3 seconds, show the long text
// Otherwise "draw" the option
if ((xTaskGetTickCount() - lastButtonTime < 300)
|| menu[currentScreen].description == NULL) {
OLED::clearScreen();
menu[currentScreen].draw.func();
lastOffset = -1;
lcdRefresh = true;
} else {
// Draw description
if (descriptionStart == 0)
descriptionStart = xTaskGetTickCount();
// lower the value - higher the speed
int16_t descriptionWidth =
FONT_12_WIDTH * (strlen(menu[currentScreen].description) + 7);
int16_t descriptionOffset =
((xTaskGetTickCount() - descriptionStart)
/ (systemSettings.descriptionScrollSpeed == 1 ?
1 : 2));
descriptionOffset %= descriptionWidth; // Roll around at the end
if (lastOffset != descriptionOffset) {
OLED::clearScreen();
//^ Rolling offset based on time
OLED::setCursor((OLED_WIDTH - descriptionOffset), 0);
OLED::print(menu[currentScreen].description);
lastOffset = descriptionOffset;
lcdRefresh = true;
}
}
ButtonState buttons = getButtonState();
if (buttons != lastButtonState) {
autoRepeatAcceleration = 0;
lastButtonState = buttons;
}
switch (buttons) {
case BUTTON_BOTH:
earlyExit = true; // will make us exit next loop
descriptionStart = 0;
break;
case BUTTON_F_SHORT:
// increment
if (descriptionStart == 0) {
if (menu[currentScreen].incrementHandler.func != NULL)
menu[currentScreen].incrementHandler.func();
else
earlyExit = true;
} else
descriptionStart = 0;
break;
case BUTTON_B_SHORT:
if (descriptionStart == 0)
currentScreen++;
else
descriptionStart = 0;
break;
case BUTTON_F_LONG:
if (xTaskGetTickCount() - autoRepeatTimer + autoRepeatAcceleration >
PRESS_ACCEL_INTERVAL_MAX) {
menu[currentScreen].incrementHandler.func();
autoRepeatTimer = xTaskGetTickCount();
descriptionStart = 0;
autoRepeatAcceleration += PRESS_ACCEL_STEP;
}
break;
case BUTTON_B_LONG:
if (xTaskGetTickCount() - autoRepeatTimer + autoRepeatAcceleration >
PRESS_ACCEL_INTERVAL_MAX) {
currentScreen++;
autoRepeatTimer = xTaskGetTickCount();
descriptionStart = 0;
autoRepeatAcceleration += PRESS_ACCEL_STEP;
}
break;
case BUTTON_NONE:
default:
break;
}
if ((PRESS_ACCEL_INTERVAL_MAX - autoRepeatAcceleration) <
PRESS_ACCEL_INTERVAL_MIN) {
autoRepeatAcceleration =
PRESS_ACCEL_INTERVAL_MAX - PRESS_ACCEL_INTERVAL_MIN;
}
if (lcdRefresh) {
OLED::refresh(); // update the LCD
osDelay(40);
lcdRefresh = false;
}
}
}
void enterSettingsMenu() {
gui_Menu(rootSettingsMenu); // Call the root menu
saveSettings();
}

View File

@@ -0,0 +1,479 @@
/*
* hardware.c
*
* Created on: 2Sep.,2017
* Author: Ben V. Brown
*/
// These are all the functions for interacting with the hardware
#include "hardware.h"
#include "FreeRTOS.h"
#include "stm32f1xx_hal.h"
#include "cmsis_os.h"
volatile uint16_t PWMSafetyTimer = 0;
volatile int16_t CalibrationTempOffset = 0;
uint16_t tipGainCalValue = 0;
void setTipType(enum TipType tipType, uint8_t manualCalGain) {
if (manualCalGain)
tipGainCalValue = manualCalGain;
else
tipGainCalValue = lookupTipDefaultCalValue(tipType);
}
void setCalibrationOffset(int16_t offSet) {
CalibrationTempOffset = offSet;
}
uint16_t getHandleTemperature() {
// We return the current handle temperature in X10 C
// TMP36 in handle, 0.5V offset and then 10mV per deg C (0.75V @ 25C for
// example) STM32 = 4096 count @ 3.3V input -> But We oversample by 32/(2^2) =
// 8 times oversampling Therefore 32768 is the 3.3V input, so 0.1007080078125
// mV per count So we need to subtract an offset of 0.5V to center on 0C
// (4964.8 counts)
//
int32_t result = getADC(0);
result -= 4965; // remove 0.5V offset
// 10mV per C
// 99.29 counts per Deg C above 0C
result *= 100;
result /= 993;
return result;
}
uint16_t tipMeasurementToC(uint16_t raw) {
//((Raw Tip-RawOffset) * calibrationgain) / 1000 = tip delta in CX10
// tip delta in CX10 + handleTemp in CX10 = tip absolute temp in CX10
// Div answer by 10 to get final result
uint32_t tipDelta = ((raw - CalibrationTempOffset) * tipGainCalValue)
/ 1000;
tipDelta += getHandleTemperature();
return tipDelta / 10;
}
uint16_t ctoTipMeasurement(uint16_t temp) {
//[ (temp-handle/10) * 10000 ]/calibrationgain = tip raw delta
// tip raw delta + tip offset = tip ADC reading
int32_t TipRaw = ((temp - (getHandleTemperature() / 10)) * 10000)
/ tipGainCalValue;
TipRaw += CalibrationTempOffset;
return TipRaw;
}
uint16_t tipMeasurementToF(uint16_t raw) {
// Convert result from C to F
return (tipMeasurementToC(raw) * 9) / 5 + 32;
}
uint16_t ftoTipMeasurement(uint16_t temp) {
// Convert the temp back to C from F
return ctoTipMeasurement(((temp - 32) * 5) / 9);
}
uint16_t getTipInstantTemperature() {
uint16_t sum;
sum = hadc1.Instance->JDR1;
sum += hadc1.Instance->JDR2;
sum += hadc1.Instance->JDR3;
sum += hadc1.Instance->JDR4;
sum += hadc2.Instance->JDR1;
sum += hadc2.Instance->JDR2;
sum += hadc2.Instance->JDR3;
sum += hadc2.Instance->JDR4;
return sum; // 8x over sample
}
/*
* Loopup table for the tip calibration values for
* the gain of the tip's
* This can be found by line of best fit of TipRaw on X, and TipTemp-handle on
* Y. Then take the m term * 10000
* */
uint16_t lookupTipDefaultCalValue(enum TipType tipID) {
#ifdef MODEL_TS100
switch (tipID) {
case TS_D24:
return 141;
break;
case TS_BC2:
return (133 + 129) / 2;
break;
case TS_C1:
return 133;
break;
case TS_B2:
return 133;
default:
return 132; // make this the average of all
break;
}
#else
switch (tipID) {
case TS_D25:
return 154;
break;
case TS_B02:
return 154;
break;
default:
return 154; // make this the average of all
break;
}
#endif
}
uint16_t getTipRawTemp(uint8_t refresh) {
static uint16_t lastSample = 0;
if (refresh) {
lastSample = getTipInstantTemperature();
}
return lastSample;
}
uint16_t getInputVoltageX10(uint16_t divisor, uint8_t sample) {
// ADC maximum is 32767 == 3.3V at input == 28.05V at VIN
// Therefore we can divide down from there
// Multiplying ADC max by 4 for additional calibration options,
// ideal term is 467
#define BATTFILTERDEPTH 32
static uint8_t preFillneeded = 10;
static uint32_t samples[BATTFILTERDEPTH];
static uint8_t index = 0;
if (preFillneeded) {
for (uint8_t i = 0; i < BATTFILTERDEPTH; i++)
samples[i] = getADC(1);
preFillneeded--;
}
if (sample) {
samples[index] = getADC(1);
index = (index + 1) % BATTFILTERDEPTH;
}
uint32_t sum = 0;
for (uint8_t i = 0; i < BATTFILTERDEPTH; i++)
sum += samples[i];
sum /= BATTFILTERDEPTH;
return sum * 4 / divisor;
}
#ifdef MODEL_TS80
uint8_t QCMode = 0;
uint8_t QCTries = 0;
void seekQC(int16_t Vx10, uint16_t divisor) {
if (QCMode == 5)
startQC(divisor);
if (QCMode == 0)
return; // NOT connected to a QC Charger
if (Vx10 < 45)
return;
if (Vx10 > 130)
Vx10 = 130; //Cap max value at 13V
// Seek the QC to the Voltage given if this adapter supports continuous mode
// try and step towards the wanted value
// 1. Measure current voltage
int16_t vStart = getInputVoltageX10(divisor, 0);
int difference = Vx10 - vStart;
// 2. calculate ideal steps (0.2V changes)
int steps = difference / 2;
if (QCMode == 3) {
while (steps < 0) {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET); //D+0.6
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); //D-3.3V
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET); // D-3.3Vs
vTaskDelay(3);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); //-0.6V
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_Delay(1);
steps++;
}
while (steps > 0) {
// step once up
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
vTaskDelay(3);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
HAL_Delay(1);
steps--;
}
}
// Re-measure
/* Disabled due to nothing to test and code space of around 1k*/
#ifdef QC2_ROUND_DOWN
steps = vStart - getInputVoltageX10(195);
if (steps < 0) steps = -steps;
if (steps > (difference / 2)) {
// No continuous mode, so QC2
QCMode = 2;
// Goto nearest
if (Vx10 > 10.5) {
// request 12V
// D- = 0.6V, D+ = 0.6V
// Clamp PB3
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);// pull down D+
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
} else {
// request 9V
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
}
}
#endif
}
// Must be called after FreeRToS Starts
void startQC(uint16_t divisor) {
// Pre check that the input could be >5V already, and if so, dont both
// negotiating as someone is feeding in hv
uint16_t vin = getInputVoltageX10(divisor, 1);
if (vin > 150)
return; // Over voltage
if (vin > 100) {
QCMode = 1; // ALready at ~12V
return;
}
GPIO_InitTypeDef GPIO_InitStruct;
// Tries to negotiate QC for 9V
// This is a multiple step process.
// 1. Set around 0.6V on D+ for 1.25 Seconds or so
// 2. After this It should un-short D+->D- and instead add a 20k pulldown on
// D-
// 3. Now set D+ to 3.3V and D- to 0.6V to request 9V
// OR both at 0.6V for 12V request (if the adapter can do it).
// If 12V is implimented then should fallback to 9V after validation
// Step 1. We want to pull D+ to 0.6V
// Pull PB3 donwn to ground
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);// pull low to put 0.6V on D+
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);// pull low to put 0.6V on D+
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_14 | GPIO_PIN_13;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// Delay 1.25 seconds
uint8_t enteredQC = 0;
for (uint16_t i = 0; i < 130 && enteredQC == 0; i++) {
// HAL_Delay(10);
vTaskDelay(1);
}
// Check if D- is low to spot a QC charger
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == GPIO_PIN_RESET)
enteredQC = 1;
if (enteredQC) {
// We have a QC capable charger
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_8;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
// Wait for frontend ADC to stabilise
QCMode = 4;
for (uint8_t i = 0; i < 10; i++) {
if (getInputVoltageX10(divisor, 1) > 80) {
// yay we have at least QC2.0 or QC3.0
QCMode = 3; // We have at least QC2, pray for 3
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
return;
}
vTaskDelay(10); // 100mS
}
QCMode = 5;
QCTries++;
if (QCTries > 10) // 10 goes to get it going
QCMode = 0;
} else {
// no QC
QCMode = 0;
}
if (QCTries > 10)
QCMode = 0;
}
// Get tip resistance in milliohms
uint32_t calculateTipR() {
static uint32_t lastRes = 0;
if (lastRes)
return lastRes;
// We inject a small current into the front end of the iron,
// By measuring the Vdrop over the tip we can calculate the resistance
// Turn PA0 into an output and drive high to inject (3.3V-0.6)/(6K8+Rtip)
// current PA0->Diode -> 6K8 -> Tip -> GND So the op-amp will amplify the
// small signal across the tip and convert this into an easily read voltage
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // Set low first
setTipPWM(0);
vTaskDelay(1);
uint32_t offReading = getTipRawTemp(1);
for (uint8_t i = 0; i < 49; i++) {
vTaskDelay(1); // delay to allow it to stabilize
HAL_IWDG_Refresh(&hiwdg);
offReading += getTipRawTemp(1);
}
// Turn on
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // Set hgih
vTaskDelay(1); // delay to allow it too stabilize
uint32_t onReading = getTipInstantTemperature();
for (uint8_t i = 0; i < 49; i++) {
vTaskDelay(1); // delay to allow it to stabilize
HAL_IWDG_Refresh(&hiwdg);
onReading += getTipRawTemp(1);
}
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // Turn the output off finally
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
uint32_t difference = onReading - offReading;
// V = IR, therefore I = V/R
// We can divide this reading by a known "gain" to get the resulting
// resistance This was determined emperically This tip is 4.688444162 ohms,
// 4688 milliohms (Measured using 4 terminal measurement) 25x oversampling
// reads this as around 47490 Almost perfectly 10x the milliohms value This
// will drift massively with tip temp However we really only need 10x ohms
lastRes = (difference / 21) + 1; // ceil
return lastRes;
}
static unsigned int sqrt32(unsigned long n) {
unsigned int c = 0x8000;
unsigned int g = 0x8000;
for (;;) {
if (g * g > n)
g ^= c;
c >>= 1;
if (c == 0)
return g;
g |= c;
}
}
int16_t calculateMaxVoltage(uint8_t useHP) {
// This measures the tip resistance, then it calculates the appropriate
// voltage To stay under ~18W. Mosfet is "9A", so no issues there
// QC3.0 supports up to 18W, which is 2A @9V and 1.5A @12V
uint32_t milliOhms = calculateTipR();
// Check no tip
if (milliOhms > 10000)
return -1;
//Because of tolerance, if a user has asked for the higher power mode, then just goto 12V and call it a day
if (useHP)
return 120;
//
// V = sqrt(18W*R)
// Convert this to sqrt(18W)*sqrt(milli ohms)*sqrt(1/1000)
uint32_t Vx = sqrt32(milliOhms);
if (useHP)
Vx *= 1549; //sqrt(24)*sqrt(1/1000)*10000
else
Vx *= 1342; // sqrt(18) * sqrt(1/1000)*10000
// Round to nearest 200mV,
// So divide by 100 to start, to get in Vxx
Vx /= 100;
if (Vx % 10 >= 5)
Vx += 10;
Vx /= 10;
// Round to nearest increment of 2
if (Vx % 2 == 1)
Vx++;
//Because of how bad the tolerance is on detecting the tip resistance is
//Its more functional to bin this
if (Vx < 90)
Vx = 90;
else if (Vx >= 105)
Vx = 120;
return Vx;
}
#endif
volatile uint8_t pendingPWM = 0;
void setTipPWM(uint8_t pulse) {
PWMSafetyTimer = 10; // This is decremented in the handler for PWM so that the tip pwm is
// disabled if the PID task is not scheduled often enough.
pendingPWM = pulse;
}
// These are called by the HAL after the corresponding events from the system
// timers.
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
// Period has elapsed
if (htim->Instance == TIM2) {
// we want to turn on the output again
PWMSafetyTimer--;
// We decrement this safety value so that lockups in the
// scheduler will not cause the PWM to become locked in an
// active driving state.
// While we could assume this could never happen, its a small price for
// increased safety
htim2.Instance->CCR4 = pendingPWM;
if (htim2.Instance->CCR4 && PWMSafetyTimer) {
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
} else {
HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_1);
}
} else if (htim->Instance == TIM1) {
// STM uses this for internal functions as a counter for timeouts
HAL_IncTick();
}
}
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) {
// This was a when the PWM for the output has timed out
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4) {
HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_1);
}
}
void vApplicationIdleHook(void) {
HAL_IWDG_Refresh(&hiwdg);
}
/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE];
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) {
*ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
*ppxIdleTaskStackBuffer = &xIdleStack[0];
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
/* place for user code */
}
/* USER CODE END GET_IDLE_TASK_MEMORY */

View File

@@ -0,0 +1,479 @@
/*
* hardware.c
*
* Created on: 2Sep.,2017
* Author: Ben V. Brown
*/
// These are all the functions for interacting with the hardware
#include "hardware.h"
#include "FreeRTOS.h"
#include "stm32f1xx_hal.h"
#include "cmsis_os.h"
#include "history.hpp"
volatile uint16_t PWMSafetyTimer = 0;
volatile int16_t CalibrationTempOffset = 0;
uint16_t tipGainCalValue = 0;
void setTipType(enum TipType tipType, uint8_t manualCalGain) {
if (manualCalGain)
tipGainCalValue = manualCalGain;
else
tipGainCalValue = lookupTipDefaultCalValue(tipType);
}
void setCalibrationOffset(int16_t offSet) {
CalibrationTempOffset = offSet;
}
uint16_t getHandleTemperature() {
// We return the current handle temperature in X10 C
// TMP36 in handle, 0.5V offset and then 10mV per deg C (0.75V @ 25C for
// example) STM32 = 4096 count @ 3.3V input -> But We oversample by 32/(2^2) =
// 8 times oversampling Therefore 32768 is the 3.3V input, so 0.1007080078125
// mV per count So we need to subtract an offset of 0.5V to center on 0C
// (4964.8 counts)
//
int32_t result = getADC(0);
result -= 4965; // remove 0.5V offset
// 10mV per C
// 99.29 counts per Deg C above 0C
result *= 100;
result /= 993;
return result;
}
uint16_t tipMeasurementToC(uint16_t raw) {
//((Raw Tip-RawOffset) * calibrationgain) / 1000 = tip delta in CX10
// tip delta in CX10 + handleTemp in CX10 = tip absolute temp in CX10
// Div answer by 10 to get final result
uint32_t tipDelta = ((raw - CalibrationTempOffset) * tipGainCalValue)
/ 1000;
tipDelta += getHandleTemperature();
return tipDelta / 10;
}
uint16_t ctoTipMeasurement(uint16_t temp) {
//[ (temp-handle/10) * 10000 ]/calibrationgain = tip raw delta
// tip raw delta + tip offset = tip ADC reading
int32_t TipRaw = ((temp - (getHandleTemperature() / 10)) * 10000)
/ tipGainCalValue;
TipRaw += CalibrationTempOffset;
return TipRaw;
}
uint16_t tipMeasurementToF(uint16_t raw) {
// Convert result from C to F
return (tipMeasurementToC(raw) * 9) / 5 + 32;
}
uint16_t ftoTipMeasurement(uint16_t temp) {
// Convert the temp back to C from F
return ctoTipMeasurement(((temp - 32) * 5) / 9);
}
uint16_t getTipInstantTemperature() {
uint16_t sum = 0; // 12 bit readings * 8 -> 15 bits
uint16_t readings[8];
//Looking to reject the highest outlier readings.
//As on some hardware these samples can run into the op-amp recovery time
//Once this time is up the signal stabilises quickly, so no need to reject minimums
readings[0] = hadc1.Instance->JDR1;
readings[1] = hadc1.Instance->JDR2;
readings[2] = hadc1.Instance->JDR3;
readings[3] = hadc1.Instance->JDR4;
readings[4] = hadc2.Instance->JDR1;
readings[5] = hadc2.Instance->JDR2;
readings[6] = hadc2.Instance->JDR3;
readings[7] = hadc2.Instance->JDR4;
uint8_t minID = 0, maxID = 0;
for (int i = 0; i < 8; i++) {
if (readings[i] < readings[minID])
minID = i;
else if (readings[i] > readings[maxID])
maxID = i;
}
for (int i = 0; i < 8; i++) {
if (i != maxID)
sum += readings[i];
}
sum += readings[minID]; //Duplicate the min to make up for the missing max value
return sum; // 8x over sample
}
/*
* Loopup table for the tip calibration values for
* the gain of the tip's
* This can be found by line of best fit of TipRaw on X, and TipTemp-handle on
* Y. Then take the m term * 10000
* */
uint16_t lookupTipDefaultCalValue(enum TipType tipID) {
#ifdef MODEL_TS100
switch (tipID) {
case TS_D24:
return 141;
break;
case TS_BC2:
return (133 + 129) / 2;
break;
case TS_C1:
return 133;
break;
case TS_B2:
return 133;
default:
return 132; // make this the average of all
break;
}
#else
switch (tipID) {
case TS_D25:
return 154;
break;
case TS_B02:
return 154;
break;
default:
return 154; // make this the average of all
break;
}
#endif
}
//2 second filter (ADC is PID_TIM_HZ Hz)
history<uint16_t, PID_TIM_HZ*4> rawTempFilter = { { 0 }, 0, 0 };
uint16_t getTipRawTemp(uint8_t refresh) {
if (refresh) {
uint16_t lastSample = getTipInstantTemperature();
rawTempFilter.update(lastSample);
return lastSample;
} else {
return rawTempFilter.average();
}
}
uint16_t getInputVoltageX10(uint16_t divisor, uint8_t sample) {
// ADC maximum is 32767 == 3.3V at input == 28.05V at VIN
// Therefore we can divide down from there
// Multiplying ADC max by 4 for additional calibration options,
// ideal term is 467
#define BATTFILTERDEPTH 32
static uint8_t preFillneeded = 10;
static uint32_t samples[BATTFILTERDEPTH];
static uint8_t index = 0;
if (preFillneeded) {
for (uint8_t i = 0; i < BATTFILTERDEPTH; i++)
samples[i] = getADC(1);
preFillneeded--;
}
if (sample) {
samples[index] = getADC(1);
index = (index + 1) % BATTFILTERDEPTH;
}
uint32_t sum = 0;
for (uint8_t i = 0; i < BATTFILTERDEPTH; i++)
sum += samples[i];
sum /= BATTFILTERDEPTH;
return sum * 4 / divisor;
}
#ifdef MODEL_TS80
uint8_t QCMode = 0;
uint8_t QCTries = 0;
void seekQC(int16_t Vx10, uint16_t divisor) {
if (QCMode == 5)
startQC(divisor);
if (QCMode == 0)
return; // NOT connected to a QC Charger
if (Vx10 < 45)
return;
if (Vx10 > 130)
Vx10 = 130; //Cap max value at 13V
// Seek the QC to the Voltage given if this adapter supports continuous mode
// try and step towards the wanted value
// 1. Measure current voltage
int16_t vStart = getInputVoltageX10(divisor, 0);
int difference = Vx10 - vStart;
// 2. calculate ideal steps (0.2V changes)
int steps = difference / 2;
if (QCMode == 3) {
while (steps < 0) {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET); //D+0.6
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); //D-3.3V
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET); // D-3.3Vs
vTaskDelay(3);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); //-0.6V
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_Delay(1);
steps++;
}
while (steps > 0) {
// step once up
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
vTaskDelay(3);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
HAL_Delay(1);
steps--;
}
}
// Re-measure
/* Disabled due to nothing to test and code space of around 1k*/
#ifdef QC2_ROUND_DOWN
steps = vStart - getInputVoltageX10(195);
if (steps < 0) steps = -steps;
if (steps > (difference / 2)) {
// No continuous mode, so QC2
QCMode = 2;
// Goto nearest
if (Vx10 > 10.5) {
// request 12V
// D- = 0.6V, D+ = 0.6V
// Clamp PB3
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);// pull down D+
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
} else {
// request 9V
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
}
}
#endif
}
// Must be called after FreeRToS Starts
void startQC(uint16_t divisor) {
// Pre check that the input could be >5V already, and if so, dont both
// negotiating as someone is feeding in hv
uint16_t vin = getInputVoltageX10(divisor, 1);
if (vin > 100) {
QCMode = 1; // ALready at ~12V
return;
}
GPIO_InitTypeDef GPIO_InitStruct;
// Tries to negotiate QC for 9V
// This is a multiple step process.
// 1. Set around 0.6V on D+ for 1.25 Seconds or so
// 2. After this It should un-short D+->D- and instead add a 20k pulldown on
// D-
// 3. Now set D+ to 3.3V and D- to 0.6V to request 9V
// OR both at 0.6V for 12V request (if the adapter can do it).
// If 12V is implimented then should fallback to 9V after validation
// Step 1. We want to pull D+ to 0.6V
// Pull PB3 donwn to ground
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);// pull low to put 0.6V on D+
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);// pull low to put 0.6V on D+
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_14 | GPIO_PIN_13;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// Delay 1.25 seconds
uint8_t enteredQC = 0;
for (uint16_t i = 0; i < 130 && enteredQC == 0; i++) {
// HAL_Delay(10);
vTaskDelay(1);
}
// Check if D- is low to spot a QC charger
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == GPIO_PIN_RESET)
enteredQC = 1;
if (enteredQC) {
// We have a QC capable charger
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_8;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
// Wait for frontend ADC to stabilise
QCMode = 4;
for (uint8_t i = 0; i < 10; i++) {
if (getInputVoltageX10(divisor, 1) > 80) {
// yay we have at least QC2.0 or QC3.0
QCMode = 3; // We have at least QC2, pray for 3
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
return;
}
vTaskDelay(10); // 100mS
}
QCMode = 5;
QCTries++;
if (QCTries > 10) // 10 goes to get it going
QCMode = 0;
} else {
// no QC
QCMode = 0;
}
if (QCTries > 10)
QCMode = 0;
}
// Get tip resistance in milliohms
uint32_t calculateTipR() {
static uint32_t lastRes = 0;
if (lastRes)
return lastRes;
// We inject a small current into the front end of the iron,
// By measuring the Vdrop over the tip we can calculate the resistance
// Turn PA0 into an output and drive high to inject (3.3V-0.6)/(6K8+Rtip)
// current PA0->Diode -> 6K8 -> Tip -> GND So the op-amp will amplify the
// small signal across the tip and convert this into an easily read voltage
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // Set low first
setTipPWM(0);
vTaskDelay(1);
uint32_t offReading = getTipRawTemp(1);
for (uint8_t i = 0; i < 49; i++) {
vTaskDelay(1); // delay to allow it to stabilize
HAL_IWDG_Refresh(&hiwdg);
offReading += getTipRawTemp(1);
}
// Turn on
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // Set hgih
vTaskDelay(1); // delay to allow it too stabilize
uint32_t onReading = getTipInstantTemperature();
for (uint8_t i = 0; i < 49; i++) {
vTaskDelay(1); // delay to allow it to stabilize
HAL_IWDG_Refresh(&hiwdg);
onReading += getTipRawTemp(1);
}
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // Turn the output off finally
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
uint32_t difference = onReading - offReading;
// V = IR, therefore I = V/R
// We can divide this reading by a known "gain" to get the resulting
// resistance This was determined emperically This tip is 4.688444162 ohms,
// 4688 milliohms (Measured using 4 terminal measurement) 25x oversampling
// reads this as around 47490 Almost perfectly 10x the milliohms value This
// will drift massively with tip temp However we really only need 10x ohms
lastRes = (difference / 21) + 1; // ceil
return lastRes;
}
static unsigned int sqrt32(unsigned long n) {
unsigned int c = 0x8000;
unsigned int g = 0x8000;
for (;;) {
if (g * g > n)
g ^= c;
c >>= 1;
if (c == 0)
return g;
g |= c;
}
}
int16_t calculateMaxVoltage(uint8_t useHP) {
// This measures the tip resistance, then it calculates the appropriate
// voltage To stay under ~18W. Mosfet is "9A", so no issues there
// QC3.0 supports up to 18W, which is 2A @9V and 1.5A @12V
uint32_t milliOhms = calculateTipR();
// Check no tip
if (milliOhms > 10000)
return -1;
//Because of tolerance, if a user has asked for the higher power mode, then just goto 12V and call it a day
if (useHP)
return 120;
//
// V = sqrt(18W*R)
// Convert this to sqrt(18W)*sqrt(milli ohms)*sqrt(1/1000)
uint32_t Vx = sqrt32(milliOhms);
if (useHP)
Vx *= 1549; //sqrt(24)*sqrt(1/1000)*10000
else
Vx *= 1342; // sqrt(18) * sqrt(1/1000)*10000
// Round to nearest 200mV,
// So divide by 100 to start, to get in Vxx
Vx /= 100;
if (Vx % 10 >= 5)
Vx += 10;
Vx /= 10;
// Round to nearest increment of 2
if (Vx % 2 == 1)
Vx++;
//Because of how bad the tolerance is on detecting the tip resistance is
//Its more functional to bin this
if (Vx < 90)
Vx = 90;
else if (Vx >= 105)
Vx = 120;
return Vx;
}
#endif
volatile uint8_t pendingPWM = 0;
void setTipPWM(uint8_t pulse) {
PWMSafetyTimer = 10; // This is decremented in the handler for PWM so that the tip pwm is
// disabled if the PID task is not scheduled often enough.
pendingPWM = pulse;
}
// These are called by the HAL after the corresponding events from the system
// timers.
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
// Period has elapsed
if (htim->Instance == TIM2) {
// we want to turn on the output again
PWMSafetyTimer--;
// We decrement this safety value so that lockups in the
// scheduler will not cause the PWM to become locked in an
// active driving state.
// While we could assume this could never happen, its a small price for
// increased safety
htim2.Instance->CCR4 = pendingPWM;
if (htim2.Instance->CCR4 && PWMSafetyTimer) {
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
} else {
HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_1);
}
} else if (htim->Instance == TIM1) {
// STM uses this for internal functions as a counter for timeouts
HAL_IncTick();
}
}
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) {
// This was a when the PWM for the output has timed out
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4) {
HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_1);
}
}

View File

@@ -0,0 +1,376 @@
// By Ben V. Brown - V2.0 of the TS100 firmware
#include <MMA8652FC.hpp>
#include <gui.hpp>
#include <main.hpp>
#include "LIS2DH12.hpp"
#include <history.hpp>
#include <power.hpp>
#include "Settings.h"
#include "Translation.h"
#include "cmsis_os.h"
#include "stdlib.h"
#include "stm32f1xx_hal.h"
#include "string.h"
uint8_t PCBVersion = 0;
// File local variables
uint32_t currentlyActiveTemperatureTarget = 0;
uint32_t lastMovementTime = 0;
int16_t idealQCVoltage = 0;
// FreeRTOS variables
osThreadId GUITaskHandle;
static const size_t GUITaskStackSize = 1024/4;
uint32_t GUITaskBuffer[GUITaskStackSize];
osStaticThreadDef_t GUITaskControlBlock;
osThreadId PIDTaskHandle;
static const size_t PIDTaskStackSize =512 / 4;
uint32_t PIDTaskBuffer[PIDTaskStackSize];
osStaticThreadDef_t PIDTaskControlBlock;
osThreadId MOVTaskHandle;
static const size_t MOVTaskStackSize = 512/4;
uint32_t MOVTaskBuffer[MOVTaskStackSize];
osStaticThreadDef_t MOVTaskControlBlock;
static TaskHandle_t pidTaskNotification = NULL;
void startGUITask(void const *argument);
void startPIDTask(void const *argument);
void startMOVTask(void const *argument);
// End FreeRTOS
// Main sets up the hardware then hands over to the FreeRTOS kernel
int main(void) {
/* Reset of all peripherals, Initializes the Flash interface and the Systick.
*/
HAL_Init();
Setup_HAL(); // Setup all the HAL objects
HAL_IWDG_Refresh(&hiwdg);
setTipMilliWatts(0); // force tip off
FRToSI2C::init(&hi2c1);
OLED::initialize(); // start up the LCD
OLED::setFont(0); // default to bigger font
// Testing for which accelerometer is mounted
uint8_t buffer[1];
HAL_IWDG_Refresh(&hiwdg);
if (HAL_I2C_Mem_Read(&hi2c1, 29 << 1, 0x0F, I2C_MEMADD_SIZE_8BIT, buffer, 1,
1000) == HAL_OK) {
PCBVersion = 1;
MMA8652FC::initalize(); // this sets up the I2C registers
} else if (HAL_I2C_Mem_Read(&hi2c1, 25 << 1, 0x0F, I2C_MEMADD_SIZE_8BIT,
buffer, 1, 1000) == HAL_OK) {
PCBVersion = 2;
// Setup the ST Accelerometer
LIS2DH12::initalize(); // startup the accelerometer
} else {
PCBVersion = 3;
systemSettings.SleepTime = 0;
systemSettings.ShutdownTime = 0; // No accel -> disable sleep
systemSettings.sensitivity = 0;
}
HAL_IWDG_Refresh(&hiwdg);
restoreSettings(); // load the settings from flash
setCalibrationOffset(systemSettings.CalibrationOffset);
setTipType((enum TipType) systemSettings.tipType,
systemSettings.customTipGain); // apply tip type selection
HAL_IWDG_Refresh(&hiwdg);
/* Create the thread(s) */
/* definition and creation of GUITask */
osThreadStaticDef(GUITask, startGUITask, osPriorityBelowNormal, 0,
GUITaskStackSize, GUITaskBuffer, &GUITaskControlBlock);
GUITaskHandle = osThreadCreate(osThread(GUITask), NULL);
/* definition and creation of PIDTask */
osThreadStaticDef(PIDTask, startPIDTask, osPriorityRealtime, 0,
PIDTaskStackSize, PIDTaskBuffer, &PIDTaskControlBlock);
PIDTaskHandle = osThreadCreate(osThread(PIDTask), NULL);
if (PCBVersion < 3) {
osThreadStaticDef(MOVTask, startMOVTask, osPriorityNormal, 0,
MOVTaskStackSize, MOVTaskBuffer, &MOVTaskControlBlock);
MOVTaskHandle = osThreadCreate(osThread(MOVTask), NULL);
}
/* Start scheduler */
osKernelStart();
/* We should never get here as control is now taken by the scheduler */
while (1) {
}
}
/* StartPIDTask function */
void startPIDTask(void const *argument __unused) {
/*
* We take the current tip temperature & evaluate the next step for the tip
* control PWM.
*/
setTipMilliWatts(0); // disable the output driver if the output is set to be off
#ifdef MODEL_TS80
idealQCVoltage = calculateMaxVoltage(systemSettings.cutoutSetting);
#endif
uint8_t rawC = ctoTipMeasurement(101) - ctoTipMeasurement(100); // 1*C change in raw.
#ifdef MODEL_TS80
//Set power management code to the tip resistance in ohms * 10
setupPower(calculateTipR() / 100);
TickType_t lastPowerPulse = 0;
#else
setupPower(85);
#endif
history<int32_t> tempError = { { 0 }, 0, 0 };
currentlyActiveTemperatureTarget = 0; // Force start with no output (off). If in sleep / soldering this will
// be over-ridden rapidly
pidTaskNotification = xTaskGetCurrentTaskHandle();
for (;;) {
if (ulTaskNotifyTake(pdTRUE, 2000)) {
// This is a call to block this thread until the ADC does its samples
uint16_t rawTemp = getTipRawTemp(1); // get instantaneous reading
if (currentlyActiveTemperatureTarget) {
// Cap the max set point to 450C
if (currentlyActiveTemperatureTarget > ctoTipMeasurement(450)) {
//Maximum allowed output
currentlyActiveTemperatureTarget = ctoTipMeasurement(450);
} else if (currentlyActiveTemperatureTarget > 32400) {
//Cap to max adc reading
currentlyActiveTemperatureTarget = 32400;
}
// As we get close to our target, temp noise causes the system
// to be unstable. Use a rolling average to dampen it.
// We overshoot by roughly 1/2 of 1 degree Fahrenheit.
// This helps stabilize the display.
int32_t tError = currentlyActiveTemperatureTarget - rawTemp
+ (rawC / 4);
tError = tError > INT16_MAX ? INT16_MAX : tError;
tError = tError < INT16_MIN ? INT16_MIN : tError;
tempError.update(tError);
// Now for the PID!
int32_t milliWattsOut = 0;
// P term - total power needed to hit target temp next cycle.
// thermal mass = 1690 milliJ/*C for my tip.
// = Watts*Seconds to raise Temp from room temp to +100*C, divided by 100*C.
// we divide milliWattsNeeded by 20 to let the I term dominate near the set point.
// This is necessary because of the temp noise and thermal lag in the system.
// Once we have feed-forward temp estimation we should be able to better tune this.
#ifdef MODEL_TS100
const uint16_t mass = 2020 / 20; // divide here so division is compile-time.
#endif
#ifdef MODEL_TS80
const uint16_t mass = 2020 / 50;
#endif
int32_t milliWattsNeeded = tempToMilliWatts(tempError.average(),
mass, rawC);
// note that milliWattsNeeded is sometimes negative, this counters overshoot
// from I term's inertia.
milliWattsOut += milliWattsNeeded;
// I term - energy needed to compensate for heat loss.
// We track energy put into the system over some window.
// Assuming the temp is stable, energy in = energy transfered.
// (If it isn't, P will dominate).
milliWattsOut += milliWattHistory.average();
// D term - use sudden temp change to counter fast cooling/heating.
// In practice, this provides an early boost if temp is dropping
// and counters extra power if the iron is no longer losing temp.
// basically: temp - lastTemp
// Unfortunately, our temp signal is too noisy to really help.
setTipMilliWatts(milliWattsOut);
} else {
#ifdef MODEL_TS80
//If its a TS80, we want to have the option of using an occasional pulse to keep the power bank on
// This is purely guesswork :'( as everyone implements stuff differently
if (xTaskGetTickCount() - lastPowerPulse < 10) {
// for the first 100mS turn on for a bit
setTipMilliWatts(5000); // typically its around 5W to hold the current temp, so this wont raise temp much
} else
setTipMilliWatts(0);
//Then wait until the next 0.5 seconds
if (xTaskGetTickCount() - lastPowerPulse > 50) {
lastPowerPulse = xTaskGetTickCount();
}
#else
setTipMilliWatts(0);
#endif
}
HAL_IWDG_Refresh(&hiwdg);
} else {
asm("bkpt");
//ADC interrupt timeout
setTipMilliWatts(0);
setTipPWM(0);
}
}
}
#define MOVFilter 8
void startMOVTask(void const *argument __unused) {
OLED::setRotation(true);
#ifdef MODEL_TS80
startQC(systemSettings.voltageDiv);
while (pidTaskNotification == 0)
osDelay(30); // To ensure we return after idealQCVoltage/tip resistance
seekQC(idealQCVoltage, systemSettings.voltageDiv); // this will move the QC output to the preferred voltage to start with
#else
osDelay(250); // wait for accelerometer to stabilize
#endif
OLED::setRotation(systemSettings.OrientationMode & 1);
lastMovementTime = 0;
int16_t datax[MOVFilter] = { 0 };
int16_t datay[MOVFilter] = { 0 };
int16_t dataz[MOVFilter] = { 0 };
uint8_t currentPointer = 0;
int16_t tx = 0, ty = 0, tz = 0;
int32_t avgx = 0, avgy = 0, avgz = 0;
if (systemSettings.sensitivity > 9)
systemSettings.sensitivity = 9;
#if ACCELDEBUG
uint32_t max = 0;
#endif
Orientation rotation = ORIENTATION_FLAT;
for (;;) {
int32_t threshold = 1500 + (9 * 200);
threshold -= systemSettings.sensitivity * 200; // 200 is the step size
if (PCBVersion == 2) {
LIS2DH12::getAxisReadings(tx, ty, tz);
rotation = LIS2DH12::getOrientation();
} else if (PCBVersion == 1) {
MMA8652FC::getAxisReadings(tx, ty, tz);
rotation = MMA8652FC::getOrientation();
}
if (systemSettings.OrientationMode == 2) {
if (rotation != ORIENTATION_FLAT) {
OLED::setRotation(rotation == ORIENTATION_LEFT_HAND); // link the data through
}
}
datax[currentPointer] = (int32_t) tx;
datay[currentPointer] = (int32_t) ty;
dataz[currentPointer] = (int32_t) tz;
currentPointer = (currentPointer + 1) % MOVFilter;
avgx = avgy = avgz = 0;
// calculate averages
for (uint8_t i = 0; i < MOVFilter; i++) {
avgx += datax[i];
avgy += datay[i];
avgz += dataz[i];
}
avgx /= MOVFilter;
avgy /= MOVFilter;
avgz /= MOVFilter;
// Sum the deltas
int32_t error = (abs(avgx - tx) + abs(avgy - ty) + abs(avgz - tz));
// So now we have averages, we want to look if these are different by more
// than the threshold
// If error has occurred then we update the tick timer
if (error > threshold) {
lastMovementTime = xTaskGetTickCount();
}
osDelay(100); // Slow down update rate
#ifdef MODEL_TS80
if (currentlyActiveTemperatureTarget) {
seekQC(idealQCVoltage, systemSettings.voltageDiv); // Run the QC seek again to try and compensate for cable V drop
}
#endif
}
}
#define FLASH_LOGOADDR \
(0x8000000 | 0xF800) /*second last page of flash set aside for logo image*/
bool showBootLogoIfavailable() {
// check if the header is there (0xAA,0x55,0xF0,0x0D)
// If so display logo
// TODO REDUCE STACK ON THIS ONE, USE DRAWING IN THE READ LOOP
uint16_t temp[98];
for (uint8_t i = 0; i < (98); i++) {
temp[i] = *(uint16_t *) (FLASH_LOGOADDR + (i * 2));
}
uint8_t temp8[98 * 2];
for (uint8_t i = 0; i < 98; i++) {
temp8[i * 2] = temp[i] >> 8;
temp8[i * 2 + 1] = temp[i] & 0xFF;
}
if (temp8[0] != 0xAA)
return false;
if (temp8[1] != 0x55)
return false;
if (temp8[2] != 0xF0)
return false;
if (temp8[3] != 0x0D)
return false;
OLED::drawArea(0, 0, 96, 16, (uint8_t *) (temp8 + 4));
OLED::refresh();
return true;
}
/*
* Catch the IRQ that says that the conversion is done on the temperature
* readings coming in Once these have come in we can unblock the PID so that it
* runs again
*/
void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef *hadc) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (hadc == &hadc1) {
if (pidTaskNotification) {
vTaskNotifyGiveFromISR(pidTaskNotification,
&xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
}
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c __unused) {
FRToSI2C::CpltCallback();
}
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c __unused) {
FRToSI2C::CpltCallback();
}
void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c __unused) {
FRToSI2C::CpltCallback();
}
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c __unused) {
asm("bkpt");
FRToSI2C::CpltCallback();
}
void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c __unused) {
//asm("bkpt");
FRToSI2C::CpltCallback();
}
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c __unused) {
FRToSI2C::CpltCallback();
}
void vApplicationStackOverflowHook(xTaskHandle *pxTask __unused,
signed portCHAR *pcTaskName __unused) {
asm("bkpt");
// We dont have a good way to handle a stack overflow at this point in time
NVIC_SystemReset();
}

View File

@@ -0,0 +1,76 @@
/*
* power.cpp
*
* Created on: 28 Oct, 2018
* Authors: Ben V. Brown, David Hilton
*/
#include <power.hpp>
#include <Settings.h>
#include <hardware.h>
const uint16_t powerPWM = 255;
const uint16_t totalPWM = 255 + 17; //htim2.Init.Period, the full PWM cycle
history<uint32_t, oscillationPeriod> milliWattHistory = { { 0 }, 0, 0 };
int32_t tempToMilliWatts(int32_t rawTemp, uint8_t rawC) {
// mass is in milliJ/*C, rawC is raw per degree C
// returns milliWatts needed to raise/lower a mass by rawTemp
// degrees in one cycle.
int32_t milliJoules = tipMass*10 * (rawTemp / rawC);
return milliJoules;
}
void setTipMilliWatts(int32_t mw) {
//Enforce Max Watts Limiter # TODO
int32_t output = milliWattsToPWM(mw, systemSettings.voltageDiv , 1);
setTipPWM(output);
uint32_t actualMilliWatts = PWMToMilliWatts(output,
systemSettings.voltageDiv , 0);
milliWattHistory.update(actualMilliWatts);
}
int32_t availableW10(uint8_t divisor, uint8_t sample) {
//P = V^2 / R, v*v = v^2 * 100
// R = R*10
// P therefore is in V^2*100/R*10 = W*10.
int32_t v = getInputVoltageX10(divisor, sample); // 100 = 10v
int32_t availableWattsX10 = (v * v) / tipResistance;
//However, 100% duty cycle is not possible as there is a dead time while the ADC takes a reading
//Therefore need to scale available milliwats by this
// avMw=(AvMw*powerPWM)/totalPWM.
availableWattsX10 = availableWattsX10 * powerPWM;
availableWattsX10 /= totalPWM;
//availableMilliWattsX10 is now an accurate representation
return availableWattsX10;
}
uint8_t milliWattsToPWM(int32_t milliWatts, uint8_t divisor, uint8_t sample) {
// Scale input milliWatts to the pwm rate
if (milliWatts < 10) // no pint driving tip
return 0;
//Calculate desired milliwatts as a percentage of availableW10
int32_t pwm = (powerPWM * milliWatts) / availableW10(divisor, sample);
if (pwm > powerPWM) {
pwm = powerPWM; //constrain to max PWM counter, shouldnt be possible, but small cost for safety to avoid wraps
} else if (pwm < 0) { //cannot go negative
pwm = 0;
}
return pwm;
}
int32_t PWMToMilliWatts(uint8_t pwm, uint8_t divisor, uint8_t sample) {
int32_t maxMW = availableW10(divisor, sample); //Get the milliwatts for the max pwm period
//Then convert pwm into percentage of powerPWM to get the percentage of the max mw
int32_t res = (pwm * maxMW) / powerPWM;
if (res < 0)
res = 0;
return res;
}

View File

@@ -0,0 +1,136 @@
#include <hardware.h>
#include "stm32f1xx_hal.h"
#include "Setup.h"
/**
* Initializes the Global MSP.
*/
void HAL_MspInit(void) {
__HAL_RCC_AFIO_CLK_ENABLE()
;
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
/* System interrupt init*/
/* MemoryManagement_IRQn interrupt configuration */
HAL_NVIC_SetPriority(MemoryManagement_IRQn, 0, 0);
/* BusFault_IRQn interrupt configuration */
HAL_NVIC_SetPriority(BusFault_IRQn, 0, 0);
/* UsageFault_IRQn interrupt configuration */
HAL_NVIC_SetPriority(UsageFault_IRQn, 0, 0);
/* SVCall_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SVCall_IRQn, 0, 0);
/* DebugMonitor_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DebugMonitor_IRQn, 0, 0);
/* PendSV_IRQn interrupt configuration */
HAL_NVIC_SetPriority(PendSV_IRQn, 15, 0);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 15, 0);
}
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc) {
GPIO_InitTypeDef GPIO_InitStruct;
if (hadc->Instance == ADC1) {
__HAL_RCC_ADC1_CLK_ENABLE()
;
/* ADC1 DMA Init */
/* ADC1 Init */
hdma_adc1.Instance = DMA1_Channel1;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_VERY_HIGH;
HAL_DMA_Init(&hdma_adc1);
__HAL_LINKDMA(hadc, DMA_Handle, hdma_adc1);
/* ADC1 interrupt Init */
HAL_NVIC_SetPriority(ADC1_2_IRQn, 15, 0);
HAL_NVIC_EnableIRQ(ADC1_2_IRQn);
} else {
__HAL_RCC_ADC2_CLK_ENABLE()
;
/**ADC2 GPIO Configuration
PB0 ------> ADC2_IN8
PB1 ------> ADC2_IN9
*/
GPIO_InitStruct.Pin = TIP_TEMP_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* ADC2 interrupt Init */
HAL_NVIC_SetPriority(ADC1_2_IRQn, 15, 0);
HAL_NVIC_EnableIRQ(ADC1_2_IRQn);
}
}
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c) {
GPIO_InitTypeDef GPIO_InitStruct;
/**I2C1 GPIO Configuration
PB6 ------> I2C1_SCL
PB7 ------> I2C1_SDA
*/
GPIO_InitStruct.Pin = SCL_Pin | SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral clock enable */
__HAL_RCC_I2C1_CLK_ENABLE()
;
/* I2C1 DMA Init */
/* I2C1_RX Init */
hdma_i2c1_rx.Instance = DMA1_Channel7;
hdma_i2c1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_i2c1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2c1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2c1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_i2c1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_i2c1_rx.Init.Mode = DMA_NORMAL;
hdma_i2c1_rx.Init.Priority = DMA_PRIORITY_LOW;
HAL_DMA_Init(&hdma_i2c1_rx);
__HAL_LINKDMA(hi2c, hdmarx, hdma_i2c1_rx);
/* I2C1_TX Init */
hdma_i2c1_tx.Instance = DMA1_Channel6;
hdma_i2c1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_i2c1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2c1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2c1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_i2c1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_i2c1_tx.Init.Mode = DMA_NORMAL;
hdma_i2c1_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hdma_i2c1_tx);
__HAL_LINKDMA(hi2c, hdmatx, hdma_i2c1_tx);
/* I2C1 interrupt Init */
HAL_NVIC_SetPriority(I2C1_EV_IRQn, 15, 0);
HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
HAL_NVIC_SetPriority(I2C1_ER_IRQn, 15, 0);
HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
}
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base) {
if (htim_base->Instance == TIM3) {
/* Peripheral clock enable */
__HAL_RCC_TIM3_CLK_ENABLE()
;
} else if (htim_base->Instance == TIM2) {
/* Peripheral clock enable */
__HAL_RCC_TIM2_CLK_ENABLE()
;
}
}

View File

@@ -0,0 +1,158 @@
/**
******************************************************************************
* @file stm32f1xx_hal_timebase_TIM.c
* @brief HAL time base based on the hardware TIM.
******************************************************************************
* This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* Copyright (c) 2017 STMicroelectronics International N.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted, provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific written permission.
* 4. This software, including modifications and/or derivative works of this
* software, must execute solely and exclusively on microcontroller or
* microprocessor devices manufactured by or for STMicroelectronics.
* 5. Redistribution and use of this software other than as permitted under
* this license is void and will automatically terminate your rights under
* this license.
*
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#include "stm32f1xx_hal_tim.h"
/** @addtogroup STM32F7xx_HAL_Examples
* @{
*/
/** @addtogroup HAL_TimeBase
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim1;
uint32_t uwIncrementState = 0;
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
* @brief This function configures the TIM1 as a time base source.
* The time source is configured to have 1ms time base with a dedicated
* Tick interrupt priority.
* @note This function is called automatically at the beginning of program after
* reset by HAL_Init() or at any time when clock is configured, by HAL_RCC_ClockConfig().
* @param TickPriority: Tick interrupt priorty.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
RCC_ClkInitTypeDef clkconfig;
uint32_t uwTimclock = 0;
uint32_t uwPrescalerValue = 0;
uint32_t pFLatency;
/*Configure the TIM1 IRQ priority */
HAL_NVIC_SetPriority(TIM1_UP_IRQn, TickPriority ,0);
/* Enable the TIM1 global Interrupt */
HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
/* Enable TIM1 clock */
__HAL_RCC_TIM1_CLK_ENABLE();
/* Get clock configuration */
HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);
/* Compute TIM1 clock */
uwTimclock = HAL_RCC_GetPCLK2Freq();
/* Compute the prescaler value to have TIM1 counter clock equal to 1MHz */
uwPrescalerValue = (uint32_t) ((uwTimclock / 1000000) - 1);
/* Initialize TIM1 */
htim1.Instance = TIM1;
/* Initialize TIMx peripheral as follow:
+ Period = [(TIM1CLK/1000) - 1]. to have a (1/1000) s time base.
+ Prescaler = (uwTimclock/1000000 - 1) to have a 1MHz counter clock.
+ ClockDivision = 0
+ Counter direction = Up
*/
htim1.Init.Period = (1000000 / 1000) - 1;
htim1.Init.Prescaler = uwPrescalerValue;
htim1.Init.ClockDivision = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
if(HAL_TIM_Base_Init(&htim1) == HAL_OK)
{
/* Start the TIM time Base generation in interrupt mode */
return HAL_TIM_Base_Start_IT(&htim1);
}
/* Return function status */
return HAL_ERROR;
}
/**
* @brief Suspend Tick increment.
* @note Disable the tick increment by disabling TIM1 update interrupt.
* @param None
* @retval None
*/
void HAL_SuspendTick(void)
{
/* Disable TIM1 update Interrupt */
__HAL_TIM_DISABLE_IT(&htim1, TIM_IT_UPDATE);
}
/**
* @brief Resume Tick increment.
* @note Enable the tick increment by Enabling TIM1 update interrupt.
* @param None
* @retval None
*/
void HAL_ResumeTick(void)
{
/* Enable TIM1 Update interrupt */
__HAL_TIM_ENABLE_IT(&htim1, TIM_IT_UPDATE);
}
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,84 @@
// This is the stock standard STM interrupt file full of handlers
#include "stm32f1xx_hal.h"
#include "stm32f1xx.h"
#include "stm32f1xx_it.h"
#include "cmsis_os.h"
#include "Setup.h"
extern TIM_HandleTypeDef htim1; //used for the systick
/******************************************************************************/
/* Cortex-M3 Processor Interruption and Exception Handlers */
/******************************************************************************/
void NMI_Handler(void) {
}
//We have the assembly for a breakpoint trigger here to halt the system when a debugger is connected
// Hardfault handler, often a screwup in the code
void HardFault_Handler(void) {
}
// Memory management unit had an error
void MemManage_Handler(void) {
}
// Prefetcher or busfault occured
void BusFault_Handler(void) {
}
void UsageFault_Handler(void) {
}
void DebugMon_Handler(void) {
}
// Systick is used by FreeRTOS tick
void SysTick_Handler(void) {
osSystickHandler();
}
/******************************************************************************/
/* STM32F1xx Peripheral Interrupt Handlers */
/* Add here the Interrupt Handlers for the used peripherals. */
/* For the available peripheral interrupt handler names, */
/* please refer to the startup file. */
/******************************************************************************/
// DMA used to move the ADC readings into system ram
void DMA1_Channel1_IRQHandler(void) {
HAL_DMA_IRQHandler(&hdma_adc1);
}
//ADC interrupt used for DMA
void ADC1_2_IRQHandler(void) {
HAL_ADC_IRQHandler(&hadc1);
}
//Timer 1 has overflowed, used for HAL ticks
void TIM1_UP_IRQHandler(void) {
HAL_TIM_IRQHandler(&htim1);
}
//Timer 3 is used for the PWM output to the tip
void TIM3_IRQHandler(void) {
HAL_TIM_IRQHandler(&htim3);
}
//Timer 2 is used for co-ordination of PWM & ADC
void TIM2_IRQHandler(void) {
HAL_TIM_IRQHandler(&htim2);
}
void I2C1_EV_IRQHandler(void) {
HAL_I2C_EV_IRQHandler(&hi2c1);
}
void I2C1_ER_IRQHandler(void) {
HAL_I2C_ER_IRQHandler(&hi2c1);
}
void DMA1_Channel6_IRQHandler(void) {
HAL_DMA_IRQHandler(&hdma_i2c1_tx);
}
void DMA1_Channel7_IRQHandler(void) {
HAL_DMA_IRQHandler(&hdma_i2c1_rx);
}

View File

@@ -0,0 +1,317 @@
// This file was automatically generated by the STM Cube software
// And as such, is BSD licneced from STM
#include "stm32f1xx.h"
#if !defined (HSI_VALUE)
#define HSI_VALUE 8000000U /*!< Default value of the Internal oscillator in Hz.
This value can be provided and adapted by the user application. */
#endif /* HSI_VALUE */
/*!< Uncomment the following line if you need to use external SRAM */
#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)
/* #define DATA_IN_ExtSRAM */
#endif /* STM32F100xE || STM32F101xE || STM32F101xG || STM32F103xE || STM32F103xG */
#ifndef LOCAL_BUILD
#define VECT_TAB_OFFSET 0x00004000U /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
#else
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
#warning LOCAL_BUILD SETUP
#endif
//We offset this by 0x4000 to because of the bootloader
/*******************************************************************************
* Clock Definitions
*******************************************************************************/
#if defined(STM32F100xB) ||defined(STM32F100xE)
uint32_t SystemCoreClock = 24000000U; /*!< System Clock Frequency (Core Clock) */
#else /*!< HSI Selected as System Clock source */
uint32_t SystemCoreClock = 64000000U; /*!< System Clock Frequency (Core Clock) */
#endif
const uint8_t AHBPrescTable[16U] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
const uint8_t APBPrescTable[8U] = {0, 0, 0, 0, 1, 2, 3, 4};
/**
* @brief Setup the microcontroller system
* Initialize the Embedded Flash Interface, the PLL and update the
* SystemCoreClock variable.
* @note This function should be used only after reset.
* @param None
* @retval None
*/
void SystemInit (void)
{
/* Reset the RCC clock configuration to the default reset state(for debug purpose) */
/* Set HSION bit */
RCC->CR |= 0x00000001U;
/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#if !defined(STM32F105xC) && !defined(STM32F107xC)
RCC->CFGR &= 0xF8FF0000U;
#else
RCC->CFGR &= 0xF0FF0000U;
#endif /* STM32F105xC */
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= 0xFEF6FFFFU;
/* Reset HSEBYP bit */
RCC->CR &= 0xFFFBFFFFU;
/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
RCC->CFGR &= 0xFF80FFFFU;
#if defined(STM32F105xC) || defined(STM32F107xC)
/* Reset PLL2ON and PLL3ON bits */
RCC->CR &= 0xEBFFFFFFU;
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x00FF0000U;
/* Reset CFGR2 register */
RCC->CFGR2 = 0x00000000U;
#elif defined(STM32F100xB) || defined(STM32F100xE)
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x009F0000U;
/* Reset CFGR2 register */
RCC->CFGR2 = 0x00000000U;
#else
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x009F0000U;
#endif /* STM32F105xC */
#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)
#ifdef DATA_IN_ExtSRAM
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM */
#endif
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif
}
/**
* @brief Update SystemCoreClock variable according to Clock Register Values.
* The SystemCoreClock variable contains the core clock (HCLK), it can
* be used by the user application to setup the SysTick timer or configure
* other parameters.
*
* @note Each time the core clock (HCLK) changes, this function must be called
* to update SystemCoreClock variable value. Otherwise, any configuration
* based on this variable will be incorrect.
*
* @note - The system frequency computed by this function is not the real
* frequency in the chip. It is calculated based on the predefined
* constant and the selected clock source:
*
* - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
*
* - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
*
* - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
* or HSI_VALUE(*) multiplied by the PLL factors.
*
* (*) HSI_VALUE is a constant defined in stm32f1xx.h file (default value
* 8 MHz) but the real value may vary depending on the variations
* in voltage and temperature.
*
* (**) HSE_VALUE is a constant defined in stm32f1xx.h file (default value
* 8 MHz or 25 MHz, depending on the product used), user has to ensure
* that HSE_VALUE is same as the real frequency of the crystal used.
* Otherwise, this function may have wrong result.
*
* - The result of this function could be not correct when using fractional
* value for HSE crystal.
* @param None
* @retval None
*/
void SystemCoreClockUpdate (void)
{
uint32_t tmp = 0U, pllmull = 0U, pllsource = 0U;
#if defined(STM32F105xC) || defined(STM32F107xC)
uint32_t prediv1source = 0U, prediv1factor = 0U, prediv2factor = 0U, pll2mull = 0U;
#endif /* STM32F105xC */
#if defined(STM32F100xB) || defined(STM32F100xE)
uint32_t prediv1factor = 0U;
#endif /* STM32F100xB or STM32F100xE */
/* Get SYSCLK source -------------------------------------------------------*/
tmp = RCC->CFGR & RCC_CFGR_SWS;
switch (tmp)
{
case 0x00U: /* HSI used as system clock */
SystemCoreClock = HSI_VALUE;
break;
case 0x04U: /* HSE used as system clock */
SystemCoreClock = HSE_VALUE;
break;
case 0x08U: /* PLL used as system clock */
/* Get PLL clock source and multiplication factor ----------------------*/
pllmull = RCC->CFGR & RCC_CFGR_PLLMULL;
pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
#if !defined(STM32F105xC) && !defined(STM32F107xC)
pllmull = ( pllmull >> 18U) + 2U;
if (pllsource == 0x00U)
{
/* HSI oscillator clock divided by 2 selected as PLL clock entry */
SystemCoreClock = (HSI_VALUE >> 1U) * pllmull;
}
else
{
#if defined(STM32F100xB) || defined(STM32F100xE)
prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1U;
/* HSE oscillator clock selected as PREDIV1 clock entry */
SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;
#else
/* HSE selected as PLL clock entry */
if ((RCC->CFGR & RCC_CFGR_PLLXTPRE) != (uint32_t)RESET)
{/* HSE oscillator clock divided by 2 */
SystemCoreClock = (HSE_VALUE >> 1U) * pllmull;
}
else
{
SystemCoreClock = HSE_VALUE * pllmull;
}
#endif
}
#else
pllmull = pllmull >> 18U;
if (pllmull != 0x0DU)
{
pllmull += 2U;
}
else
{ /* PLL multiplication factor = PLL input clock * 6.5 */
pllmull = 13U / 2U;
}
if (pllsource == 0x00U)
{
/* HSI oscillator clock divided by 2 selected as PLL clock entry */
SystemCoreClock = (HSI_VALUE >> 1U) * pllmull;
}
else
{/* PREDIV1 selected as PLL clock entry */
/* Get PREDIV1 clock source and division factor */
prediv1source = RCC->CFGR2 & RCC_CFGR2_PREDIV1SRC;
prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1U;
if (prediv1source == 0U)
{
/* HSE oscillator clock selected as PREDIV1 clock entry */
SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;
}
else
{/* PLL2 clock selected as PREDIV1 clock entry */
/* Get PREDIV2 division factor and PLL2 multiplication factor */
prediv2factor = ((RCC->CFGR2 & RCC_CFGR2_PREDIV2) >> 4U) + 1U;
pll2mull = ((RCC->CFGR2 & RCC_CFGR2_PLL2MUL) >> 8U) + 2U;
SystemCoreClock = (((HSE_VALUE / prediv2factor) * pll2mull) / prediv1factor) * pllmull;
}
}
#endif /* STM32F105xC */
break;
default:
SystemCoreClock = HSI_VALUE;
break;
}
/* Compute HCLK clock frequency ----------------*/
/* Get HCLK prescaler */
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4U)];
/* HCLK clock frequency */
SystemCoreClock >>= tmp;
}
#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)
/**
* @brief Setup the external memory controller. Called in startup_stm32f1xx.s
* before jump to __main
* @param None
* @retval None
*/
#ifdef DATA_IN_ExtSRAM
/**
* @brief Setup the external memory controller.
* Called in startup_stm32f1xx_xx.s/.c before jump to main.
* This function configures the external SRAM mounted on STM3210E-EVAL
* board (STM32 High density devices). This SRAM will be used as program
* data memory (including heap and stack).
* @param None
* @retval None
*/
void SystemInit_ExtMemCtl(void)
{
__IO uint32_t tmpreg;
/*!< FSMC Bank1 NOR/SRAM3 is used for the STM3210E-EVAL, if another Bank is
required, then adjust the Register Addresses */
/* Enable FSMC clock */
RCC->AHBENR = 0x00000114U;
/* Delay after an RCC peripheral clock enabling */
tmpreg = READ_BIT(RCC->AHBENR, RCC_AHBENR_FSMCEN);
/* Enable GPIOD, GPIOE, GPIOF and GPIOG clocks */
RCC->APB2ENR = 0x000001E0U;
/* Delay after an RCC peripheral clock enabling */
tmpreg = READ_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPDEN);
(void)(tmpreg);
/* --------------- SRAM Data lines, NOE and NWE configuration ---------------*/
/*---------------- SRAM Address lines configuration -------------------------*/
/*---------------- NOE and NWE configuration --------------------------------*/
/*---------------- NE3 configuration ----------------------------------------*/
/*---------------- NBL0, NBL1 configuration ---------------------------------*/
GPIOD->CRL = 0x44BB44BBU;
GPIOD->CRH = 0xBBBBBBBBU;
GPIOE->CRL = 0xB44444BBU;
GPIOE->CRH = 0xBBBBBBBBU;
GPIOF->CRL = 0x44BBBBBBU;
GPIOF->CRH = 0xBBBB4444U;
GPIOG->CRL = 0x44BBBBBBU;
GPIOG->CRH = 0x444B4B44U;
/*---------------- FSMC Configuration ---------------------------------------*/
/*---------------- Enable FSMC Bank1_SRAM Bank ------------------------------*/
FSMC_Bank1->BTCR[4U] = 0x00001091U;
FSMC_Bank1->BTCR[5U] = 0x00110212U;
}
#endif /* DATA_IN_ExtSRAM */
#endif /* STM32F100xE || STM32F101xE || STM32F101xG || STM32F103xE || STM32F103xG */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/