Browse Source

synced code with multiwii 2.0 release

split uart2 initialization inside drv_uart. added receive data callback to use either with GPS or spektrum satellite
added spektrum satellite support, also freeing up 4 motor outputs for hexa/octo/camstab
configurable acc lpf and gyro lpf via cli
configurable (build-time) temperature lpf on baro. seems mostly useless.
fixed a nice boner bug in mag code which ended up multiplying magADC twice with magCal data.
fixed mpu3050 driver to allow configurable lpf, also broke other stuff in the process. considering moving this sort of stuff to "init" struct for sensor.
pwm driver rewritten to fully disable pwm/ppm inputs (such as using spektrum satellite case)
cleaned up double math in gps.c to use sinf/cosf etc
removed TRUSTED_ACCZ since its useless anyway
whitespace cleanup

git-svn-id: https://afrodevices.googlecode.com/svn/trunk/baseflight@130 7c89a4a9-59b9-e629-4cfe-3a2d53b20e61
master
timecop 13 years ago
parent
commit
96829b7306
  1. 132
      baseflight.uvopt
  2. 10
      baseflight.uvproj
  3. 4958
      obj/baseflight.hex
  4. 11
      src/board.h
  5. 24
      src/cli.c
  6. 6
      src/config.c
  7. 6
      src/drv_adxl345.c
  8. 14
      src/drv_bmp085.c
  9. 21
      src/drv_hmc5883l.c
  10. 31
      src/drv_mpu3050.c
  11. 1
      src/drv_mpu3050.h
  12. 126
      src/drv_pwm.c
  13. 2
      src/drv_pwm.h
  14. 60
      src/drv_uart.c
  15. 1
      src/drv_uart.h
  16. 57
      src/gps.c
  17. 93
      src/imu.c
  18. 22
      src/main.c
  19. 8
      src/mixer.c
  20. 101
      src/mw.c
  21. 11
      src/mw.h
  22. 30
      src/sensors.c
  23. 90
      src/spektrum.c

132
baseflight.uvopt

@ -73,7 +73,7 @@
<OPTFL> <OPTFL>
<tvExp>1</tvExp> <tvExp>1</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<IsCurrentTarget>1</IsCurrentTarget>
<IsCurrentTarget>0</IsCurrentTarget>
</OPTFL> </OPTFL>
<CpuCode>255</CpuCode> <CpuCode>255</CpuCode>
<Books> <Books>
@ -317,7 +317,7 @@
<OPTFL> <OPTFL>
<tvExp>1</tvExp> <tvExp>1</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<IsCurrentTarget>0</IsCurrentTarget>
<IsCurrentTarget>1</IsCurrentTarget>
</OPTFL> </OPTFL>
<CpuCode>255</CpuCode> <CpuCode>255</CpuCode>
<Books> <Books>
@ -383,7 +383,7 @@
<SetRegEntry> <SetRegEntry>
<Number>0</Number> <Number>0</Number>
<Key>DLGUARM</Key> <Key>DLGUARM</Key>
<Name>(106=-1,-1,-1,-1,0)(107=-1,-1,-1,-1,0)</Name>
<Name>(105=-1,-1,-1,-1,0)(106=-1,-1,-1,-1,0)(107=-1,-1,-1,-1,0)</Name>
</SetRegEntry> </SetRegEntry>
<SetRegEntry> <SetRegEntry>
<Number>0</Number> <Number>0</Number>
@ -400,9 +400,9 @@
<Bp> <Bp>
<Number>0</Number> <Number>0</Number>
<Type>0</Type> <Type>0</Type>
<LineNumber>254</LineNumber>
<LineNumber>71</LineNumber>
<EnabledFlag>1</EnabledFlag> <EnabledFlag>1</EnabledFlag>
<Address>134227724</Address>
<Address>134232388</Address>
<ByteObject>0</ByteObject> <ByteObject>0</ByteObject>
<ManyObjects>0</ManyObjects> <ManyObjects>0</ManyObjects>
<SizeOfObject>0</SizeOfObject> <SizeOfObject>0</SizeOfObject>
@ -410,7 +410,7 @@
<BreakIfRCount>1</BreakIfRCount> <BreakIfRCount>1</BreakIfRCount>
<Filename></Filename> <Filename></Filename>
<ExecCommand></ExecCommand> <ExecCommand></ExecCommand>
<Expression>\\baseflight\drv_bmp085.c\254</Expression>
<Expression>\\baseflight\src/spektrum.c\71</Expression>
</Bp> </Bp>
</Breakpoint> </Breakpoint>
<WatchWindow1> <WatchWindow1>
@ -469,6 +469,12 @@
<WinNumber>1</WinNumber> <WinNumber>1</WinNumber>
<ItemText>rawMagADC,0x0A</ItemText> <ItemText>rawMagADC,0x0A</ItemText>
</Ww> </Ww>
<Ww>
<count>11</count>
<WinNumber>1</WinNumber>
<ItemText>spekChannelData
</ItemText>
</Ww>
</WatchWindow1> </WatchWindow1>
<MemoryWindow1> <MemoryWindow1>
<Mm> <Mm>
@ -526,10 +532,10 @@
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>37</ColumnNumber>
<ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>523</TopLine>
<CurrentLine>523</CurrentLine>
<TopLine>1</TopLine>
<CurrentLine>1</CurrentLine>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>.\src\cli.c</PathWithFileName> <PathWithFileName>.\src\cli.c</PathWithFileName>
<FilenameWithoutPath>cli.c</FilenameWithoutPath> <FilenameWithoutPath>cli.c</FilenameWithoutPath>
@ -540,10 +546,10 @@
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>20</ColumnNumber>
<ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>149</TopLine>
<CurrentLine>162</CurrentLine>
<TopLine>102</TopLine>
<CurrentLine>125</CurrentLine>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>.\src\config.c</PathWithFileName> <PathWithFileName>.\src\config.c</PathWithFileName>
<FilenameWithoutPath>config.c</FilenameWithoutPath> <FilenameWithoutPath>config.c</FilenameWithoutPath>
@ -556,8 +562,8 @@
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>0</ColumnNumber> <ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>50</TopLine>
<CurrentLine>62</CurrentLine>
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>.\src\imu.c</PathWithFileName> <PathWithFileName>.\src\imu.c</PathWithFileName>
<FilenameWithoutPath>imu.c</FilenameWithoutPath> <FilenameWithoutPath>imu.c</FilenameWithoutPath>
@ -568,10 +574,10 @@
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>43</ColumnNumber>
<ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>35</TopLine>
<CurrentLine>51</CurrentLine>
<TopLine>43</TopLine>
<CurrentLine>50</CurrentLine>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>.\src\main.c</PathWithFileName> <PathWithFileName>.\src\main.c</PathWithFileName>
<FilenameWithoutPath>main.c</FilenameWithoutPath> <FilenameWithoutPath>main.c</FilenameWithoutPath>
@ -582,10 +588,10 @@
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>0</ColumnNumber>
<ColumnNumber>8</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>284</TopLine>
<CurrentLine>302</CurrentLine>
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>.\src\mixer.c</PathWithFileName> <PathWithFileName>.\src\mixer.c</PathWithFileName>
<FilenameWithoutPath>mixer.c</FilenameWithoutPath> <FilenameWithoutPath>mixer.c</FilenameWithoutPath>
@ -596,10 +602,10 @@
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>21</ColumnNumber>
<ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>560</TopLine>
<CurrentLine>587</CurrentLine>
<TopLine>15</TopLine>
<CurrentLine>26</CurrentLine>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>.\src\mw.c</PathWithFileName> <PathWithFileName>.\src\mw.c</PathWithFileName>
<FilenameWithoutPath>mw.c</FilenameWithoutPath> <FilenameWithoutPath>mw.c</FilenameWithoutPath>
@ -610,10 +616,10 @@
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>31</ColumnNumber>
<ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>281</TopLine>
<CurrentLine>299</CurrentLine>
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>.\src\sensors.c</PathWithFileName> <PathWithFileName>.\src\sensors.c</PathWithFileName>
<FilenameWithoutPath>sensors.c</FilenameWithoutPath> <FilenameWithoutPath>sensors.c</FilenameWithoutPath>
@ -626,8 +632,8 @@
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>0</ColumnNumber> <ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>205</TopLine>
<CurrentLine>209</CurrentLine>
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>.\src\serial.c</PathWithFileName> <PathWithFileName>.\src\serial.c</PathWithFileName>
<FilenameWithoutPath>serial.c</FilenameWithoutPath> <FilenameWithoutPath>serial.c</FilenameWithoutPath>
@ -638,10 +644,10 @@
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>18</ColumnNumber>
<ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>1</TopLine>
<CurrentLine>20</CurrentLine>
<TopLine>19</TopLine>
<CurrentLine>43</CurrentLine>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>.\src\board.h</PathWithFileName> <PathWithFileName>.\src\board.h</PathWithFileName>
<FilenameWithoutPath>board.h</FilenameWithoutPath> <FilenameWithoutPath>board.h</FilenameWithoutPath>
@ -654,8 +660,8 @@
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>0</ColumnNumber> <ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>248</TopLine>
<CurrentLine>280</CurrentLine>
<TopLine>252</TopLine>
<CurrentLine>288</CurrentLine>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>.\src\mw.h</PathWithFileName> <PathWithFileName>.\src\mw.h</PathWithFileName>
<FilenameWithoutPath>mw.h</FilenameWithoutPath> <FilenameWithoutPath>mw.h</FilenameWithoutPath>
@ -666,19 +672,33 @@
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>1</ColumnNumber>
<ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>35</TopLine>
<CurrentLine>71</CurrentLine>
<TopLine>1</TopLine>
<CurrentLine>4</CurrentLine>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>.\src\gps.c</PathWithFileName> <PathWithFileName>.\src\gps.c</PathWithFileName>
<FilenameWithoutPath>gps.c</FilenameWithoutPath> <FilenameWithoutPath>gps.c</FilenameWithoutPath>
</File> </File>
<File>
<GroupNumber>1</GroupNumber>
<FileNumber>0</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
<ColumnNumber>14</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg>
<TopLine>53</TopLine>
<CurrentLine>71</CurrentLine>
<bDave2>0</bDave2>
<PathWithFileName>.\src\spektrum.c</PathWithFileName>
<FilenameWithoutPath>spektrum.c</FilenameWithoutPath>
</File>
</Group> </Group>
<Group> <Group>
<GroupName>Drivers</GroupName> <GroupName>Drivers</GroupName>
<tvExp>1</tvExp>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel> <cbSel>0</cbSel>
<File> <File>
@ -701,7 +721,7 @@
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>65</ColumnNumber>
<ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>0</TopLine> <TopLine>0</TopLine>
<CurrentLine>0</CurrentLine> <CurrentLine>0</CurrentLine>
@ -729,10 +749,10 @@
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>42</ColumnNumber>
<ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>1</TopLine>
<CurrentLine>29</CurrentLine>
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>.\src\drv_hmc5883l.c</PathWithFileName> <PathWithFileName>.\src\drv_hmc5883l.c</PathWithFileName>
<FilenameWithoutPath>drv_hmc5883l.c</FilenameWithoutPath> <FilenameWithoutPath>drv_hmc5883l.c</FilenameWithoutPath>
@ -745,8 +765,8 @@
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>27</ColumnNumber> <ColumnNumber>27</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>167</TopLine>
<CurrentLine>167</CurrentLine>
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>.\src\drv_i2c.c</PathWithFileName> <PathWithFileName>.\src\drv_i2c.c</PathWithFileName>
<FilenameWithoutPath>drv_i2c.c</FilenameWithoutPath> <FilenameWithoutPath>drv_i2c.c</FilenameWithoutPath>
@ -771,10 +791,10 @@
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>1</ColumnNumber>
<ColumnNumber>47</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>77</TopLine>
<CurrentLine>99</CurrentLine>
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>.\src\drv_pwm.c</PathWithFileName> <PathWithFileName>.\src\drv_pwm.c</PathWithFileName>
<FilenameWithoutPath>drv_pwm.c</FilenameWithoutPath> <FilenameWithoutPath>drv_pwm.c</FilenameWithoutPath>
@ -797,12 +817,12 @@
<GroupNumber>2</GroupNumber> <GroupNumber>2</GroupNumber>
<FileNumber>19</FileNumber> <FileNumber>19</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp>
<tvExp>1</tvExp>
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>0</ColumnNumber> <ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<TopLine>153</TopLine>
<CurrentLine>190</CurrentLine>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>.\src\drv_uart.c</PathWithFileName> <PathWithFileName>.\src\drv_uart.c</PathWithFileName>
<FilenameWithoutPath>drv_uart.c</FilenameWithoutPath> <FilenameWithoutPath>drv_uart.c</FilenameWithoutPath>
@ -825,12 +845,12 @@
<GroupNumber>2</GroupNumber> <GroupNumber>2</GroupNumber>
<FileNumber>21</FileNumber> <FileNumber>21</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>1</tvExp>
<tvExp>0</tvExp>
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>13</ColumnNumber>
<ColumnNumber>14</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>421</TopLine>
<CurrentLine>451</CurrentLine>
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>.\src\drv_mpu6050.c</PathWithFileName> <PathWithFileName>.\src\drv_mpu6050.c</PathWithFileName>
<FilenameWithoutPath>drv_mpu6050.c</FilenameWithoutPath> <FilenameWithoutPath>drv_mpu6050.c</FilenameWithoutPath>
@ -974,10 +994,10 @@
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<Focus>0</Focus> <Focus>0</Focus>
<ColumnNumber>0</ColumnNumber>
<ColumnNumber>9</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<TopLine>609</TopLine>
<CurrentLine>609</CurrentLine>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>.\lib\STM32F10x_StdPeriph_Driver\src\stm32f10x_usart.c</PathWithFileName> <PathWithFileName>.\lib\STM32F10x_StdPeriph_Driver\src\stm32f10x_usart.c</PathWithFileName>
<FilenameWithoutPath>stm32f10x_usart.c</FilenameWithoutPath> <FilenameWithoutPath>stm32f10x_usart.c</FilenameWithoutPath>

10
baseflight.uvproj

@ -441,6 +441,11 @@
<FileType>1</FileType> <FileType>1</FileType>
<FilePath>.\src\gps.c</FilePath> <FilePath>.\src\gps.c</FilePath>
</File> </File>
<File>
<FileName>spektrum.c</FileName>
<FileType>1</FileType>
<FilePath>.\src\spektrum.c</FilePath>
</File>
</Files> </Files>
</Group> </Group>
<Group> <Group>
@ -1064,6 +1069,11 @@
<FileType>1</FileType> <FileType>1</FileType>
<FilePath>.\src\gps.c</FilePath> <FilePath>.\src\gps.c</FilePath>
</File> </File>
<File>
<FileName>spektrum.c</FileName>
<FileType>1</FileType>
<FilePath>.\src\spektrum.c</FilePath>
</File>
</Files> </Files>
</Group> </Group>
<Group> <Group>

4958
obj/baseflight.hex
File diff suppressed because it is too large
View File

11
src/board.h

@ -11,6 +11,10 @@
#include "stm32f10x_conf.h" #include "stm32f10x_conf.h"
#include "core_cm3.h" #include "core_cm3.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif /* M_PI */
typedef enum { typedef enum {
SENSOR_ACC = 1 << 0, SENSOR_ACC = 1 << 0,
SENSOR_BARO = 1 << 1, SENSOR_BARO = 1 << 1,
@ -30,10 +34,13 @@ typedef enum {
FEATURE_GYRO_SMOOTHING = 1 << 7, FEATURE_GYRO_SMOOTHING = 1 << 7,
FEATURE_LED_RING = 1 << 8, FEATURE_LED_RING = 1 << 8,
FEATURE_GPS = 1 << 9, FEATURE_GPS = 1 << 9,
FEATURE_SPEKTRUM = 1 << 10,
} AvailableFeatures; } AvailableFeatures;
typedef void (* sensorInitFuncPtr)(void);
typedef void (* sensorReadFuncPtr)(int16_t *data);
typedef void (* sensorInitFuncPtr)(void); // sensor init prototype
typedef void (* sensorReadFuncPtr)(int16_t *data); // sensor read and align prototype
typedef void (* uartReceiveCallbackPtr)(uint16_t data); // used by uart2 driver to return frames to app
typedef uint16_t (* rcReadRawDataPtr)(uint8_t chan); // used by receiver driver to return channel data
typedef struct sensor_t typedef struct sensor_t
{ {

24
src/cli.c

@ -36,6 +36,7 @@ const char *mixerNames[] = {
const char *featureNames[] = { const char *featureNames[] = {
"PPM", "VBAT", "INFLIGHT_ACC_CAL", "DIGITAL_SERVO", "MOTOR_STOP", "PPM", "VBAT", "INFLIGHT_ACC_CAL", "DIGITAL_SERVO", "MOTOR_STOP",
"SERVO_TILT", "CAMTRIG", "GYRO_SMOOTHING", "LED_RING", "GPS", "SERVO_TILT", "CAMTRIG", "GYRO_SMOOTHING", "LED_RING", "GPS",
"SPEKTRUM",
NULL NULL
}; };
@ -88,6 +89,7 @@ const clivalue_t valueTable[] = {
{ "mincommand", VAR_UINT16, &cfg.mincommand, 0, 2000 }, { "mincommand", VAR_UINT16, &cfg.mincommand, 0, 2000 },
{ "mincheck", VAR_UINT16, &cfg.mincheck, 0, 2000 }, { "mincheck", VAR_UINT16, &cfg.mincheck, 0, 2000 },
{ "maxcheck", VAR_UINT16, &cfg.maxcheck, 0, 2000 }, { "maxcheck", VAR_UINT16, &cfg.maxcheck, 0, 2000 },
{ "spektrum_hires", VAR_UINT8, &cfg.spektrum_hires, 0, 1 },
{ "vbatscale", VAR_UINT8, &cfg.vbatscale, 10, 200 }, { "vbatscale", VAR_UINT8, &cfg.vbatscale, 10, 200 },
{ "vbatmaxcellvoltage", VAR_UINT8, &cfg.vbatmaxcellvoltage, 10, 50 }, { "vbatmaxcellvoltage", VAR_UINT8, &cfg.vbatmaxcellvoltage, 10, 50 },
{ "vbatmincellvoltage", VAR_UINT8, &cfg.vbatmincellvoltage, 10, 50 }, { "vbatmincellvoltage", VAR_UINT8, &cfg.vbatmincellvoltage, 10, 50 },
@ -99,6 +101,8 @@ const clivalue_t valueTable[] = {
{ "tri_yaw_max", VAR_UINT16, &cfg.tri_yaw_max, 0, 2000 }, { "tri_yaw_max", VAR_UINT16, &cfg.tri_yaw_max, 0, 2000 },
{ "tilt_pitch_prop", VAR_INT8, &cfg.tilt_pitch_prop, -100, 100 }, { "tilt_pitch_prop", VAR_INT8, &cfg.tilt_pitch_prop, -100, 100 },
{ "tilt_roll_prop", VAR_INT8, &cfg.tilt_roll_prop, -100, 100 }, { "tilt_roll_prop", VAR_INT8, &cfg.tilt_roll_prop, -100, 100 },
{ "acc_lpf_factor", VAR_UINT8, &cfg.acc_lpf_factor, 0, 32 },
{ "gyro_lpf", VAR_UINT16, &cfg.gyro_lpf, 0, 256 },
{ "p_pitch", VAR_UINT8, &cfg.P8[PITCH], 0, 200}, { "p_pitch", VAR_UINT8, &cfg.P8[PITCH], 0, 200},
{ "i_pitch", VAR_UINT8, &cfg.I8[PITCH], 0, 200}, { "i_pitch", VAR_UINT8, &cfg.I8[PITCH], 0, 200},
{ "d_pitch", VAR_UINT8, &cfg.D8[PITCH], 0, 200}, { "d_pitch", VAR_UINT8, &cfg.D8[PITCH], 0, 200},
@ -252,10 +256,10 @@ static void cliHelp(char *cmdline)
uartPrint("Available commands:\r\n"); uartPrint("Available commands:\r\n");
for (i = 0; i < CMD_COUNT; i++) { for (i = 0; i < CMD_COUNT; i++) {
uartPrint(cmdTable[i].name);
uartWrite(' ');
uartPrint(cmdTable[i].param);
uartPrint("\r\n");
uartPrint(cmdTable[i].name);
uartWrite(' ');
uartPrint(cmdTable[i].param);
uartPrint("\r\n");
} }
} }
@ -344,15 +348,15 @@ static void cliPrintVar(const clivalue_t *var)
case VAR_UINT8: case VAR_UINT8:
value = *(uint8_t *)var->ptr; value = *(uint8_t *)var->ptr;
break; break;
case VAR_INT8: case VAR_INT8:
value = *(int8_t *)var->ptr; value = *(int8_t *)var->ptr;
break; break;
case VAR_UINT16: case VAR_UINT16:
value = *(uint16_t *)var->ptr; value = *(uint16_t *)var->ptr;
break; break;
case VAR_INT16: case VAR_INT16:
value = *(int16_t *)var->ptr; value = *(int16_t *)var->ptr;
break; break;
@ -389,7 +393,7 @@ static void cliSet(char *cmdline)
const clivalue_t *val; const clivalue_t *val;
char *eqptr = NULL; char *eqptr = NULL;
int32_t value = 0; int32_t value = 0;
len = strlen(cmdline); len = strlen(cmdline);
if (len == 0) { if (len == 0) {
@ -525,7 +529,7 @@ void cliProcess(void)
// enter pressed // enter pressed
clicmd_t *cmd = NULL; clicmd_t *cmd = NULL;
clicmd_t target; clicmd_t target;
uartPrint("\r\n");
uartPrint("\r\n");
cliBuffer[bufferIndex] = 0; // null terminate cliBuffer[bufferIndex] = 0; // null terminate
target.name = cliBuffer; target.name = cliBuffer;
@ -542,7 +546,7 @@ void cliProcess(void)
// 'exit' will reset this flag, so we don't need to print prompt again // 'exit' will reset this flag, so we don't need to print prompt again
if (!cliMode) if (!cliMode)
return;
return;
cliPrompt(); cliPrompt();
} else if (c == 127) { } else if (c == 127) {
// backspace // backspace

6
src/config.c

@ -9,7 +9,7 @@ config_t cfg;
const char rcChannelLetters[] = "AERT1234"; const char rcChannelLetters[] = "AERT1234";
static uint32_t enabledSensors = 0; static uint32_t enabledSensors = 0;
static uint8_t checkNewConf = 6;
static uint8_t checkNewConf = 7;
void parseRcChannels(const char *input) void parseRcChannels(const char *input)
{ {
@ -112,6 +112,8 @@ void checkFirstTime(bool reset)
} }
cfg.accTrim[0] = 0; cfg.accTrim[0] = 0;
cfg.accTrim[1] = 0; cfg.accTrim[1] = 0;
cfg.acc_lpf_factor = 4;
cfg.gyro_lpf = 42;
cfg.gyro_smoothing_factor = 0x00141403; // default factors of 20, 20, 3 for R/P/Y cfg.gyro_smoothing_factor = 0x00141403; // default factors of 20, 20, 3 for R/P/Y
cfg.powerTrigger1 = 0; cfg.powerTrigger1 = 0;
cfg.vbatscale = 110; cfg.vbatscale = 110;
@ -120,8 +122,8 @@ void checkFirstTime(bool reset)
// Radio/ESC // Radio/ESC
parseRcChannels("AETR1234"); parseRcChannels("AETR1234");
// parseRcChannels("ATER1234");
cfg.deadband = 0; cfg.deadband = 0;
cfg.spektrum_hires = 0;
cfg.midrc = 1500; cfg.midrc = 1500;
cfg.mincheck = 1100; cfg.mincheck = 1100;
cfg.maxcheck = 1900; cfg.maxcheck = 1900;

6
src/drv_adxl345.c

@ -57,14 +57,8 @@ static void adxl345Init(void)
#else #else
// MWC defaults // MWC defaults
i2cWrite(ADXL345_ADDRESS, ADXL345_POWER_CTL, 1 << 3); // register: Power CTRL -- value: Set measure bit 3 on i2cWrite(ADXL345_ADDRESS, ADXL345_POWER_CTL, 1 << 3); // register: Power CTRL -- value: Set measure bit 3 on
#if 1
i2cWrite(ADXL345_ADDRESS, ADXL345_DATA_FORMAT, 0x0B); // register: DATA_FORMAT -- value: Set bits 3(full range) and 1 0 on (+/- 16g-range) i2cWrite(ADXL345_ADDRESS, ADXL345_DATA_FORMAT, 0x0B); // register: DATA_FORMAT -- value: Set bits 3(full range) and 1 0 on (+/- 16g-range)
i2cWrite(ADXL345_ADDRESS, ADXL345_BW_RATE, 0x09); // register: BW_RATE -- value: rate=50hz, bw=20hz i2cWrite(ADXL345_ADDRESS, ADXL345_BW_RATE, 0x09); // register: BW_RATE -- value: rate=50hz, bw=20hz
#else
// testing
i2cWrite(ADXL345_ADDRESS, ADXL345_DATA_FORMAT, (ADXL_RANGE_8G & 0x03) | ADXL_FULL_RES); // register: DATA_FORMAT -- value: Set bits 3(full range) and 1 0 on (+/- 16g-range)
i2cWrite(ADXL345_ADDRESS, ADXL345_BW_RATE, ADXL_RATE_800); // register: BW_RATE -- value: rate=50hz, bw=20hz
#endif
#endif /* FreeFlight */ #endif /* FreeFlight */
} }

14
src/drv_bmp085.c

@ -35,7 +35,6 @@ typedef struct {
uint8_t sensortype; uint8_t sensortype;
int32_t param_b5; int32_t param_b5;
int32_t number_of_samples;
int16_t oversampling_setting; int16_t oversampling_setting;
int16_t smd500_t_resolution, smd500_masterclock; int16_t smd500_t_resolution, smd500_masterclock;
@ -129,7 +128,6 @@ bool bmp085Init(void)
p_bmp085->dev_addr = BMP085_I2C_ADDR; /* preset BMP085 I2C_addr */ p_bmp085->dev_addr = BMP085_I2C_ADDR; /* preset BMP085 I2C_addr */
i2cRead(p_bmp085->dev_addr, BMP085_CHIP_ID__REG, 1, &data); /* read Chip Id */ i2cRead(p_bmp085->dev_addr, BMP085_CHIP_ID__REG, 1, &data); /* read Chip Id */
p_bmp085->chip_id = BMP085_GET_BITSLICE(data, BMP085_CHIP_ID); p_bmp085->chip_id = BMP085_GET_BITSLICE(data, BMP085_CHIP_ID);
p_bmp085->number_of_samples = 1;
p_bmp085->oversampling_setting = 2; p_bmp085->oversampling_setting = 2;
if (p_bmp085->chip_id == BMP085_CHIP_ID) { /* get bitslice */ if (p_bmp085->chip_id == BMP085_CHIP_ID) { /* get bitslice */
@ -162,11 +160,15 @@ int32_t bmp085_read_pressure(void)
return bmp085_get_pressure(bmp085_get_up()); return bmp085_get_pressure(bmp085_get_up());
} }
// #define BMP_TEMP_OSS 4
int16_t bmp085_get_temperature(uint32_t ut) int16_t bmp085_get_temperature(uint32_t ut)
{ {
int16_t temperature; int16_t temperature;
int32_t x1, x2; int32_t x1, x2;
#ifdef BMP_TEMP_OSS
static uint32_t temp;
#endif
if (p_bmp085->sensortype == BOSCH_PRESSURE_BMP085) { if (p_bmp085->sensortype == BOSCH_PRESSURE_BMP085) {
x1 = (((int32_t) ut - (int32_t) p_bmp085->cal_param.ac6) * (int32_t) p_bmp085->cal_param.ac5) >> 15; x1 = (((int32_t) ut - (int32_t) p_bmp085->cal_param.ac6) * (int32_t) p_bmp085->cal_param.ac5) >> 15;
@ -175,7 +177,14 @@ int16_t bmp085_get_temperature(uint32_t ut)
} }
temperature = ((p_bmp085->param_b5 + 8) >> 4); // temperature in 0.1°C temperature = ((p_bmp085->param_b5 + 8) >> 4); // temperature in 0.1°C
#ifdef BMP_TEMP_OSS
temp *= (1 << BMP_TEMP_OSS) - 1; // multiply the temperature variable by 3 - we have tau == 1/4
temp += ((uint32_t)temperature) << 8; // add on the buffer
temp >>= BMP_TEMP_OSS; // divide by 4
return (int16_t)temp;
#else
return temperature; return temperature;
#endif
} }
int32_t bmp085_get_pressure(uint32_t up) int32_t bmp085_get_pressure(uint32_t up)
@ -266,7 +275,6 @@ uint32_t bmp085_get_up(void)
i2cRead(p_bmp085->dev_addr, BMP085_ADC_OUT_MSB_REG, 3, data); i2cRead(p_bmp085->dev_addr, BMP085_ADC_OUT_MSB_REG, 3, data);
up = (((uint32_t) data[0] << 16) | ((uint32_t) data[1] << 8) | (uint32_t) data[2]) >> (8 - p_bmp085->oversampling_setting); up = (((uint32_t) data[0] << 16) | ((uint32_t) data[1] << 8) | (uint32_t) data[2]) >> (8 - p_bmp085->oversampling_setting);
p_bmp085->number_of_samples = 1;
return up; return up;
} }

21
src/drv_hmc5883l.c

@ -9,12 +9,11 @@ bool hmc5883lDetect(void)
{ {
bool ack = false; bool ack = false;
uint8_t sig = 0; uint8_t sig = 0;
ack = i2cRead(MAG_ADDRESS, 0x0A, 1, &sig); ack = i2cRead(MAG_ADDRESS, 0x0A, 1, &sig);
if (!ack || sig != 'H') if (!ack || sig != 'H')
return false; return false;
return true; return true;
} }
@ -22,28 +21,28 @@ void hmc5883lInit(void)
{ {
delay(100); delay(100);
// force positiveBias // force positiveBias
i2cWrite(MAG_ADDRESS, 0x00, 0x71); //Configuration Register A -- 0 11 100 01 num samples: 8 ; output rate: 15Hz ; positive bias
i2cWrite(MAG_ADDRESS, 0x00, 0x71); // Configuration Register A -- 0 11 100 01 num samples: 8 ; output rate: 15Hz ; positive bias
delay(50); delay(50);
// set gains for calibration // set gains for calibration
i2cWrite(MAG_ADDRESS, 0x01, 0x60); //Configuration Register B -- 011 00000 configuration gain 2.5Ga
i2cWrite(MAG_ADDRESS, 0x02, 0x01); //Mode register -- 000000 01 single Conversion Mode
i2cWrite(MAG_ADDRESS, 0x01, 0x60); // Configuration Register B -- 011 00000 configuration gain 2.5Ga
i2cWrite(MAG_ADDRESS, 0x02, 0x01); // Mode register -- 000000 01 single Conversion Mode
// this enters test mode // this enters test mode
} }
void hmc5883lFinishCal(void) void hmc5883lFinishCal(void)
{ {
// leave test mode // leave test mode
i2cWrite(MAG_ADDRESS, 0x00, 0x70); //Configuration Register A -- 0 11 100 00 num samples: 8 ; output rate: 15Hz ; normal measurement mode
i2cWrite(MAG_ADDRESS, 0x01, 0x20); //Configuration Register B -- 001 00000 configuration gain 1.3Ga
i2cWrite(MAG_ADDRESS, 0x02, 0x00); //Mode register -- 000000 00 continuous Conversion Mode
i2cWrite(MAG_ADDRESS, 0x00, 0x70); // Configuration Register A -- 0 11 100 00 num samples: 8 ; output rate: 15Hz ; normal measurement mode
i2cWrite(MAG_ADDRESS, 0x01, 0x20); // Configuration Register B -- 001 00000 configuration gain 1.3Ga
i2cWrite(MAG_ADDRESS, 0x02, 0x00); // Mode register -- 000000 00 continuous Conversion Mode
} }
void hmc5883lRead(int16_t *magData) void hmc5883lRead(int16_t *magData)
{ {
uint8_t buf[6]; uint8_t buf[6];
i2cRead(MAG_ADDRESS, MAG_DATA_REGISTER, 6, buf); i2cRead(MAG_ADDRESS, MAG_DATA_REGISTER, 6, buf);
magData[0] = buf[0] << 8 | buf[1]; magData[0] = buf[0] << 8 | buf[1];
magData[1] = buf[2] << 8 | buf[3]; magData[1] = buf[2] << 8 | buf[3];
magData[2] = buf[4] << 8 | buf[5]; magData[2] = buf[4] << 8 | buf[5];

31
src/drv_mpu3050.c

@ -14,6 +14,7 @@
// Bits // Bits
#define MPU3050_FS_SEL_2000DPS 0x18 #define MPU3050_FS_SEL_2000DPS 0x18
#define MPU3050_DLPF_10HZ 0x05
#define MPU3050_DLPF_20HZ 0x04 #define MPU3050_DLPF_20HZ 0x04
#define MPU3050_DLPF_42HZ 0x03 #define MPU3050_DLPF_42HZ 0x03
#define MPU3050_DLPF_98HZ 0x02 #define MPU3050_DLPF_98HZ 0x02
@ -23,7 +24,7 @@
#define MPU3050_USER_RESET 0x01 #define MPU3050_USER_RESET 0x01
#define MPU3050_CLK_SEL_PLL_GX 0x01 #define MPU3050_CLK_SEL_PLL_GX 0x01
static uint8_t mpuLowPassFliter = MPU3050_DLPF_42HZ;
static uint8_t mpuLowPassFilter = MPU3050_DLPF_42HZ;
static void mpu3050Init(void); static void mpu3050Init(void);
static void mpu3050Read(int16_t *gyroData); static void mpu3050Read(int16_t *gyroData);
@ -46,6 +47,32 @@ bool mpu3050Detect(sensor_t *gyro)
return true; return true;
} }
void mpu3050Config(uint16_t lpf)
{
switch (lpf) {
case 256:
mpuLowPassFilter = MPU3050_DLPF_256HZ;
break;
case 188:
mpuLowPassFilter = MPU3050_DLPF_188HZ;
break;
case 98:
mpuLowPassFilter = MPU3050_DLPF_98HZ;
break;
case 42:
mpuLowPassFilter = MPU3050_DLPF_42HZ;
break;
case 20:
mpuLowPassFilter = MPU3050_DLPF_20HZ;
break;
case 10:
mpuLowPassFilter = MPU3050_DLPF_10HZ;
break;
}
i2cWrite(MPU3050_ADDRESS, MPU3050_DLPF_FS_SYNC, MPU3050_FS_SEL_2000DPS | mpuLowPassFilter);
}
static void mpu3050Init(void) static void mpu3050Init(void)
{ {
bool ack; bool ack;
@ -56,7 +83,7 @@ static void mpu3050Init(void)
if (!ack) if (!ack)
failureMode(3); failureMode(3);
i2cWrite(MPU3050_ADDRESS, MPU3050_DLPF_FS_SYNC, MPU3050_FS_SEL_2000DPS | mpuLowPassFliter);
i2cWrite(MPU3050_ADDRESS, MPU3050_DLPF_FS_SYNC, MPU3050_FS_SEL_2000DPS | mpuLowPassFilter);
i2cWrite(MPU3050_ADDRESS, MPU3050_INT_CFG, 0); i2cWrite(MPU3050_ADDRESS, MPU3050_INT_CFG, 0);
i2cWrite(MPU3050_ADDRESS, MPU3050_USER_CTRL, MPU3050_USER_RESET); i2cWrite(MPU3050_ADDRESS, MPU3050_USER_CTRL, MPU3050_USER_RESET);
i2cWrite(MPU3050_ADDRESS, MPU3050_PWR_MGM, MPU3050_CLK_SEL_PLL_GX); i2cWrite(MPU3050_ADDRESS, MPU3050_PWR_MGM, MPU3050_CLK_SEL_PLL_GX);

1
src/drv_mpu3050.h

@ -1,3 +1,4 @@
#pragma once #pragma once
bool mpu3050Detect(sensor_t *gyro); bool mpu3050Detect(sensor_t *gyro);
void mpu3050Config(uint16_t lpf);

126
src/drv_pwm.c

@ -154,67 +154,14 @@ static void pwmIRQHandler(TIM_TypeDef *tim)
} }
} }
bool pwmInit(bool usePPM, bool useServos, bool useDigitalServos)
static void pwmInitializeInput(bool usePPM)
{ {
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitTypeDef NVIC_InitStructure;
uint8_t i;
uint8_t i, val;
uint16_t c;
bool throttleCal = false;
// Inputs
// RX1 TIM2_CH1 PA0 [also PPM] [also used for throttle calibration]
// RX2 TIM2_CH2 PA1
// RX3 TIM2_CH3 PA2 [also UART2_TX]
// RX4 TIM2_CH4 PA3 [also UART2_RX]
// RX5 TIM3_CH1 PA6 [also ADC_IN6]
// RX6 TIM3_CH2 PA7 [also ADC_IN7]
// RX7 TIM3_CH3 PB0 [also ADC_IN8]
// RX8 TIM3_CH4 PB1 [also ADC_IN9]
// Outputs
// PWM1 TIM1_CH1 PA8
// PWM2 TIM1_CH4 PA11
// PWM3 TIM4_CH1 PB6 [also I2C1_SCL]
// PWM4 TIM4_CH2 PB7 [also I2C1_SDA]
// PWM5 TIM4_CH3 PB8
// PWM6 TIM4_CH4 PB9
// automatic throttle calibration detection: PA0 to ground via bindplug
// Configure TIM2_CH1 for input
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
#if 0
// wait a while
delay(100);
for (c = 0; c < 50000; c++) {
val = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0);
if (val) {
throttleCal = false;
break;
}
}
#endif
// use PPM or PWM input
usePPMFlag = usePPM;
// preset channels to center
for (i = 0; i < 8; i++)
Inputs[i].capture = 1500;
// Timers run at 1mhz.
// TODO: clean this shit up. Make it all dynamic etc.
// Input pins
// Input pins
if (usePPM) { if (usePPM) {
// Configure TIM2_CH1 for PPM input // Configure TIM2_CH1 for PPM input
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
@ -295,7 +242,69 @@ bool pwmInit(bool usePPM, bool useServos, bool useDigitalServos)
// In PWM input mode, all 8 channels are wasted // In PWM input mode, all 8 channels are wasted
numOutputChannels = 6; numOutputChannels = 6;
} }
}
bool pwmInit(bool usePPM, bool pwmppmInput, bool useServos, bool useDigitalServos)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
uint8_t i, val;
uint16_t c;
bool throttleCal = false;
// Inputs
// RX1 TIM2_CH1 PA0 [also PPM] [also used for throttle calibration]
// RX2 TIM2_CH2 PA1
// RX3 TIM2_CH3 PA2 [also UART2_TX]
// RX4 TIM2_CH4 PA3 [also UART2_RX]
// RX5 TIM3_CH1 PA6 [also ADC_IN6]
// RX6 TIM3_CH2 PA7 [also ADC_IN7]
// RX7 TIM3_CH3 PB0 [also ADC_IN8]
// RX8 TIM3_CH4 PB1 [also ADC_IN9]
// Outputs
// PWM1 TIM1_CH1 PA8
// PWM2 TIM1_CH4 PA11
// PWM3 TIM4_CH1 PB6 [also I2C1_SCL]
// PWM4 TIM4_CH2 PB7 [also I2C1_SDA]
// PWM5 TIM4_CH3 PB8
// PWM6 TIM4_CH4 PB9
// automatic throttle calibration detection: PA0 to ground via bindplug
// Configure TIM2_CH1 for input
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
#if 0
// wait a while
delay(100);
for (c = 0; c < 50000; c++) {
val = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0);
if (val) {
throttleCal = false;
break;
}
}
#endif
// use PPM or PWM input
usePPMFlag = usePPM;
// preset channels to center
for (i = 0; i < 8; i++)
Inputs[i].capture = 1500;
// Timers run at 1mhz.
// TODO: clean this shit up. Make it all dynamic etc.
if (pwmppmInput)
pwmInitializeInput(usePPMFlag);
// Output pins // Output pins
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_11; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
@ -327,7 +336,7 @@ bool pwmInit(bool usePPM, bool useServos, bool useDigitalServos)
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
// PWM1,2
// PWM1,2
TIM_OC1Init(TIM1, &TIM_OCInitStructure); TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_OC4Init(TIM1, &TIM_OCInitStructure); TIM_OC4Init(TIM1, &TIM_OCInitStructure);
// PWM3,4,5,6 // PWM3,4,5,6
@ -341,7 +350,8 @@ bool pwmInit(bool usePPM, bool useServos, bool useDigitalServos)
TIM_CtrlPWMOutputs(TIM1, ENABLE); TIM_CtrlPWMOutputs(TIM1, ENABLE);
TIM_CtrlPWMOutputs(TIM4, ENABLE); TIM_CtrlPWMOutputs(TIM4, ENABLE);
if (usePPM) {
// turn on more motor outputs if we're using ppm / not using pwm input
if (!pwmppmInput || usePPM) {
// PWM 7,8,9,10 // PWM 7,8,9,10
TIM_TimeBaseStructure.TIM_Period = PULSE_PERIOD - 1; TIM_TimeBaseStructure.TIM_Period = PULSE_PERIOD - 1;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

2
src/drv_pwm.h

@ -1,6 +1,6 @@
#pragma once #pragma once
bool pwmInit(bool usePPM, bool useServos, bool useDigitalServos); // returns whether driver is asking to calibrate throttle or not
bool pwmInit(bool usePPM, bool pwmppmInput, bool useServos, bool useDigitalServos); // returns whether driver is asking to calibrate throttle or not
void pwmWrite(uint8_t channel, uint16_t value); void pwmWrite(uint8_t channel, uint16_t value);
uint16_t pwmRead(uint8_t channel); uint16_t pwmRead(uint8_t channel);
uint8_t pwmGetNumOutputChannels(void); uint8_t pwmGetNumOutputChannels(void);

60
src/drv_uart.c

@ -18,11 +18,11 @@ static void uartTxDMA(void)
{ {
DMA1_Channel4->CMAR = (uint32_t)&txBuffer[txBufferTail]; DMA1_Channel4->CMAR = (uint32_t)&txBuffer[txBufferTail];
if (txBufferHead > txBufferTail) { if (txBufferHead > txBufferTail) {
DMA1_Channel4->CNDTR = txBufferHead - txBufferTail;
txBufferTail = txBufferHead;
DMA1_Channel4->CNDTR = txBufferHead - txBufferTail;
txBufferTail = txBufferHead;
} else { } else {
DMA1_Channel4->CNDTR = UART_BUFFER_SIZE - txBufferTail;
txBufferTail = 0;
DMA1_Channel4->CNDTR = UART_BUFFER_SIZE - txBufferTail;
txBufferTail = 0;
} }
DMA_Cmd(DMA1_Channel4, ENABLE); DMA_Cmd(DMA1_Channel4, ENABLE);
@ -34,7 +34,7 @@ void DMA1_Channel4_IRQHandler(void)
DMA_Cmd(DMA1_Channel4, DISABLE); DMA_Cmd(DMA1_Channel4, DISABLE);
if (txBufferHead != txBufferTail) if (txBufferHead != txBufferTail)
uartTxDMA();
uartTxDMA();
} }
void uartInit(void) void uartInit(void)
@ -47,7 +47,7 @@ void uartInit(void)
// UART // UART
// USART1_TX PA9 // USART1_TX PA9
// USART1_RX PA10 // USART1_RX PA10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
@ -119,7 +119,7 @@ uint8_t uartRead(void)
ch = rxBuffer[UART_BUFFER_SIZE - rxDMAPos]; ch = rxBuffer[UART_BUFFER_SIZE - rxDMAPos];
// go back around the buffer // go back around the buffer
if (--rxDMAPos == 0) if (--rxDMAPos == 0)
rxDMAPos = UART_BUFFER_SIZE;
rxDMAPos = UART_BUFFER_SIZE;
return ch; return ch;
} }
@ -137,11 +137,53 @@ void uartWrite(uint8_t ch)
// if DMA wasn't enabled, fire it up // if DMA wasn't enabled, fire it up
if (!(DMA1_Channel4->CCR & 1)) if (!(DMA1_Channel4->CCR & 1))
uartTxDMA();
uartTxDMA();
} }
void uartPrint(char *str) void uartPrint(char *str)
{ {
while (*str) while (*str)
uartWrite(*(str++));
uartWrite(*(str++));
}
/* -------------------------- UART2 (Spektrum, GPS) ----------------------------- */
uartReceiveCallbackPtr uart2Callback = NULL;
void uart2Init(uint32_t speed, uartReceiveCallbackPtr func)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = speed;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Rx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART2, &USART_InitStructure);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_Cmd(USART2, ENABLE);
uart2Callback = func;
}
void USART2_IRQHandler(void)
{
if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET) {
if (uart2Callback)
uart2Callback(USART_ReceiveData(USART2));
}
} }

1
src/drv_uart.h

@ -6,3 +6,4 @@ uint8_t uartRead(void);
uint8_t uartReadPoll(void); uint8_t uartReadPoll(void);
void uartWrite(uint8_t ch); void uartWrite(uint8_t ch);
void uartPrint(char *str); void uartPrint(char *str);
void uart2Init(uint32_t speed, uartReceiveCallbackPtr func);

57
src/gps.c

@ -1,10 +1,6 @@
#include "board.h" #include "board.h"
#include "mw.h" #include "mw.h"
#ifndef PI
#define PI 3.14159265358979323846
#endif
#ifndef sq #ifndef sq
#define sq(x) ((x)*(x)) #define sq(x) ((x)*(x))
#endif #endif
@ -13,52 +9,9 @@ static void GPS_NewData(uint16_t c);
static bool GPS_newFrame(char c); static bool GPS_newFrame(char c);
static void GPS_distance(int32_t lat1, int32_t lon1, int32_t lat2, int32_t lon2, uint16_t * dist, int16_t * bearing); static void GPS_distance(int32_t lat1, int32_t lon1, int32_t lat2, int32_t lon2, uint16_t * dist, int16_t * bearing);
/*-----------------------------------------------------------
*
* GPS low level routines
*
*-----------------------------------------------------------*/
void USART2_IRQHandler(void)
{
if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET) {
GPS_NewData(USART_ReceiveData(USART2));
}
}
static void uart2Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Rx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART2, &USART_InitStructure);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_Cmd(USART2, ENABLE);
}
void gpsInit(void) void gpsInit(void)
{ {
uart2Init();
uart2Init(9600, GPS_NewData);
sensorsSet(SENSOR_GPS); sensorsSet(SENSOR_GPS);
} }
@ -98,9 +51,9 @@ static void GPS_NewData(uint16_t c)
static void GPS_distance(int32_t lat1, int32_t lon1, int32_t lat2, int32_t lon2, uint16_t * dist, int16_t * bearing) static void GPS_distance(int32_t lat1, int32_t lon1, int32_t lat2, int32_t lon2, uint16_t * dist, int16_t * bearing)
{ {
float dLat = (lat2 - lat1); // difference of latitude in 1/100000 degrees float dLat = (lat2 - lat1); // difference of latitude in 1/100000 degrees
float dLon = (lon2 - lon1) * cos(lat1 * (PI / 180 / 100000.0)); // difference of longitude in 1/100000 degrees
*dist = 6372795 / 100000.0 * PI / 180 * (sqrt(sq(dLat) + sq(dLon)));
*bearing = 180 / PI * (atan2(dLon, dLat));
float dLon = (lon2 - lon1) * cosf(lat1 * (M_PI / 180 / 100000.0)); // difference of longitude in 1/100000 degrees
*dist = 6372795.0 / 100000.0 * M_PI / 180.0 * (sqrtf(sq(dLat) + sq(dLon)));
*bearing = 180.0 / M_PI * (atan2f(dLon, dLat));
} }
/* The latitude or longitude is coded this way in NMEA frames /* The latitude or longitude is coded this way in NMEA frames
@ -231,7 +184,7 @@ static bool GPS_newFrame(char c)
else else
parity ^= c; parity ^= c;
} else if (c == '\r' || c == '\n') { } else if (c == '\r' || c == '\n') {
if (checksum_param) { //parity checksum
if (checksum_param) { // parity checksum
uint8_t checksum = hex_c(string[0]); uint8_t checksum = hex_c(string[0]);
checksum <<= 4; checksum <<= 4;
checksum += hex_c(string[1]); checksum += hex_c(string[1]);

93
src/imu.c

@ -1,8 +1,6 @@
#include "board.h" #include "board.h"
#include "mw.h" #include "mw.h"
#define M_PI 3.14159265358979323846
int16_t gyroADC[3], accADC[3], accSmooth[3], magADC[3]; int16_t gyroADC[3], accADC[3], accSmooth[3], magADC[3];
int16_t acc_25deg = 0; int16_t acc_25deg = 0;
int32_t BaroAlt; int32_t BaroAlt;
@ -23,7 +21,7 @@ static void getEstimatedAttitude(void);
void imuInit(void) void imuInit(void)
{ {
acc_25deg = acc_1G * 0.423;
acc_25deg = acc_1G * 0.423f;
// if mag sensor is enabled, use it // if mag sensor is enabled, use it
if (sensors(SENSOR_MAG)) if (sensors(SENSOR_MAG))
@ -53,7 +51,7 @@ void computeIMU(void)
if ((micros() - timeInterleave) > 650) { if ((micros() - timeInterleave) > 650) {
annex650_overrun_count++; annex650_overrun_count++;
} else { } else {
while ((micros() - timeInterleave) < 650); //empirical, interleaving delay between 2 consecutive reads
while ((micros() - timeInterleave) < 650); // empirical, interleaving delay between 2 consecutive reads
} }
Gyro_getADC(); Gyro_getADC();
@ -108,11 +106,6 @@ void computeIMU(void)
// ************************************************** // **************************************************
//****** advanced users settings ******************* //****** advanced users settings *******************
/* Set the Low Pass Filter factor for ACC */
/* Increasing this value would reduce ACC noise (visible in GUI), but would increase ACC lag time*/
/* Comment this if you do not want filter at all.*/
/* Default WMC value: 8*/
#define ACC_LPF_FACTOR 4
/* Set the Low Pass Filter factor for Magnetometer */ /* Set the Low Pass Filter factor for Magnetometer */
/* Increasing this value would reduce Magnetometer noise (not visible in GUI), but would increase Magnetometer lag time*/ /* Increasing this value would reduce Magnetometer noise (not visible in GUI), but would increase Magnetometer lag time*/
@ -176,9 +169,7 @@ static void getEstimatedAttitude(void)
#if defined(MG_LPF_FACTOR) #if defined(MG_LPF_FACTOR)
static int16_t mgSmooth[3]; static int16_t mgSmooth[3];
#endif #endif
#if defined(ACC_LPF_FACTOR)
static int16_t accTemp[3]; //projection of smoothed and normalized magnetic vector on x/y/z axis, as measured by magnetometer static int16_t accTemp[3]; //projection of smoothed and normalized magnetic vector on x/y/z axis, as measured by magnetometer
#endif
static uint32_t previousT; static uint32_t previousT;
uint32_t currentT = micros(); uint32_t currentT = micros();
float scale, deltaGyroAngle[3]; float scale, deltaGyroAngle[3];
@ -189,16 +180,15 @@ static void getEstimatedAttitude(void)
// Initialization // Initialization
for (axis = 0; axis < 3; axis++) { for (axis = 0; axis < 3; axis++) {
deltaGyroAngle[axis] = gyroADC[axis] * scale; deltaGyroAngle[axis] = gyroADC[axis] * scale;
#if defined(ACC_LPF_FACTOR)
accTemp[axis] = (accTemp[axis] - (accTemp[axis] >> ACC_LPF_FACTOR)) + accADC[axis];
accSmooth[axis] = accTemp[axis] >> ACC_LPF_FACTOR;
#define ACC_VALUE accSmooth[axis]
#else
accSmooth[axis] = accADC[axis];
#define ACC_VALUE accADC[axis]
#endif
accMag += (int32_t) ACC_VALUE * ACC_VALUE;
if (cfg.acc_lpf_factor > 0) {
accTemp[axis] = (accTemp[axis] - (accTemp[axis] >> cfg.acc_lpf_factor)) + accADC[axis];
accSmooth[axis] = accTemp[axis] >> cfg.acc_lpf_factor;
} else {
accSmooth[axis] = accADC[axis];
}
accMag += (int32_t)accSmooth[axis] * accSmooth[axis];
if (sensors(SENSOR_MAG)) { if (sensors(SENSOR_MAG)) {
#if defined(MG_LPF_FACTOR) #if defined(MG_LPF_FACTOR)
mgSmooth[axis] = (mgSmooth[axis] * (MG_LPF_FACTOR - 1) + magADC[axis]) / MG_LPF_FACTOR; // LPF for Magnetometer values mgSmooth[axis] = (mgSmooth[axis] * (MG_LPF_FACTOR - 1) + magADC[axis]) / MG_LPF_FACTOR; // LPF for Magnetometer values
@ -208,7 +198,7 @@ static void getEstimatedAttitude(void)
#endif #endif
} }
} }
accMag = accMag * 100 / ((int32_t) acc_1G * acc_1G);
accMag = accMag * 100 / ((int32_t)acc_1G * acc_1G);
rotateV(&EstG.V, deltaGyroAngle); rotateV(&EstG.V, deltaGyroAngle);
if (sensors(SENSOR_MAG)) { if (sensors(SENSOR_MAG)) {
@ -223,18 +213,12 @@ static void getEstimatedAttitude(void)
// Apply complimentary filter (Gyro drift correction) // Apply complimentary filter (Gyro drift correction)
// If accel magnitude >1.4G or <0.6G and ACC vector outside of the limit range => we neutralize the effect of accelerometers in the angle estimation. // If accel magnitude >1.4G or <0.6G and ACC vector outside of the limit range => we neutralize the effect of accelerometers in the angle estimation.
// To do that, we just skip filter, as EstV already rotated by Gyro // To do that, we just skip filter, as EstV already rotated by Gyro
if ((36 < accMag && accMag < 196) || smallAngle25)
if ((36 < accMag && accMag < 196) || smallAngle25) {
for (axis = 0; axis < 3; axis++) { for (axis = 0; axis < 3; axis++) {
int16_t acc = ACC_VALUE;
#if !defined(TRUSTED_ACCZ)
if (smallAngle25 && axis == YAW)
//We consider ACCZ = acc_1G when the acc on other axis is small.
//It's a tweak to deal with some configs where ACC_Z tends to a value < acc_1G when high throttle is applied.
//This tweak applies only when the multi is not in inverted position
acc = acc_1G;
#endif
int16_t acc = accSmooth[axis];
EstG.A[axis] = (EstG.A[axis] * GYR_CMPF_FACTOR + acc) * INV_GYR_CMPF_FACTOR; EstG.A[axis] = (EstG.A[axis] * GYR_CMPF_FACTOR + acc) * INV_GYR_CMPF_FACTOR;
} }
}
if (sensors(SENSOR_MAG)) { if (sensors(SENSOR_MAG)) {
for (axis = 0; axis < 3; axis++) for (axis = 0; axis < 3; axis++)
@ -246,53 +230,8 @@ static void getEstimatedAttitude(void)
angle[PITCH] = _atan2f(EstG.V.Y, EstG.V.Z); angle[PITCH] = _atan2f(EstG.V.Y, EstG.V.Z);
if (sensors(SENSOR_MAG)) { if (sensors(SENSOR_MAG)) {
#define GHETTO
#ifdef GHETTO
// Attitude of the cross product vector GxM // Attitude of the cross product vector GxM
heading = _atan2f(EstG.V.X * EstM.V.Z - EstG.V.Z * EstM.V.X, EstG.V.Z * EstM.V.Y - EstG.V.Y * EstM.V.Z) / 10; heading = _atan2f(EstG.V.X * EstM.V.Z - EstG.V.Z * EstM.V.X, EstG.V.Z * EstM.V.Y - EstG.V.Y * EstM.V.Z) / 10;
#else
static float Cos_Roll, Sin_Roll, Cos_Pitch, Sin_Pitch;
static float Mx1, My1, Mz1, xh, yh;
static float rollRadians;
static float pitchRadians;
// proper tilt compensation
// Get pitch and roll in radians
rollRadians = angle[ROLL] / 1800.0 * M_PI;
pitchRadians = angle[PITCH] /1800.0 * M_PI;
//rollRadians = _atan2f(accADC[ROLL], accADC[YAW])/1800.0*M_PI;
//pitchRadians = _atan2f(accADC[PITCH], accADC[YAW])/1800.0*M_PI;
// Mx2 and My2 are the corrected values
// Mx1, My1 and Mz1 are the floating point values from the mag sensor
//Mx1 = magADC[ROLL];
//My1 = magADC[PITCH];
//Mz1 = magADC[YAW];
Mx1 = EstM.V.X;
My1 = EstM.V.Y;
Mz1 = EstM.V.Z;
// These are used more than once, so pre-calculate for efficiency
Cos_Roll = cosf(rollRadians);
Cos_Pitch = cosf(pitchRadians);
Sin_Roll = sinf(rollRadians);
Sin_Pitch = sinf(pitchRadians);
// The tilt-compensation equations are as follows
//X_h=X*cos(pitch)+Y*sin(roll)sin(pitch)-Z*cos(roll)*sin(pitch)
//Y_h=Y*cos(roll)+Z*sin(roll)
xh = (Mx1 * Cos_Pitch) + (My1 * Sin_Roll * Sin_Pitch) - (Mz1 * Sin_Pitch * Cos_Roll); // Correct x axis
yh = (My1 * Cos_Roll) + (Mz1 * Sin_Roll); // Correct y axis
// Tilt-adjusted heading in degrees
heading = _atan2f(yh, xh) / 10;
#endif
} }
} }
@ -332,7 +271,7 @@ void getEstimatedAltitude(void)
//D //D
temp32 = cfg.D8[PIDALT] * (BaroHigh - BaroLow) / 40; temp32 = cfg.D8[PIDALT] * (BaroHigh - BaroLow) / 40;
BaroPID -= temp32; BaroPID -= temp32;
EstAlt = BaroHigh * 10 / (BARO_TAB_SIZE / 2); EstAlt = BaroHigh * 10 / (BARO_TAB_SIZE / 2);
temp32 = AltHold - EstAlt; temp32 = AltHold - EstAlt;
@ -341,7 +280,7 @@ void getEstimatedAltitude(void)
// P // P
BaroPID += cfg.P8[PIDALT] * constrain(temp32, (-2) * cfg.P8[PIDALT], 2 * cfg.P8[PIDALT]) / 100; BaroPID += cfg.P8[PIDALT] * constrain(temp32, (-2) * cfg.P8[PIDALT], 2 * cfg.P8[PIDALT]) / 100;
BaroPID = constrain(BaroPID, -150, +150); // sum of P and D should be in range 150 BaroPID = constrain(BaroPID, -150, +150); // sum of P and D should be in range 150
// I // I
errorAltitudeI += temp32 * cfg.I8[PIDALT] / 50; errorAltitudeI += temp32 * cfg.I8[PIDALT] / 50;
errorAltitudeI = constrain(errorAltitudeI, -30000, 30000); errorAltitudeI = constrain(errorAltitudeI, -30000, 30000);

22
src/main.c

@ -2,6 +2,11 @@
#include "mw.h" #include "mw.h"
extern uint8_t useServo; extern uint8_t useServo;
extern rcReadRawDataPtr rcReadRawFunc;
// two receiver read functions
extern uint16_t pwmReadRawRC(uint8_t chan);
extern uint16_t spektrumReadRawRC(uint8_t chan);
void throttleCalibration(void) void throttleCalibration(void)
{ {
@ -48,9 +53,12 @@ int main(void)
mixerInit(); // this will set useServo var depending on mixer type mixerInit(); // this will set useServo var depending on mixer type
// pwmInit returns true if throttle calibration is requested. if so, do it here. throttleCalibration() does NOT return - for safety. // pwmInit returns true if throttle calibration is requested. if so, do it here. throttleCalibration() does NOT return - for safety.
if (pwmInit(feature(FEATURE_PPM), useServo, feature(FEATURE_DIGITAL_SERVO)))
if (pwmInit(feature(FEATURE_PPM), !feature(FEATURE_SPEKTRUM), useServo, feature(FEATURE_DIGITAL_SERVO)))
throttleCalibration(); // noreturn throttleCalibration(); // noreturn
// configure PWM/CPPM read function. spektrum will override that
rcReadRawFunc = pwmReadRawRC;
LED1_ON; LED1_ON;
LED0_OFF; LED0_OFF;
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
@ -72,9 +80,15 @@ int main(void)
if (feature(FEATURE_VBAT)) if (feature(FEATURE_VBAT))
batteryInit(); batteryInit();
// Optional GPS - available only when using PPM, otherwise required pins won't be usable
if (feature(FEATURE_PPM) && feature(FEATURE_GPS))
gpsInit();
if (feature(FEATURE_SPEKTRUM)) {
spektrumInit();
rcReadRawFunc = spektrumReadRawRC;
} else {
// spektrum and GPS are mutually exclusive
// Optional GPS - available only when using PPM, otherwise required pins won't be usable
if (feature(FEATURE_PPM) && feature(FEATURE_GPS))
gpsInit();
}
previousTime = micros(); previousTime = micros();
calibratingG = 400; calibratingG = 400;

8
src/mixer.c

@ -101,7 +101,7 @@ void mixTable(void)
static uint8_t camCycle = 0; static uint8_t camCycle = 0;
static uint8_t camState = 0; static uint8_t camState = 0;
static uint32_t camTime = 0; static uint32_t camTime = 0;
if (numberMotor > 3) { if (numberMotor > 3) {
//prevent "yaw jump" during yaw correction //prevent "yaw jump" during yaw correction
axisPID[YAW] = constrain(axisPID[YAW], -100 - abs(rcCommand[YAW]), +100 + abs(rcCommand[YAW])); axisPID[YAW] = constrain(axisPID[YAW], -100 - abs(rcCommand[YAW]), +100 + abs(rcCommand[YAW]));
@ -115,7 +115,7 @@ void mixTable(void)
servo[4] = constrain(1500 + (cfg.yaw_direction * axisPID[YAW]) + axisPID[PITCH], 1020, 2000); //LEFT servo[4] = constrain(1500 + (cfg.yaw_direction * axisPID[YAW]) + axisPID[PITCH], 1020, 2000); //LEFT
servo[5] = constrain(1500 + (cfg.yaw_direction * axisPID[YAW]) - axisPID[PITCH], 1020, 2000); //RIGHT servo[5] = constrain(1500 + (cfg.yaw_direction * axisPID[YAW]) - axisPID[PITCH], 1020, 2000); //RIGHT
break; break;
case MULTITYPE_TRI: case MULTITYPE_TRI:
motor[0] = PIDMIX(0, +4 / 3, 0); //REAR motor[0] = PIDMIX(0, +4 / 3, 0); //REAR
motor[1] = PIDMIX(-1, -2 / 3, 0); //RIGHT motor[1] = PIDMIX(-1, -2 / 3, 0); //RIGHT
@ -143,7 +143,7 @@ void mixTable(void)
motor[2] = PIDMIX(+0, +1, +1); //REAR_2 CCW motor[2] = PIDMIX(+0, +1, +1); //REAR_2 CCW
motor[3] = PIDMIX(+1, -1, 0); //FRONT_L CW motor[3] = PIDMIX(+1, -1, 0); //FRONT_L CW
break; break;
case MULTITYPE_Y6: case MULTITYPE_Y6:
motor[0] = PIDMIX(+0, +4 / 3, +1); //REAR motor[0] = PIDMIX(+0, +4 / 3, +1); //REAR
motor[1] = PIDMIX(-1, -2 / 3, -1); //RIGHT motor[1] = PIDMIX(-1, -2 / 3, -1); //RIGHT
@ -229,7 +229,7 @@ void mixTable(void)
servo[1] = constrain(servo[1] + cfg.wing_right_mid, WING_RIGHT_MIN, WING_RIGHT_MAX); servo[1] = constrain(servo[1] + cfg.wing_right_mid, WING_RIGHT_MIN, WING_RIGHT_MAX);
break; break;
} }
// do camstab // do camstab
if (feature(FEATURE_SERVO_TILT)) { if (feature(FEATURE_SERVO_TILT)) {
servo[0] = TILT_PITCH_MIDDLE + rcData[AUX3] - 1500; servo[0] = TILT_PITCH_MIDDLE + rcData[AUX3] - 1500;

101
src/mw.c

@ -1,7 +1,7 @@
#include "board.h" #include "board.h"
#include "mw.h" #include "mw.h"
// March 2012 V2.0_pre_version_3
// March 2012 V2.0
#define CHECKBOXITEMS 11 #define CHECKBOXITEMS 11
#define PIDITEMS 8 #define PIDITEMS 8
@ -22,19 +22,12 @@ uint8_t vbat; // battery voltage in 0.1V steps
volatile int16_t failsafeCnt = 0; volatile int16_t failsafeCnt = 0;
int16_t failsafeEvents = 0; int16_t failsafeEvents = 0;
int16_t rcData[8]; // interval [1000;2000]
int16_t rcData[8] = { 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500 }; // interval [1000;2000]
int16_t rcCommand[4]; // interval [1000;2000] for THROTTLE and [-500;+500] for ROLL/PITCH/YAW int16_t rcCommand[4]; // interval [1000;2000] for THROTTLE and [-500;+500] for ROLL/PITCH/YAW
//uint8_t rcRate8;
//uint8_t rcExpo8;
int16_t lookupRX[7]; // lookup table for expo & RC rate
int16_t lookupRX[7]; // lookup table for expo & RC rate
rcReadRawDataPtr rcReadRawFunc = NULL; // receive data from default (pwm/ppm) or additional (spek/sbus/?? receiver drivers)
// uint8_t P8[8], I8[8], D8[8]; //8 bits is much faster and the code is much shorter
uint8_t dynP8[3], dynI8[3], dynD8[3]; uint8_t dynP8[3], dynI8[3], dynD8[3];
// uint8_t rollPitchRate;
// uint8_t yawRate;
// uint8_t dynThrPID;
// uint8_t activate1[CHECKBOXITEMS];
// uint8_t activate2[CHECKBOXITEMS];
uint8_t rcOptions[CHECKBOXITEMS]; uint8_t rcOptions[CHECKBOXITEMS];
uint8_t okToArm = 0; uint8_t okToArm = 0;
uint8_t accMode = 0; // if level mode is a activated uint8_t accMode = 0; // if level mode is a activated
@ -42,7 +35,6 @@ uint8_t magMode = 0; // if compass heading hold is a activated
uint8_t baroMode = 0; // if altitude hold is activated uint8_t baroMode = 0; // if altitude hold is activated
int16_t axisPID[3]; int16_t axisPID[3];
volatile uint16_t rcValue[18] = { 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502 }; // interval [1000;2000]
// ********************** // **********************
// GPS // GPS
@ -60,7 +52,6 @@ uint16_t GPS_altitude, GPS_speed; // altitude in 0.1m and speed in 0.1m/s
uint8_t GPS_update = 0; // it's a binary toogle to distinct a GPS position update uint8_t GPS_update = 0; // it's a binary toogle to distinct a GPS position update
int16_t GPS_angle[2]; // it's the angles that must be applied for GPS correction int16_t GPS_angle[2]; // it's the angles that must be applied for GPS correction
//Automatic ACC Offset Calibration //Automatic ACC Offset Calibration
// ********************** // **********************
uint16_t InflightcalibratingA = 0; uint16_t InflightcalibratingA = 0;
@ -76,7 +67,6 @@ uint16_t AccInflightCalibrationActive = 0;
uint32_t pMeter[PMOTOR_SUM + 1]; // we use [0:7] for eight motors,one extra for sum uint32_t pMeter[PMOTOR_SUM + 1]; // we use [0:7] for eight motors,one extra for sum
uint8_t pMeterV; // dummy to satisfy the paramStruct logic in ConfigurationLoop() uint8_t pMeterV; // dummy to satisfy the paramStruct logic in ConfigurationLoop()
uint32_t pAlarm; // we scale the eeprom value from [0:255] to this value we can directly compare to the sum in pMeter[6] uint32_t pAlarm; // we scale the eeprom value from [0:255] to this value we can directly compare to the sum in pMeter[6]
// uint8_t powerTrigger1 = 0;
uint16_t powerValue = 0; // last known current uint16_t powerValue = 0; // last known current
uint16_t intPowerMeterSum, intPowerTrigger1; uint16_t intPowerMeterSum, intPowerTrigger1;
uint8_t batteryCellCount = 3; // cell count uint8_t batteryCellCount = 3; // cell count
@ -119,7 +109,7 @@ void annexCode(void)
static uint16_t vbatRawArray[8]; static uint16_t vbatRawArray[8];
uint8_t i; uint8_t i;
//PITCH & ROLL only dynamic PID adjustemnt, depending on throttle value
// PITCH & ROLL only dynamic PID adjustemnt, depending on throttle value
if (rcData[THROTTLE] < 1500) { if (rcData[THROTTLE] < 1500) {
prop2 = 100; prop2 = 100;
} else if (rcData[THROTTLE] < 2000) { } else if (rcData[THROTTLE] < 2000) {
@ -141,20 +131,20 @@ void annexCode(void)
uint16_t tmp2 = tmp / 100; uint16_t tmp2 = tmp / 100;
rcCommand[axis] = lookupRX[tmp2] + (tmp - tmp2 * 100) * (lookupRX[tmp2 + 1] - lookupRX[tmp2]) / 100; rcCommand[axis] = lookupRX[tmp2] + (tmp - tmp2 * 100) * (lookupRX[tmp2 + 1] - lookupRX[tmp2]) / 100;
prop1 = 100 - (uint16_t) cfg.rollPitchRate * tmp / 500; prop1 = 100 - (uint16_t) cfg.rollPitchRate * tmp / 500;
prop1 = (uint16_t) prop1 *prop2 / 100;
prop1 = (uint16_t)prop1 * prop2 / 100;
} else { //YAW } else { //YAW
rcCommand[axis] = tmp; rcCommand[axis] = tmp;
prop1 = 100 - (uint16_t) cfg.yawRate * tmp / 500;
prop1 = 100 - (uint16_t)cfg.yawRate * tmp / 500;
} }
dynP8[axis] = (uint16_t) cfg.P8[axis] * prop1 / 100;
dynD8[axis] = (uint16_t) cfg.D8[axis] * prop1 / 100;
dynP8[axis] = (uint16_t)cfg.P8[axis] * prop1 / 100;
dynD8[axis] = (uint16_t)cfg.D8[axis] * prop1 / 100;
if (rcData[axis] < cfg.midrc) if (rcData[axis] < cfg.midrc)
rcCommand[axis] = -rcCommand[axis]; rcCommand[axis] = -rcCommand[axis];
} }
rcCommand[THROTTLE] = cfg.minthrottle + (int32_t) (cfg.maxthrottle - cfg.minthrottle) * (rcData[THROTTLE] - cfg.mincheck) / (2000 - cfg.mincheck);
rcCommand[THROTTLE] = cfg.minthrottle + (int32_t)(cfg.maxthrottle - cfg.minthrottle) * (rcData[THROTTLE] - cfg.mincheck) / (2000 - cfg.mincheck);
if (headFreeMode) { if (headFreeMode) {
float radDiff = (heading - headFreeModeHold) * 0.0174533f; // where PI/180 ~= 0.0174533
float radDiff = (heading - headFreeModeHold) * M_PI / 180.0f;
float cosDiff = cosf(radDiff); float cosDiff = cosf(radDiff);
float sinDiff = sinf(radDiff); float sinDiff = sinf(radDiff);
int16_t rcCommand_PITCH = rcCommand[PITCH] * cosDiff + rcCommand[ROLL] * sinDiff; int16_t rcCommand_PITCH = rcCommand[PITCH] * cosDiff + rcCommand[ROLL] * sinDiff;
@ -274,7 +264,7 @@ void annexCode(void)
} }
} }
uint16_t readRawRC(uint8_t chan)
uint16_t pwmReadRawRC(uint8_t chan)
{ {
uint16_t data; uint16_t data;
@ -292,12 +282,9 @@ void computeRC(void)
static uint8_t rc4ValuesIndex = 0; static uint8_t rc4ValuesIndex = 0;
uint8_t chan, a; uint8_t chan, a;
#if defined(SBUS)
readSBus();
#endif
rc4ValuesIndex++; rc4ValuesIndex++;
for (chan = 0; chan < 8; chan++) { for (chan = 0; chan < 8; chan++) {
rcData4Values[chan][rc4ValuesIndex % 4] = readRawRC(chan);
rcData4Values[chan][rc4ValuesIndex % 4] = rcReadRawFunc(chan);
rcDataMean[chan] = 0; rcDataMean[chan] = 0;
for (a = 0; a < 4; a++) for (a = 0; a < 4; a++)
rcDataMean[chan] += rcData4Values[chan][a]; rcDataMean[chan] += rcData4Values[chan][a];
@ -324,16 +311,15 @@ void loop(void)
static uint32_t rcTime = 0; static uint32_t rcTime = 0;
static int16_t initialThrottleHold; static int16_t initialThrottleHold;
#if defined(SPEKTRUM)
if (rcFrameComplete)
// this will return false if spektrum is disabled. shrug.
if (spektrumFrameComplete())
computeRC(); computeRC();
#endif
if (currentTime > rcTime) { // 50Hz if (currentTime > rcTime) { // 50Hz
rcTime = currentTime + 20000; rcTime = currentTime + 20000;
#if !(defined(SPEKTRUM) ||defined(BTSERIAL))
computeRC();
#endif
// TODO clean this up. computeRC should handle this check
if (!feature(FEATURE_SPEKTRUM))
computeRC();
// Failsafe routine - added by MIS // Failsafe routine - added by MIS
#if defined(FAILSAFE) #if defined(FAILSAFE)
if (failsafeCnt > (5 * FAILSAVE_DELAY) && armed == 1) { // Stabilize, and set Throttle to specified level if (failsafeCnt > (5 * FAILSAVE_DELAY) && armed == 1) { // Stabilize, and set Throttle to specified level
@ -376,7 +362,7 @@ void loop(void)
} }
} else if (feature(FEATURE_INFLIGHT_ACC_CAL) && (armed == 0 && rcData[YAW] < cfg.mincheck && rcData[PITCH] > cfg.maxcheck && rcData[ROLL] > cfg.maxcheck)) { } else if (feature(FEATURE_INFLIGHT_ACC_CAL) && (armed == 0 && rcData[YAW] < cfg.mincheck && rcData[PITCH] > cfg.maxcheck && rcData[ROLL] > cfg.maxcheck)) {
if (rcDelayCommand == 20) { if (rcDelayCommand == 20) {
if (AccInflightCalibrationMeasurementDone) { //trigger saving into eeprom after landing
if (AccInflightCalibrationMeasurementDone) { // trigger saving into eeprom after landing
AccInflightCalibrationMeasurementDone = 0; AccInflightCalibrationMeasurementDone = 0;
AccInflightCalibrationSavetoEEProm = 1; AccInflightCalibrationSavetoEEProm = 1;
} else { } else {
@ -395,12 +381,10 @@ void loop(void)
} else if (armed) } else if (armed)
armed = 0; armed = 0;
rcDelayCommand = 0; rcDelayCommand = 0;
} else if ((rcData[YAW] < cfg.mincheck || rcData[ROLL] < cfg.mincheck)
&& armed == 1) {
} else if ((rcData[YAW] < cfg.mincheck || rcData[ROLL] < cfg.mincheck) && armed == 1) {
if (rcDelayCommand == 20) if (rcDelayCommand == 20)
armed = 0; // rcDelayCommand = 20 => 20x20ms = 0.4s = time to wait for a specific RC command to be acknowledged armed = 0; // rcDelayCommand = 20 => 20x20ms = 0.4s = time to wait for a specific RC command to be acknowledged
} else if ((rcData[YAW] > cfg.maxcheck || rcData[ROLL] > cfg.maxcheck)
&& rcData[PITCH] < cfg.maxcheck && armed == 0 && calibratingG == 0 && calibratedACC == 1) {
} else if ((rcData[YAW] > cfg.maxcheck || rcData[ROLL] > cfg.maxcheck) && rcData[PITCH] < cfg.maxcheck && armed == 0 && calibratingG == 0 && calibratedACC == 1) {
if (rcDelayCommand == 20) { if (rcDelayCommand == 20) {
armed = 1; armed = 1;
headFreeModeHold = heading; headFreeModeHold = heading;
@ -418,11 +402,11 @@ void loop(void)
} else } else
rcDelayCommand = 0; rcDelayCommand = 0;
} else if (rcData[THROTTLE] > cfg.maxcheck && armed == 0) { } else if (rcData[THROTTLE] > cfg.maxcheck && armed == 0) {
if (rcData[YAW] < cfg.mincheck && rcData[PITCH] < cfg.mincheck) { //throttle=max, yaw=left, pitch=min
if (rcData[YAW] < cfg.mincheck && rcData[PITCH] < cfg.mincheck) { // throttle=max, yaw=left, pitch=min
if (rcDelayCommand == 20) if (rcDelayCommand == 20)
calibratingA = 400; calibratingA = 400;
rcDelayCommand++; rcDelayCommand++;
} else if (rcData[YAW] > cfg.maxcheck && rcData[PITCH] < cfg.mincheck) { //throttle=max, yaw=right, pitch=min
} else if (rcData[YAW] > cfg.maxcheck && rcData[PITCH] < cfg.mincheck) { // throttle=max, yaw=right, pitch=min
if (rcDelayCommand == 20) if (rcDelayCommand == 20)
calibratingM = 1; // MAG calibration request calibratingM = 1; // MAG calibration request
rcDelayCommand++; rcDelayCommand++;
@ -462,7 +446,7 @@ void loop(void)
InflightcalibratingA = 50; InflightcalibratingA = 50;
AccInflightCalibrationArmed = 0; AccInflightCalibrationArmed = 0;
} }
if (rcOptions[BOXPASSTHRU]) { //Use the Passthru Option to activate : Passthru = TRUE Meausrement started, Land and passtrhu = 0 measurement stored
if (rcOptions[BOXPASSTHRU]) { // Use the Passthru Option to activate : Passthru = TRUE Meausrement started, Land and passtrhu = 0 measurement stored
if (!AccInflightCalibrationArmed) { if (!AccInflightCalibrationArmed) {
AccInflightCalibrationArmed = 1; AccInflightCalibrationArmed = 1;
InflightcalibratingA = 50; InflightcalibratingA = 50;
@ -479,7 +463,7 @@ void loop(void)
|| (((rcData[AUX3] < 1300) | (1300 < rcData[AUX3] && rcData[AUX3] < 1700) << 1 | (rcData[AUX3] > 1700) << 2 | (rcData[AUX4] < 1300) << 3 | (1300 < rcData[AUX4] && rcData[AUX4] < 1700) << 4 | (rcData[AUX4] > 1700) << 5) & cfg.activate2[i]); || (((rcData[AUX3] < 1300) | (1300 < rcData[AUX3] && rcData[AUX3] < 1700) << 1 | (rcData[AUX3] > 1700) << 2 | (rcData[AUX4] < 1300) << 3 | (1300 < rcData[AUX4] && rcData[AUX4] < 1700) << 4 | (rcData[AUX4] > 1700) << 5) & cfg.activate2[i]);
} }
//note: if FAILSAFE is disable, failsafeCnt > 5*FAILSAVE_DELAY is always false
// note: if FAILSAFE is disable, failsafeCnt > 5*FAILSAVE_DELAY is always false
if ((rcOptions[BOXACC] || (failsafeCnt > 5 * FAILSAVE_DELAY)) && (sensors(SENSOR_ACC))) { if ((rcOptions[BOXACC] || (failsafeCnt > 5 * FAILSAVE_DELAY)) && (sensors(SENSOR_ACC))) {
// bumpless transfer to Level mode // bumpless transfer to Level mode
if (!accMode) { if (!accMode) {
@ -547,7 +531,7 @@ void loop(void)
} else } else
passThruMode = 0; passThruMode = 0;
} else { // not in rc loop } else { // not in rc loop
static int8_t taskOrder = 0; //never call all function in the same loop, to avoid high delay spikes
static int8_t taskOrder = 0; // never call all function in the same loop, to avoid high delay spikes
switch (taskOrder) { switch (taskOrder) {
case 0: case 0:
taskOrder++; taskOrder++;
@ -570,7 +554,6 @@ void loop(void)
GPS_NewData(); GPS_NewData();
#endif #endif
break; break;
default: default:
taskOrder = 0; taskOrder = 0;
break; break;
@ -578,12 +561,11 @@ void loop(void)
} }
computeIMU(); computeIMU();
// Measure loop rate just afer reading the sensors // Measure loop rate just afer reading the sensors
currentTime = micros(); currentTime = micros();
cycleTime = currentTime - previousTime; cycleTime = currentTime - previousTime;
previousTime = currentTime; previousTime = currentTime;
mpu6050DmpLoop(); mpu6050DmpLoop();
if (sensors(SENSOR_MAG)) { if (sensors(SENSOR_MAG)) {
@ -625,37 +607,38 @@ void loop(void)
GPS_dist = GPS_distanceToHold; GPS_dist = GPS_distanceToHold;
GPS_dir = GPS_directionToHold; GPS_dir = GPS_directionToHold;
} }
radDiff = (GPS_dir - heading) * 0.0174533f;
GPS_angle[ROLL] = constrain(cfg.P8[PIDGPS] * sin(radDiff) * GPS_dist / 10, -cfg.D8[PIDGPS] * 10, +cfg.D8[PIDGPS] * 10); // with P=5.0, a distance of 1 meter = 0.5deg inclination
GPS_angle[PITCH] = constrain(cfg.P8[PIDGPS] * cos(radDiff) * GPS_dist / 10, -cfg.D8[PIDGPS] * 10, +cfg.D8[PIDGPS] * 10); // max inclination = D deg
radDiff = (GPS_dir - heading) * M_PI / 180.0f;
GPS_angle[ROLL] = constrain(cfg.P8[PIDGPS] * sinf(radDiff) * GPS_dist / 10, -cfg.D8[PIDGPS] * 10, +cfg.D8[PIDGPS] * 10); // with P=5.0, a distance of 1 meter = 0.5deg inclination
GPS_angle[PITCH] = constrain(cfg.P8[PIDGPS] * cosf(radDiff) * GPS_dist / 10, -cfg.D8[PIDGPS] * 10, +cfg.D8[PIDGPS] * 10); // max inclination = D deg
} }
} }
//**** PITCH & ROLL & YAW PID ****
// **** PITCH & ROLL & YAW PID ****
for (axis = 0; axis < 3; axis++) { for (axis = 0; axis < 3; axis++) {
if (accMode == 1 && axis < 2) { //LEVEL MODE
if (accMode == 1 && axis < 2) { // LEVEL MODE
// 50 degrees max inclination // 50 degrees max inclination
errorAngle = constrain(2 * rcCommand[axis] - GPS_angle[axis], -500, +500) - angle[axis] + cfg.accTrim[axis]; //16 bits is ok here errorAngle = constrain(2 * rcCommand[axis] - GPS_angle[axis], -500, +500) - angle[axis] + cfg.accTrim[axis]; //16 bits is ok here
#ifdef LEVEL_PDF #ifdef LEVEL_PDF
PTerm = -(int32_t) angle[axis] * cfg.P8[PIDLEVEL] / 100;
PTerm = -(int32_t)angle[axis] * cfg.P8[PIDLEVEL] / 100;
#else #else
PTerm = (int32_t) errorAngle * cfg.P8[PIDLEVEL] / 100; //32 bits is needed for calculation: errorAngle*P8[PIDLEVEL] could exceed 32768 16 bits is ok for result
PTerm = (int32_t)errorAngle * cfg.P8[PIDLEVEL] / 100; //32 bits is needed for calculation: errorAngle*P8[PIDLEVEL] could exceed 32768 16 bits is ok for result
#endif #endif
PTerm = constrain(PTerm, -cfg.D8[PIDLEVEL] * 5, +cfg.D8[PIDLEVEL] * 5); PTerm = constrain(PTerm, -cfg.D8[PIDLEVEL] * 5, +cfg.D8[PIDLEVEL] * 5);
errorAngleI[axis] = constrain(errorAngleI[axis] + errorAngle, -10000, +10000); //WindUp //16 bits is ok here
ITerm = ((int32_t) errorAngleI[axis] * cfg.I8[PIDLEVEL]) >> 12; //32 bits is needed for calculation:10000*I8 could exceed 32768 16 bits is ok for result
} else { //ACRO MODE or YAW axis
error = (int32_t) rcCommand[axis] * 10 * 8 / cfg.P8[axis]; //32 bits is needed for calculation: 500*5*10*8 = 200000 16 bits is ok for result if P8>2 (P>0.2)
errorAngleI[axis] = constrain(errorAngleI[axis] + errorAngle, -10000, +10000); // WindUp // 16 bits is ok here
ITerm = ((int32_t)errorAngleI[axis] * cfg.I8[PIDLEVEL]) >> 12; // 32 bits is needed for calculation:10000*I8 could exceed 32768 16 bits is ok for result
} else { // ACRO MODE or YAW axis
error = (int32_t)rcCommand[axis] * 10 * 8 / cfg.P8[axis]; //32 bits is needed for calculation: 500*5*10*8 = 200000 16 bits is ok for result if P8>2 (P>0.2)
error -= gyroData[axis]; error -= gyroData[axis];
PTerm = rcCommand[axis]; PTerm = rcCommand[axis];
errorGyroI[axis] = constrain(errorGyroI[axis] + error, -16000, +16000); //WindUp //16 bits is ok here
errorGyroI[axis] = constrain(errorGyroI[axis] + error, -16000, +16000); // WindUp // 16 bits is ok here
if (abs(gyroData[axis]) > 640) if (abs(gyroData[axis]) > 640)
errorGyroI[axis] = 0; errorGyroI[axis] = 0;
ITerm = (errorGyroI[axis] / 125 * cfg.I8[axis]) >> 6; // 16 bits is ok here 16000/125 = 128 ; 128*250 = 32000 ITerm = (errorGyroI[axis] / 125 * cfg.I8[axis]) >> 6; // 16 bits is ok here 16000/125 = 128 ; 128*250 = 32000
} }
PTerm -= (int32_t) gyroData[axis] * dynP8[axis] / 10 / 8; // 32 bits is needed for calculation
PTerm -= (int32_t)gyroData[axis] * dynP8[axis] / 10 / 8; // 32 bits is needed for calculation
delta = gyroData[axis] - lastGyro[axis]; //16 bits is ok here, the dif between 2 consecutive gyro reads is limited to 800 delta = gyroData[axis] - lastGyro[axis]; //16 bits is ok here, the dif between 2 consecutive gyro reads is limited to 800
lastGyro[axis] = gyroData[axis]; lastGyro[axis] = gyroData[axis];
@ -663,7 +646,7 @@ void loop(void)
delta2[axis] = delta1[axis]; delta2[axis] = delta1[axis];
delta1[axis] = delta; delta1[axis] = delta;
DTerm = ((int32_t) deltaSum * dynD8[axis]) >> 5; //32 bits is needed for calculation
DTerm = ((int32_t)deltaSum * dynD8[axis]) >> 5; //32 bits is needed for calculation
axisPID[axis] = PTerm + ITerm - DTerm; axisPID[axis] = PTerm + ITerm - DTerm;
} }

11
src/mw.h

@ -60,7 +60,7 @@
//#define MMSERVOGIMBAL // Active Output Moving Average Function for Servos Gimbal //#define MMSERVOGIMBAL // Active Output Moving Average Function for Servos Gimbal
//#define MMSERVOGIMBALVECTORLENGHT 32 // Lenght of Moving Average Vector //#define MMSERVOGIMBALVECTORLENGHT 32 // Lenght of Moving Average Vector
#define VERSION 203
#define VERSION 20
// Syncronized with GUI. Only exception is mixer > 11, which is always returned as 11 during serialization. // Syncronized with GUI. Only exception is mixer > 11, which is always returned as 11 during serialization.
typedef enum MultiType typedef enum MultiType
@ -142,6 +142,10 @@ typedef struct config_t {
int16_t accZero[3]; int16_t accZero[3];
int16_t magZero[3]; int16_t magZero[3];
int16_t accTrim[2]; int16_t accTrim[2];
// sensor-related stuff
uint8_t acc_lpf_factor; // Set the Low Pass Filter factor for ACC. Increasing this value would reduce ACC noise (visible in GUI), but would increase ACC lag time. Zero = no filter
uint16_t gyro_lpf; // mpuX050 LPF setting
uint32_t gyro_smoothing_factor; // How much to smoothen with per axis (32bit value with Roll, Pitch, Yaw in bits 24, 16, 8 respectively uint32_t gyro_smoothing_factor; // How much to smoothen with per axis (32bit value with Roll, Pitch, Yaw in bits 24, 16, 8 respectively
uint8_t activate1[CHECKBOXITEMS]; uint8_t activate1[CHECKBOXITEMS];
@ -154,6 +158,7 @@ typedef struct config_t {
// Radio/ESC-related configuration // Radio/ESC-related configuration
uint8_t rcmap[8]; // mapping of radio channels to internal RPYTA+ order uint8_t rcmap[8]; // mapping of radio channels to internal RPYTA+ order
uint8_t deadband; // introduce a deadband around the stick center. Must be greater than zero uint8_t deadband; // introduce a deadband around the stick center. Must be greater than zero
uint8_t spektrum_hires; // spektrum high-resolution y/n (1024/2048bit)
uint16_t midrc; // Some radios have not a neutral point centered on 1500. can be changed here uint16_t midrc; // Some radios have not a neutral point centered on 1500. can be changed here
uint16_t mincheck; // minimum rc end uint16_t mincheck; // minimum rc end
uint16_t maxcheck; // maximum rc end uint16_t maxcheck; // maximum rc end
@ -278,6 +283,10 @@ void featureClear(uint32_t mask);
void featureClearAll(void); void featureClearAll(void);
uint32_t featureMask(void); uint32_t featureMask(void);
// spektrum
void spektrumInit(void);
bool spektrumFrameComplete(void);
// cli // cli
void cliProcess(void); void cliProcess(void);

30
src/sensors.c

@ -45,6 +45,8 @@ void sensorsAutodetect(void)
} }
// this is safe because either mpu6050 or mpu3050 sets it, and in case of fail, none do. // this is safe because either mpu6050 or mpu3050 sets it, and in case of fail, none do.
gyro.init(); gyro.init();
// todo: this is driver specific :(
mpu3050Config(cfg.gyro_lpf);
} }
uint16_t batteryAdcToVoltage(uint16_t src) uint16_t batteryAdcToVoltage(uint16_t src)
@ -59,6 +61,7 @@ void batteryInit(void)
uint8_t i; uint8_t i;
uint32_t voltage = 0; uint32_t voltage = 0;
// average up some voltage readings
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
voltage += adcGetBattery(); voltage += adcGetBattery();
delay(10); delay(10);
@ -68,8 +71,8 @@ void batteryInit(void)
// autodetect cell count, going from 2S..6S // autodetect cell count, going from 2S..6S
for (i = 2; i < 6; i++) { for (i = 2; i < 6; i++) {
if (voltage < i * cfg.vbatmaxcellvoltage)
break;
if (voltage < i * cfg.vbatmaxcellvoltage)
break;
} }
batteryCellCount = i; batteryCellCount = i;
batteryWarningVoltage = i * cfg.vbatmincellvoltage; // 3.3V per cell minimum, configurable in CLI batteryWarningVoltage = i * cfg.vbatmincellvoltage; // 3.3V per cell minimum, configurable in CLI
@ -102,12 +105,12 @@ static void ACC_Common(void)
} }
calibratingA--; calibratingA--;
} }
if (feature(FEATURE_INFLIGHT_ACC_CAL)) { if (feature(FEATURE_INFLIGHT_ACC_CAL)) {
static int32_t b[3]; static int32_t b[3];
static int16_t accZero_saved[3] = { 0, 0, 0 }; static int16_t accZero_saved[3] = { 0, 0, 0 };
static int16_t accTrim_saved[2] = { 0, 0 }; static int16_t accTrim_saved[2] = { 0, 0 };
//Saving old zeropoints before measurement
// Saving old zeropoints before measurement
if (InflightcalibratingA == 50) { if (InflightcalibratingA == 50) {
accZero_saved[ROLL] = cfg.accZero[ROLL]; accZero_saved[ROLL] = cfg.accZero[ROLL];
accZero_saved[PITCH] = cfg.accZero[PITCH]; accZero_saved[PITCH] = cfg.accZero[PITCH];
@ -127,7 +130,7 @@ static void ACC_Common(void)
accADC[axis] = 0; accADC[axis] = 0;
cfg.accZero[axis] = 0; cfg.accZero[axis] = 0;
} }
//all values are measured
// all values are measured
if (InflightcalibratingA == 1) { if (InflightcalibratingA == 1) {
AccInflightCalibrationActive = 0; AccInflightCalibrationActive = 0;
AccInflightCalibrationMeasurementDone = 1; AccInflightCalibrationMeasurementDone = 1;
@ -142,7 +145,7 @@ static void ACC_Common(void)
InflightcalibratingA--; InflightcalibratingA--;
} }
// Calculate average, shift Z down by acc_1G and store values in EEPROM at end of calibration // Calculate average, shift Z down by acc_1G and store values in EEPROM at end of calibration
if (AccInflightCalibrationSavetoEEProm == 1) { //the copter is landed, disarmed and the combo has been done again
if (AccInflightCalibrationSavetoEEProm == 1) { // the copter is landed, disarmed and the combo has been done again
AccInflightCalibrationSavetoEEProm = 0; AccInflightCalibrationSavetoEEProm = 0;
cfg.accZero[ROLL] = b[ROLL] / 50; cfg.accZero[ROLL] = b[ROLL] / 50;
cfg.accZero[PITCH] = b[PITCH] / 50; cfg.accZero[PITCH] = b[PITCH] / 50;
@ -158,7 +161,6 @@ static void ACC_Common(void)
accADC[YAW] -= cfg.accZero[YAW]; accADC[YAW] -= cfg.accZero[YAW];
} }
void ACC_getADC(void) void ACC_getADC(void)
{ {
acc.read(accADC); acc.read(accADC);
@ -171,12 +173,11 @@ static uint32_t baroDeadline = 0;
static uint8_t baroState = 0; static uint8_t baroState = 0;
static uint16_t baroUT = 0; static uint16_t baroUT = 0;
static uint32_t baroUP = 0; static uint32_t baroUP = 0;
static int16_t baroTemp = 0;
void Baro_update(void) void Baro_update(void)
{ {
int32_t pressure; int32_t pressure;
if (currentTime < baroDeadline) if (currentTime < baroDeadline)
return; return;
@ -199,9 +200,8 @@ void Baro_update(void)
break; break;
case 3: case 3:
baroUP = bmp085_get_up(); baroUP = bmp085_get_up();
baroTemp = bmp085_get_temperature(baroUT);
bmp085_get_temperature(baroUT);
pressure = bmp085_get_pressure(baroUP); pressure = bmp085_get_pressure(baroUP);
BaroAlt = (1.0f - pow(pressure / 101325.0f, 0.190295f)) * 4433000.0f; // centimeter BaroAlt = (1.0f - pow(pressure / 101325.0f, 0.190295f)) * 4433000.0f; // centimeter
baroState = 0; baroState = 0;
baroDeadline += 5000; baroDeadline += 5000;
@ -214,7 +214,7 @@ static void GYRO_Common(void)
static int16_t previousGyroADC[3] = { 0, 0, 0 }; static int16_t previousGyroADC[3] = { 0, 0, 0 };
static int32_t g[3]; static int32_t g[3];
uint8_t axis; uint8_t axis;
#if defined MMGYRO #if defined MMGYRO
// Moving Average Gyros by Magnetron1 // Moving Average Gyros by Magnetron1
//--------------------------------------------------- //---------------------------------------------------
@ -242,7 +242,7 @@ static void GYRO_Common(void)
calibratingG--; calibratingG--;
} }
#ifdef MMGYRO
#ifdef MMGYRO
mediaMobileGyroIDX = ++mediaMobileGyroIDX % MMGYROVECTORLENGTH; mediaMobileGyroIDX = ++mediaMobileGyroIDX % MMGYROVECTORLENGTH;
for (axis = 0; axis < 3; axis++) { for (axis = 0; axis < 3; axis++) {
gyroADC[axis] -= gyroZero[axis]; gyroADC[axis] -= gyroZero[axis];
@ -329,9 +329,7 @@ void Mag_getADC(void)
} }
calibratingM = 0; calibratingM = 0;
} }
magADC[ROLL] = magADC[ROLL] * magCal[ROLL];
magADC[PITCH] = magADC[PITCH] * magCal[PITCH];
magADC[YAW] = magADC[YAW] * magCal[YAW];
if (magInit) { // we apply offset only once mag calibration is done if (magInit) { // we apply offset only once mag calibration is done
magADC[ROLL] -= cfg.magZero[ROLL]; magADC[ROLL] -= cfg.magZero[ROLL];
magADC[PITCH] -= cfg.magZero[PITCH]; magADC[PITCH] -= cfg.magZero[PITCH];

90
src/spektrum.c

@ -0,0 +1,90 @@
#include "board.h"
#include "mw.h"
// driver for spektrum satellite receiver / sbus using UART2 (freeing up more motor outputs for stuff)
#define SPEK_MAX_CHANNEL 7
#define SPEK_FRAME_SIZE 16
static uint8_t spek_chan_shift;
static uint8_t spek_chan_mask;
static bool rcFrameComplete = false;
static bool spekDataIncoming = false;
volatile uint8_t spekFrame[SPEK_FRAME_SIZE];
static void spektrumDataReceive(uint16_t c);
void spektrumInit(void)
{
if (cfg.spektrum_hires) {
// 11 bit frames
spek_chan_shift = 3;
spek_chan_mask = 0x07;
} else {
// 10 bit frames
spek_chan_shift = 2;
spek_chan_mask = 0x03;
}
uart2Init(115200, spektrumDataReceive);
}
// UART2 Receive ISR callback
static void spektrumDataReceive(uint16_t c)
{
uint32_t spekTime;
static uint32_t spekTimeLast, spekTimeInterval;
static uint8_t spekFramePosition;
spekDataIncoming = true;
spekTime = micros();
spekTimeInterval = spekTime - spekTimeLast;
spekTimeLast = spekTime;
if (spekTimeInterval > 5000)
spekFramePosition = 0;
spekFrame[spekFramePosition] = (uint8_t)c;
if (spekFramePosition == SPEK_FRAME_SIZE - 1) {
rcFrameComplete = true;
#if defined(FAILSAFE)
if(failsafeCnt > 20)
failsafeCnt -= 20;
else
failsafeCnt = 0; // clear FailSafe counter
#endif
} else {
spekFramePosition++;
}
}
bool spektrumFrameComplete(void)
{
return rcFrameComplete;
}
static const uint8_t spekRcChannelMap[SPEK_MAX_CHANNEL] = {1, 2, 3, 0, 4, 5, 6};
uint16_t spektrumReadRawRC(uint8_t chan)
{
uint16_t data;
static uint32_t spekChannelData[SPEK_MAX_CHANNEL];
uint8_t b;
if (rcFrameComplete) {
for (b = 3; b < SPEK_FRAME_SIZE; b += 2) {
uint8_t spekChannel = 0x0F & (spekFrame[b - 1] >> spek_chan_shift);
if (spekChannel < SPEK_MAX_CHANNEL)
spekChannelData[spekChannel] = ((uint32_t)(spekFrame[b - 1] & spek_chan_mask) << 8) + spekFrame[b];
}
rcFrameComplete = false;
}
if (chan >= SPEK_MAX_CHANNEL || !spekDataIncoming) {
data = 1500;
} else {
if (cfg.spektrum_hires)
data = 988 + (spekChannelData[spekRcChannelMap[chan]] >> 1); // 2048 mode
else
data = 988 + spekChannelData[spekRcChannelMap[chan]]; // 1024 mode
}
return data;
}
Loading…
Cancel
Save