Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • danc/MicroCART
  • snawerdt/MicroCART_17-18
  • bbartels/MicroCART_17-18
  • jonahu/MicroCART
4 results
Show changes
Showing
with 2480 additions and 0 deletions
/**
* || ____ _ __
* +------+ / __ )(_) /_______________ _____ ___
* | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2011-2012 Bitcraze AB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, in version 3.
*
* This program 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* nvicconf.c - Interrupt priority configuration
*
* The STM32 has 16 priorities to choose from where 0 is the
* highest priority. They are now configured using no groups.
*
* Interrupt functions that call FreeRTOS FromISR functions
* must have a interrupt number 10 and above which is currently
* set by configMAX_SYSCALL_INTERRUPT_PRIORITY.
*/
#ifndef NVIC_CONF_H_
#define NVIC_CONF_H_
/*
Interrupt priority organisation in Crazyflie:
In Cortex-M low priority number is higher priority. Hence priority 0 is the
highest priority interrupt and priority 15 the lowest (STM32 implements
4 priority bits)
Interrupts bellow MAX_SYSCALL_INTERRUPT_PRIORITY cannot call any RTOS
functions! They should be handled like some kind of softdevice, running above
the OS.
4 Interrupt level are defined
- NVIC_LOW_PRI
- NVIC_MID_PRI
- NVIC_HIGH_PRI
- NVIC_VERY_HIGH_PRI
The aim is to simplify interrupt handling and to document why any special case
is required.
15 -
14 -
13 - NVIC_LOW_PRI
12 - NVIC_ADC_PRI
11 - NVIC_RADIO_PRI
10 - NVIC_MID_PRI
9 -
8 -
7 - NVIC_HIGH_PRI
6 - NVIC_VERY_HIGH_PRI
5 - <-- MAX_SYSCALL_INTERRUPT_PRIORITY
4 ! NVIC_I2C_PRI_LOW NVIC_TRACE_TIM_PRI --- Does not call any RTOS function
3 ! NVIC_I2C_PRI_HIGH
2 !
1 !
0 !
*/
// Standard interrupt levels
#define NVIC_LOW_PRI 13
#define NVIC_MID_PRI 10
#define NVIC_HIGH_PRI 7
#define NVIC_VERY_HIGH_PRI 7
// Priorities used for Crazyflie
#define NVIC_I2C_HIGH_PRI 3
#define NVIC_I2C_LOW_PRI 4
#define NVIC_TRACE_TIM_PRI 4
#define NVIC_UART_PRI 6
// Priorities for Crazyflie 2.0
#define NVIC_RADIO_PRI 11
#define NVIC_ADC_PRI 12
#define NVIC_CPPM_PRI 14
#define NVIC_SYSLINK_PRI 5
// Priorities for external interrupts
#define EXTI0_PRI NVIC_LOW_PRI
#define EXTI1_PRI NVIC_LOW_PRI
#define EXTI2_PRI NVIC_LOW_PRI
#define EXTI3_PRI NVIC_LOW_PRI
#define EXTI4_PRI NVIC_SYSLINK_PRI // this serves the syslink UART
#define EXTI9_5_PRI NVIC_LOW_PRI
#define EXTI15_10_PRI NVIC_MID_PRI // this serves the decks and sensors
#endif /* NVIC_CONF_H_ */
/**
******************************************************************************
* @file Project/STM32F4xx_StdPeriph_Templates/stm32f4xx_conf.h
* @author MCD Application Team
* @version V1.3.0
* @date 13-November-2013
* @brief Library configuration file.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2013 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F4xx_CONF_H
#define __STM32F4xx_CONF_H
/* Includes ------------------------------------------------------------------*/
/* Uncomment the line below to enable peripheral header file inclusion */
#include "stm32f4xx_adc.h"
#include "stm32f4xx_crc.h"
#include "stm32f4xx_dbgmcu.h"
#include "stm32f4xx_dma.h"
#include "stm32f4xx_exti.h"
#include "stm32f4xx_flash.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_i2c.h"
#include "stm32f4xx_iwdg.h"
#include "stm32f4xx_pwr.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_rtc.h"
#include "stm32f4xx_sdio.h"
#include "stm32f4xx_spi.h"
#include "stm32f4xx_syscfg.h"
#include "stm32f4xx_tim.h"
#include "stm32f4xx_usart.h"
#include "stm32f4xx_wwdg.h"
#include "stm32f4xx_misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
#if defined (STM32F429_439xx)
#include "stm32f4xx_cryp.h"
#include "stm32f4xx_hash.h"
#include "stm32f4xx_rng.h"
#include "stm32f4xx_can.h"
#include "stm32f4xx_dac.h"
#include "stm32f4xx_dcmi.h"
#include "stm32f4xx_dma2d.h"
#include "stm32f4xx_fmc.h"
#include "stm32f4xx_ltdc.h"
#include "stm32f4xx_sai.h"
#endif /* STM32F429_439xx */
#if defined (STM32F427_437xx)
#include "stm32f4xx_cryp.h"
#include "stm32f4xx_hash.h"
#include "stm32f4xx_rng.h"
#include "stm32f4xx_can.h"
#include "stm32f4xx_dac.h"
#include "stm32f4xx_dcmi.h"
#include "stm32f4xx_dma2d.h"
#include "stm32f4xx_fmc.h"
#include "stm32f4xx_sai.h"
#endif /* STM32F427_437xx */
#if defined (STM32F40_41xxx)
#include "stm32f4xx_cryp.h"
#include "stm32f4xx_hash.h"
#include "stm32f4xx_rng.h"
#include "stm32f4xx_can.h"
#include "stm32f4xx_dac.h"
#include "stm32f4xx_dcmi.h"
#include "stm32f4xx_fsmc.h"
#endif /* STM32F40_41xxx */
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* If an external clock source is used, then the value of the following define
should be set to the value of the external clock source, else, if no external
clock is used, keep this define commented */
/*#define I2S_EXTERNAL_CLOCK_VAL 12288000 */ /* Value of the external clock in Hz */
/* Uncomment the line below to expanse the "assert_param" macro in the
Standard Peripheral Library drivers code */
/* #define USE_FULL_ASSERT 1 */
/* 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)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0)
#endif /* USE_FULL_ASSERT */
#endif /* __STM32F4xx_CONF_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/**
* || ____ _ __
* +------+ / __ )(_) /_______________ _____ ___
* | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2011-2012 Bitcraze AB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, in version 3.
*
* This program 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* stm32fxxx.h - Includes correct stm32 include file.
*/
#ifndef STM32FXXX_H_
#define STM32FXXX_H_
#if defined (STM32F40_41xxx)
#include "stm32f4xx.h"
#elif defined (STM32F10X_MD)
#include "stm32f10x.h"
#else
#warning "Don't know which stm32fxxx header file to include"
#endif
#endif /* STM32FXXX_H_ */
/**
* || ____ _ __
* +------+ / __ )(_) /_______________ _____ ___
* | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2011-2012 Bitcraze AB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, in version 3.
*
* This program 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* trace.h - ITM trace implementation/definition
*/
#ifndef __TRACE_H__
#define __TRACE_H__
#define configUSE_TRACE_FACILITY 1
// ITM useful macros
#ifndef ITM_NO_OVERFLOW
#define ITM_SEND(CH, DATA) ((uint32_t*)0xE0000000)[CH] = DATA
#else
#define ITM_SEND(CH, DATA) while(((uint32_t*)0xE0000000)[CH] == 0);\
((uint32_t*)0xE0000000)[CH] = DATA
#endif
// Send 4 first chatacters of task name to ITM port 1
#define traceTASK_SWITCHED_IN() ITM_SEND(1, *((uint32_t*)pxCurrentTCB->pcTaskName))
// Systick value on port 2
#define traceTASK_INCREMENT_TICK(xTickCount) ITM_SEND(2, xTickCount)
// Queue trace on port 3
#define ITM_QUEUE_SEND 0x0100
#define ITM_QUEUE_FAILED 0x0200
#define ITM_BLOCKING_ON_QUEUE_RECEIVE 0x0300
#define ITM_BLOCKING_ON_QUEUE_SEND 0x0400
#define traceQUEUE_SEND(xQueue) ITM_SEND(3, ITM_QUEUE_SEND | ((xQUEUE *) xQueue)->uxQueueNumber)
#define traceQUEUE_SEND_FAILED(xQueue) ITM_SEND(3, ITM_QUEUE_FAILED | ((xQUEUE *) xQueue)->uxQueueNumber)
#define traceBLOCKING_ON_QUEUE_RECEIVE(xQueue) ITM_SEND(3, ITM_BLOCKING_ON_QUEUE_RECEIVE | ((xQUEUE *) xQueue)->uxQueueNumber)
#define traceBLOCKING_ON_QUEUE_SEND(xQueue) ITM_SEND(3, ITM_BLOCKING_ON_QUEUE_SEND | ((xQUEUE *) xQueue)->uxQueueNumber)
#endif
/*
* || ____ _ __
* +------+ / __ )(_) /_______________ _____ ___
* | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2015 Bitcraze AB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, in version 3.
*
* This program 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* deck_analog.c - Arduino-compatible analog input implementation
*/
#include "deck.h"
#include "stm32fxxx.h"
static uint32_t stregResolution;
static uint32_t adcRange;
void adcInit(void)
{
/*
* Note: This function initializes only ADC2, and only for single channel, single conversion mode. No DMA, no interrupts, no bells or whistles.
*/
/* Note that this de-initializes registers for all ADCs (ADCx) */
ADC_DeInit();
/* Define ADC init structures */
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
/* Populates structures with reset values */
ADC_StructInit(&ADC_InitStructure);
ADC_CommonStructInit(&ADC_CommonInitStructure);
/* enable ADC clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
/* init ADCs in independent mode, div clock by two */
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; /* HCLK = 168MHz, PCLK2 = 84MHz, ADCCLK = 42MHz (when using ADC_Prescaler_Div2) */
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
/* Init ADC2: 12bit, single-conversion. For Arduino compatibility set 10bit */
analogReadResolution(12);
/* Enable ADC2 */
ADC_Cmd(ADC2, ENABLE);
}
static uint16_t analogReadChannel(uint8_t channel)
{
/* According to datasheet, minimum sampling time for 12-bit conversion is 15 cycles. */
ADC_RegularChannelConfig(ADC2, channel, 1, ADC_SampleTime_15Cycles);
/* Start the conversion */
ADC_SoftwareStartConv(ADC2);
/* Wait until conversion completion */
while(ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC) == RESET);
/* Get the conversion value */
return ADC_GetConversionValue(ADC2);
}
uint16_t analogRead(const deckPin_t pin)
{
assert_param(deckGPIOMapping[pin.id].adcCh > -1);
/* Now set the GPIO pin to analog mode. */
/* Enable clock for the peripheral of the pin.*/
RCC_AHB1PeriphClockCmd(deckGPIOMapping[pin.id].periph, ENABLE);
/* Populate structure with RESET values. */
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_StructInit(&GPIO_InitStructure);
/* Initialise the GPIO pin to analog mode. */
GPIO_InitStructure.GPIO_Pin = deckGPIOMapping[pin.id].pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
/* TODO: Any settling time before we can do ADC after init on the GPIO pin? */
GPIO_Init(deckGPIOMapping[pin.id].port, &GPIO_InitStructure);
/* Read the appropriate ADC channel. */
return analogReadChannel((uint8_t)deckGPIOMapping[pin.id].adcCh);
}
void analogReference(uint8_t type)
{
/*
* TODO: We should probably support the Arduino EXTERNAL type here.
* TODO: Figure out which voltage reference to compensate with.
*/
assert_param(type == 0 /* DEFAULT */);
}
void analogReadResolution(uint8_t bits)
{
ADC_InitTypeDef ADC_InitStructure;
assert_param((bits >= 6) && (bits <= 12));
adcRange = 1 << bits;
switch (bits)
{
case 12: stregResolution = ADC_Resolution_12b; break;
case 10: stregResolution = ADC_Resolution_10b; break;
case 8: stregResolution = ADC_Resolution_8b; break;
case 6: stregResolution = ADC_Resolution_6b; break;
default: stregResolution = ADC_Resolution_12b; break;
}
/* Init ADC2 witch new resolution */
ADC_InitStructure.ADC_Resolution = stregResolution;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = 0;
ADC_InitStructure.ADC_ExternalTrigConv = 0;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC2, &ADC_InitStructure);
}
float analogReadVoltage(const deckPin_t pin)
{
float voltage;
voltage = analogRead(pin) * VREF / adcRange;
return voltage;
}
/*
* || ____ _ __
* +------+ / __ )(_) /_______________ _____ ___
* | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2015 Bitcraze AB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, in version 3.
*
* This program 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* deck_constants.c - Constants for the Deck API
*/
#include "deck.h"
/* Mapping between Deck Pin number, real GPIO and ADC channel */
deckGPIOMapping_t deckGPIOMapping[13] = {
{.periph= RCC_AHB1Periph_GPIOC, .port= GPIOC, .pin=GPIO_Pin_11, .adcCh=-1}, /* RX1 */
{.periph= RCC_AHB1Periph_GPIOC, .port= GPIOC, .pin=GPIO_Pin_10, .adcCh=-1}, /* TX1 */
{.periph= RCC_AHB1Periph_GPIOB, .port= GPIOB, .pin=GPIO_Pin_7, .adcCh=-1}, /* SDA */
{.periph= RCC_AHB1Periph_GPIOB, .port= GPIOB, .pin=GPIO_Pin_6, .adcCh=-1}, /* SCL */
{.periph= RCC_AHB1Periph_GPIOB, .port= GPIOB, .pin=GPIO_Pin_8, .adcCh=-1}, /* IO1 */
{.periph= RCC_AHB1Periph_GPIOB, .port= GPIOB, .pin=GPIO_Pin_5, .adcCh=-1}, /* IO2 */
{.periph= RCC_AHB1Periph_GPIOB, .port= GPIOB, .pin=GPIO_Pin_4, .adcCh=-1}, /* IO3 */
{.periph= RCC_AHB1Periph_GPIOC, .port= GPIOC, .pin=GPIO_Pin_12, .adcCh=-1}, /* IO4 */
{.periph= RCC_AHB1Periph_GPIOA, .port= GPIOA, .pin=GPIO_Pin_2, .adcCh=ADC_Channel_2}, /* TX2 */
{.periph= RCC_AHB1Periph_GPIOA, .port= GPIOA, .pin=GPIO_Pin_3, .adcCh=ADC_Channel_3}, /* RX2 */
{.periph= RCC_AHB1Periph_GPIOA, .port= GPIOA, .pin=GPIO_Pin_5, .adcCh=ADC_Channel_5}, /* SCK */
{.periph= RCC_AHB1Periph_GPIOA, .port= GPIOA, .pin=GPIO_Pin_6, .adcCh=ADC_Channel_6}, /* MISO */
{.periph= RCC_AHB1Periph_GPIOA, .port= GPIOA, .pin=GPIO_Pin_7, .adcCh=ADC_Channel_7}, /* MOSI */
};
// Pin definitions
const deckPin_t DECK_GPIO_RX1 = {.id=0};
const deckPin_t DECK_GPIO_TX1 = {.id=1};
const deckPin_t DECK_GPIO_SDA = {.id=2};
const deckPin_t DECK_GPIO_SCL = {.id=3};
const deckPin_t DECK_GPIO_IO1 = {.id=4};
const deckPin_t DECK_GPIO_IO2 = {.id=5};
const deckPin_t DECK_GPIO_IO3 = {.id=6};
const deckPin_t DECK_GPIO_IO4 = {.id=7};
const deckPin_t DECK_GPIO_TX2 = {.id=8};
const deckPin_t DECK_GPIO_RX2 = {.id=9};
const deckPin_t DECK_GPIO_SCK = {.id=10};
const deckPin_t DECK_GPIO_MISO = {.id=11};
const deckPin_t DECK_GPIO_MOSI = {.id=12};
/*
* || ____ _ __
* +------+ / __ )(_) /_______________ _____ ___
* | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2015 Bitcraze AB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, in version 3.
*
* This program 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* digital.c - Deck-API digital IO implementation
*/
#include "deck.h"
#include "stm32fxxx.h"
void pinMode(const deckPin_t pin, const uint32_t mode)
{
RCC_AHB1PeriphClockCmd(deckGPIOMapping[pin.id].periph, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure = {0};
GPIO_InitStructure.GPIO_Pin = deckGPIOMapping[pin.id].pin;
GPIO_InitStructure.GPIO_Mode = (mode == OUTPUT) ? GPIO_Mode_OUT:GPIO_Mode_IN;
if (mode == OUTPUT) GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
if (mode == INPUT_PULLUP) GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
if (mode == INPUT_PULLDOWN) GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_Init(deckGPIOMapping[pin.id].port, &GPIO_InitStructure);
}
void digitalWrite(const deckPin_t pin, const uint32_t val)
{
BitAction action = Bit_RESET;
if (val) {
action = Bit_SET;
}
GPIO_WriteBit(deckGPIOMapping[pin.id].port, deckGPIOMapping[pin.id].pin, action);
}
int digitalRead(const deckPin_t pin)
{
int val = GPIO_ReadInputDataBit(deckGPIOMapping[pin.id].port, deckGPIOMapping[pin.id].pin);
return (val==Bit_SET)?HIGH:LOW;
}
/*
* || ____ _ __
* +------+ / __ )(_) /_______________ _____ ___
* | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2015 Bitcraze AB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, in version 3.
*
* This program 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* deck_spi.c - Deck-API SPI communication implementation
*/
#include "deck.h"
/*ST includes */
#include "stm32fxxx.h"
#include "config.h"
#include "FreeRTOS.h"
#include "semphr.h"
#include "cfassert.h"
#include "config.h"
#include "nvicconf.h"
#define SPI SPI1
#define SPI_CLK RCC_APB2Periph_SPI1
#define SPI_CLK_INIT RCC_APB2PeriphClockCmd
#define SPI_IRQ_HANDLER SPI1_IRQHandler
#define SPI_IRQn SPI1_IRQn
#define SPI_DMA_IRQ_PRIO (NVIC_HIGH_PRI)
#define SPI_DMA DMA2
#define SPI_DMA_CLK RCC_AHB1Periph_DMA2
#define SPI_DMA_CLK_INIT RCC_AHB1PeriphClockCmd
#define SPI_TX_DMA_STREAM DMA2_Stream5
#define SPI_TX_DMA_IRQ DMA2_Stream5_IRQn
#define SPI_TX_DMA_IRQHandler DMA2_Stream5_IRQHandler
#define SPI_TX_DMA_CHANNEL DMA_Channel_3
#define SPI_TX_DMA_FLAG_TCIF DMA_FLAG_TCIF5
#define SPI_RX_DMA_STREAM DMA2_Stream0
#define SPI_RX_DMA_IRQ DMA2_Stream0_IRQn
#define SPI_RX_DMA_IRQHandler DMA2_Stream0_IRQHandler
#define SPI_RX_DMA_CHANNEL DMA_Channel_3
#define SPI_RX_DMA_FLAG_TCIF DMA_FLAG_TCIF0
#define SPI_SCK_PIN GPIO_Pin_5
#define SPI_SCK_GPIO_PORT GPIOA
#define SPI_SCK_GPIO_CLK RCC_AHB1Periph_GPIOA
#define SPI_SCK_SOURCE GPIO_PinSource5
#define SPI_SCK_AF GPIO_AF_SPI1
#define SPI_MISO_PIN GPIO_Pin_6
#define SPI_MISO_GPIO_PORT GPIOA
#define SPI_MISO_GPIO_CLK RCC_AHB1Periph_GPIOA
#define SPI_MISO_SOURCE GPIO_PinSource6
#define SPI_MISO_AF GPIO_AF_SPI1
#define SPI_MOSI_PIN GPIO_Pin_7
#define SPI_MOSI_GPIO_PORT GPIOA
#define SPI_MOSI_GPIO_CLK RCC_AHB1Periph_GPIOA
#define SPI_MOSI_SOURCE GPIO_PinSource7
#define SPI_MOSI_AF GPIO_AF_SPI1
#define DUMMY_BYTE 0xA5
static bool isInit = false;
static SemaphoreHandle_t txComplete;
static SemaphoreHandle_t rxComplete;
static SemaphoreHandle_t spiMutex;
static void spiDMAInit();
static void spiConfigureWithSpeed(uint16_t baudRatePrescaler);
void spiBegin(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// binary semaphores created using xSemaphoreCreateBinary() are created in a state
// such that the the semaphore must first be 'given' before it can be 'taken'
txComplete = xSemaphoreCreateBinary();
rxComplete = xSemaphoreCreateBinary();
spiMutex = xSemaphoreCreateMutex();
/*!< Enable the SPI clock */
SPI_CLK_INIT(SPI_CLK, ENABLE);
/*!< Enable GPIO clocks */
RCC_AHB1PeriphClockCmd(SPI_SCK_GPIO_CLK | SPI_MISO_GPIO_CLK |
SPI_MOSI_GPIO_CLK, ENABLE);
/*!< Enable DMA Clocks */
SPI_DMA_CLK_INIT(SPI_DMA_CLK, ENABLE);
/*!< SPI pins configuration *************************************************/
/*!< Connect SPI pins to AF5 */
GPIO_PinAFConfig(SPI_SCK_GPIO_PORT, SPI_SCK_SOURCE, SPI_SCK_AF);
GPIO_PinAFConfig(SPI_MISO_GPIO_PORT, SPI_MISO_SOURCE, SPI_MISO_AF);
GPIO_PinAFConfig(SPI_MOSI_GPIO_PORT, SPI_MOSI_SOURCE, SPI_MOSI_AF);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
#ifdef DECK_SPI_MODE3
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
#else
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
#endif
/*!< SPI SCK pin configuration */
GPIO_InitStructure.GPIO_Pin = SPI_SCK_PIN;
GPIO_Init(SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
/*!< SPI MOSI pin configuration */
GPIO_InitStructure.GPIO_Pin = SPI_MOSI_PIN;
GPIO_Init(SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
/*!< SPI MISO pin configuration */
GPIO_InitStructure.GPIO_Pin = SPI_MISO_PIN;
GPIO_Init(SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
/*!< SPI DMA Initialization */
spiDMAInit();
/*!< SPI configuration */
spiConfigureWithSpeed(SPI_BAUDRATE_2MHZ);
isInit = true;
}
static void spiDMAInit()
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure DMA Initialization Structure */
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable ;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull ;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single ;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t) (&(SPI->DR)) ;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_BufferSize = 0; // set later
DMA_InitStructure.DMA_Memory0BaseAddr = 0; // set later
// Configure TX DMA
DMA_InitStructure.DMA_Channel = SPI_TX_DMA_CHANNEL;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_Cmd(SPI_TX_DMA_STREAM,DISABLE);
DMA_Init(SPI_TX_DMA_STREAM, &DMA_InitStructure);
// Configure RX DMA
DMA_InitStructure.DMA_Channel = SPI_RX_DMA_CHANNEL;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_Cmd(SPI_RX_DMA_STREAM,DISABLE);
DMA_Init(SPI_RX_DMA_STREAM, &DMA_InitStructure);
// Configure interrupts
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_HIGH_PRI;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannel = SPI_TX_DMA_IRQ;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = SPI_RX_DMA_IRQ;
NVIC_Init(&NVIC_InitStructure);
}
static void spiConfigureWithSpeed(uint16_t baudRatePrescaler)
{
SPI_InitTypeDef SPI_InitStructure;
SPI_I2S_DeInit(SPI);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
#ifdef DECK_SPI_MODE3
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
#else
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
#endif
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 0; // Not used
SPI_InitStructure.SPI_BaudRatePrescaler = baudRatePrescaler;
SPI_Init(SPI, &SPI_InitStructure);
}
bool spiTest(void)
{
return isInit;
}
bool spiExchange(size_t length, const uint8_t * data_tx, uint8_t * data_rx)
{
ASSERT_DMA_SAFE(data_tx);
ASSERT_DMA_SAFE(data_rx);
// DMA already configured, just need to set memory addresses
SPI_TX_DMA_STREAM->M0AR = (uint32_t)data_tx;
SPI_TX_DMA_STREAM->NDTR = length;
SPI_RX_DMA_STREAM->M0AR = (uint32_t)data_rx;
SPI_RX_DMA_STREAM->NDTR = length;
// Enable SPI DMA Interrupts
DMA_ITConfig(SPI_TX_DMA_STREAM, DMA_IT_TC, ENABLE);
DMA_ITConfig(SPI_RX_DMA_STREAM, DMA_IT_TC, ENABLE);
// Clear DMA Flags
DMA_ClearFlag(SPI_TX_DMA_STREAM, DMA_FLAG_FEIF5|DMA_FLAG_DMEIF5|DMA_FLAG_TEIF5|DMA_FLAG_HTIF5|DMA_FLAG_TCIF5);
DMA_ClearFlag(SPI_RX_DMA_STREAM, DMA_FLAG_FEIF0|DMA_FLAG_DMEIF0|DMA_FLAG_TEIF0|DMA_FLAG_HTIF0|DMA_FLAG_TCIF0);
// Enable DMA Streams
DMA_Cmd(SPI_TX_DMA_STREAM,ENABLE);
DMA_Cmd(SPI_RX_DMA_STREAM,ENABLE);
// Enable SPI DMA requests
SPI_I2S_DMACmd(SPI, SPI_I2S_DMAReq_Tx, ENABLE);
SPI_I2S_DMACmd(SPI, SPI_I2S_DMAReq_Rx, ENABLE);
// Enable peripheral
SPI_Cmd(SPI, ENABLE);
// Wait for completion
bool result = (xSemaphoreTake(txComplete, portMAX_DELAY) == pdTRUE)
&& (xSemaphoreTake(rxComplete, portMAX_DELAY) == pdTRUE);
// Disable peripheral
SPI_Cmd(SPI, DISABLE);
return result;
}
void spiBeginTransaction(uint16_t baudRatePrescaler)
{
xSemaphoreTake(spiMutex, portMAX_DELAY);
spiConfigureWithSpeed(baudRatePrescaler);
}
void spiEndTransaction()
{
xSemaphoreGive(spiMutex);
}
void __attribute__((used)) SPI_TX_DMA_IRQHandler(void)
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
// Stop and cleanup DMA stream
DMA_ITConfig(SPI_TX_DMA_STREAM, DMA_IT_TC, DISABLE);
DMA_ClearITPendingBit(SPI_TX_DMA_STREAM, SPI_TX_DMA_FLAG_TCIF);
// Clear stream flags
DMA_ClearFlag(SPI_TX_DMA_STREAM,SPI_TX_DMA_FLAG_TCIF);
// Disable SPI DMA requests
SPI_I2S_DMACmd(SPI, SPI_I2S_DMAReq_Tx, DISABLE);
// Disable streams
DMA_Cmd(SPI_TX_DMA_STREAM,DISABLE);
// Give the semaphore, allowing the SPI transaction to complete
xSemaphoreGiveFromISR(txComplete, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken)
{
portYIELD();
}
}
void __attribute__((used)) SPI_RX_DMA_IRQHandler(void)
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
// Stop and cleanup DMA stream
DMA_ITConfig(SPI_RX_DMA_STREAM, DMA_IT_TC, DISABLE);
DMA_ClearITPendingBit(SPI_RX_DMA_STREAM, SPI_RX_DMA_FLAG_TCIF);
// Clear stream flags
DMA_ClearFlag(SPI_RX_DMA_STREAM,SPI_RX_DMA_FLAG_TCIF);
// Disable SPI DMA requests
SPI_I2S_DMACmd(SPI, SPI_I2S_DMAReq_Rx, DISABLE);
// Disable streams
DMA_Cmd(SPI_RX_DMA_STREAM,DISABLE);
// Give the semaphore, allowing the SPI transaction to complete
xSemaphoreGiveFromISR(rxComplete, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken)
{
portYIELD();
}
}
/*
* || ____ _ __
* +------+ / __ )(_) /_______________ _____ ___
* | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2015 Bitcraze AB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, in version 3.
*
* This program 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* deck_spi3.c - Deck-API SPI3 communication implementation. Mainly used so that
* the uSD-deck can log e.g. the loco deck.
*/
#include "deck.h"
/*ST includes */
#include "stm32fxxx.h"
#include "config.h"
#include "FreeRTOS.h"
#include "semphr.h"
#include "cfassert.h"
#include "config.h"
#include "nvicconf.h"
// Alternative SPI
#define SPI SPI3
#define SPI_CLK RCC_APB1Periph_SPI3
#define SPI_CLK_INIT RCC_APB1PeriphClockCmd
#define SPI_IRQ_HANDLER SPI3_IRQHandler
#define SPI_IRQn SPI3_IRQn
#define SPI_DMA_IRQ_PRIO (NVIC_HIGH_PRI)
#define SPI_DMA DMA1
#define SPI_DMA_CLK RCC_AHB1Periph_DMA1
#define SPI_DMA_CLK_INIT RCC_AHB1PeriphClockCmd
#define SPI_TX_DMA_STREAM DMA1_Stream7
#define SPI_TX_DMA_IRQ DMA1_Stream7_IRQn
#define SPI_TX_DMA_IRQHandler DMA1_Stream7_IRQHandler
#define SPI_TX_DMA_CHANNEL DMA_Channel_0
#define SPI_TX_DMA_FLAG_TCIF DMA_FLAG_TCIF7
#define SPI_RX_DMA_STREAM DMA1_Stream0
#define SPI_RX_DMA_IRQ DMA1_Stream0_IRQn
#define SPI_RX_DMA_IRQHandler DMA1_Stream0_IRQHandler
#define SPI_RX_DMA_CHANNEL DMA_Channel_0
#define SPI_RX_DMA_FLAG_TCIF DMA_FLAG_TCIF0
#define SPI_SCK_PIN GPIO_Pin_10
#define SPI_SCK_GPIO_PORT GPIOC
#define SPI_SCK_GPIO_CLK RCC_AHB1Periph_GPIOC
#define SPI_SCK_SOURCE GPIO_PinSource10
#define SPI_SCK_AF GPIO_AF_SPI3
#define SPI_MISO_PIN GPIO_Pin_11
#define SPI_MISO_GPIO_PORT GPIOC
#define SPI_MISO_GPIO_CLK RCC_AHB1Periph_GPIOC
#define SPI_MISO_SOURCE GPIO_PinSource11
#define SPI_MISO_AF GPIO_AF_SPI3
#define SPI_MOSI_PIN GPIO_Pin_12
#define SPI_MOSI_GPIO_PORT GPIOC
#define SPI_MOSI_GPIO_CLK RCC_AHB1Periph_GPIOC
#define SPI_MOSI_SOURCE GPIO_PinSource12
#define SPI_MOSI_AF GPIO_AF_SPI3
#define DUMMY_BYTE 0xA5
static bool isInit = false;
static SemaphoreHandle_t txComplete;
static SemaphoreHandle_t rxComplete;
static SemaphoreHandle_t spiMutex;
// Mainly used of uSD deck that is patched to use alternative SPI
static void spi3DMAInit();
static void spi3ConfigureWithSpeed(uint16_t baudRatePrescaler);
void spi3Begin(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// binary semaphores created using xSemaphoreCreateBinary() are created in a state
// such that the the semaphore must first be 'given' before it can be 'taken'
txComplete = xSemaphoreCreateBinary();
rxComplete = xSemaphoreCreateBinary();
spiMutex = xSemaphoreCreateMutex();
/*!< Enable the SPI clock */
SPI_CLK_INIT(SPI_CLK, ENABLE);
/*!< Enable GPIO clocks */
RCC_AHB1PeriphClockCmd(SPI_SCK_GPIO_CLK | SPI_MISO_GPIO_CLK |
SPI_MOSI_GPIO_CLK, ENABLE);
/*!< Enable DMA Clocks */
SPI_DMA_CLK_INIT(SPI_DMA_CLK, ENABLE);
/*!< SPI pins configuration *************************************************/
/*!< Connect SPI pins to AF5 */
GPIO_PinAFConfig(SPI_SCK_GPIO_PORT, SPI_SCK_SOURCE, SPI_SCK_AF);
GPIO_PinAFConfig(SPI_MISO_GPIO_PORT, SPI_MISO_SOURCE, SPI_MISO_AF);
GPIO_PinAFConfig(SPI_MOSI_GPIO_PORT, SPI_MOSI_SOURCE, SPI_MOSI_AF);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
/*!< SPI SCK pin configuration */
GPIO_InitStructure.GPIO_Pin = SPI_SCK_PIN;
GPIO_Init(SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
/*!< SPI MOSI pin configuration */
GPIO_InitStructure.GPIO_Pin = SPI_MOSI_PIN;
GPIO_Init(SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
/*!< SPI MISO pin configuration */
GPIO_InitStructure.GPIO_Pin = SPI_MISO_PIN;
GPIO_Init(SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
/*!< SPI DMA Initialization */
spi3DMAInit();
/*!< SPI configuration */
spi3ConfigureWithSpeed(SPI_BAUDRATE_2MHZ);
isInit = true;
}
static void spi3DMAInit()
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure DMA Initialization Structure */
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable ;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull ;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single ;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t) (&(SPI->DR)) ;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_BufferSize = 0; // set later
DMA_InitStructure.DMA_Memory0BaseAddr = 0; // set later
// Configure TX DMA
DMA_InitStructure.DMA_Channel = SPI_TX_DMA_CHANNEL;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_Cmd(SPI_TX_DMA_STREAM,DISABLE);
DMA_Init(SPI_TX_DMA_STREAM, &DMA_InitStructure);
// Configure RX DMA
DMA_InitStructure.DMA_Channel = SPI_RX_DMA_CHANNEL;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_Cmd(SPI_RX_DMA_STREAM,DISABLE);
DMA_Init(SPI_RX_DMA_STREAM, &DMA_InitStructure);
// Configure interrupts
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_HIGH_PRI;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannel = SPI_TX_DMA_IRQ;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = SPI_RX_DMA_IRQ;
NVIC_Init(&NVIC_InitStructure);
}
static void spi3ConfigureWithSpeed(uint16_t baudRatePrescaler)
{
SPI_InitTypeDef SPI_InitStructure;
SPI_I2S_DeInit(SPI);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 0; // Not used
SPI_InitStructure.SPI_BaudRatePrescaler = baudRatePrescaler;
SPI_Init(SPI, &SPI_InitStructure);
}
bool spi3Test(void)
{
return isInit;
}
bool spi3Exchange(size_t length, const uint8_t * data_tx, uint8_t * data_rx)
{
ASSERT_DMA_SAFE(data_tx);
ASSERT_DMA_SAFE(data_rx);
// DMA already configured, just need to set memory addresses
SPI_TX_DMA_STREAM->M0AR = (uint32_t)data_tx;
SPI_TX_DMA_STREAM->NDTR = length;
SPI_RX_DMA_STREAM->M0AR = (uint32_t)data_rx;
SPI_RX_DMA_STREAM->NDTR = length;
// Enable SPI DMA Interrupts
DMA_ITConfig(SPI_TX_DMA_STREAM, DMA_IT_TC, ENABLE);
DMA_ITConfig(SPI_RX_DMA_STREAM, DMA_IT_TC, ENABLE);
// Clear DMA Flags
DMA_ClearFlag(SPI_TX_DMA_STREAM, DMA_FLAG_FEIF7|DMA_FLAG_DMEIF7|DMA_FLAG_TEIF7|DMA_FLAG_HTIF7|DMA_FLAG_TCIF7);
DMA_ClearFlag(SPI_RX_DMA_STREAM, DMA_FLAG_FEIF0|DMA_FLAG_DMEIF0|DMA_FLAG_TEIF0|DMA_FLAG_HTIF0|DMA_FLAG_TCIF0);
// Enable DMA Streams
DMA_Cmd(SPI_TX_DMA_STREAM,ENABLE);
DMA_Cmd(SPI_RX_DMA_STREAM,ENABLE);
// Enable SPI DMA requests
SPI_I2S_DMACmd(SPI, SPI_I2S_DMAReq_Tx, ENABLE);
SPI_I2S_DMACmd(SPI, SPI_I2S_DMAReq_Rx, ENABLE);
// Enable peripheral
SPI_Cmd(SPI, ENABLE);
// Wait for completion
bool result = (xSemaphoreTake(txComplete, portMAX_DELAY) == pdTRUE)
&& (xSemaphoreTake(rxComplete, portMAX_DELAY) == pdTRUE);
// Disable peripheral
SPI_Cmd(SPI, DISABLE);
return result;
}
void spi3BeginTransaction(uint16_t baudRatePrescaler)
{
xSemaphoreTake(spiMutex, portMAX_DELAY);
spi3ConfigureWithSpeed(baudRatePrescaler);
}
void spi3EndTransaction()
{
xSemaphoreGive(spiMutex);
}
#ifdef USDDECK_USE_ALT_PINS_AND_SPI
void __attribute__((used)) SPI_TX_DMA_IRQHandler(void)
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
// Stop and cleanup DMA stream
DMA_ITConfig(SPI_TX_DMA_STREAM, DMA_IT_TC, DISABLE);
DMA_ClearITPendingBit(SPI_TX_DMA_STREAM, SPI_TX_DMA_FLAG_TCIF);
// Clear stream flags
DMA_ClearFlag(SPI_TX_DMA_STREAM,SPI_TX_DMA_FLAG_TCIF);
// Disable SPI DMA requests
SPI_I2S_DMACmd(SPI, SPI_I2S_DMAReq_Tx, DISABLE);
// Disable streams
DMA_Cmd(SPI_TX_DMA_STREAM,DISABLE);
// Give the semaphore, allowing the SPI transaction to complete
xSemaphoreGiveFromISR(txComplete, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken)
{
portYIELD();
}
}
void __attribute__((used)) SPI_RX_DMA_IRQHandler(void)
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
// Stop and cleanup DMA stream
DMA_ITConfig(SPI_RX_DMA_STREAM, DMA_IT_TC, DISABLE);
DMA_ClearITPendingBit(SPI_RX_DMA_STREAM, SPI_RX_DMA_FLAG_TCIF);
// Clear stream flags
DMA_ClearFlag(SPI_RX_DMA_STREAM,SPI_RX_DMA_FLAG_TCIF);
// Disable SPI DMA requests
SPI_I2S_DMACmd(SPI, SPI_I2S_DMAReq_Rx, DISABLE);
// Disable streams
DMA_Cmd(SPI_RX_DMA_STREAM,DISABLE);
// Give the semaphore, allowing the SPI transaction to complete
xSemaphoreGiveFromISR(rxComplete, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken)
{
portYIELD();
}
}
#endif
/**
* || ____ _ __
* +------+ / __ )(_) /_______________ _____ ___
* | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2015 Bitcraze AB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, in version 3.
*
* This program 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* deck.c - Deck subsystem main entry points
*/
#define DEBUG_MODULE "DECK_CORE"
#include <string.h>
#include "deck.h"
#include "deck_memory.h"
#include "debug.h"
#ifdef DEBUG
#define DECK_CORE_DBG_PRINT(fmt, ...) DEBUG_PRINT(fmt, ## __VA_ARGS__)
#else
#define DECK_CORE_DBG_PRINT(...)
#endif
extern void deckInfoInit();
void deckInit()
{
deckDriverCount();
deckInfoInit();
deckMemoryInit();
int nDecks;
int i;
nDecks = deckCount();
DEBUG_PRINT("%d deck(s) found\n", nDecks);
for (i=0; i<nDecks; i++) {
DeckInfo *deck = deckInfo(i);
if (deck->driver->init) {
if (deck->driver->name) {
DEBUG_PRINT("Calling INIT on driver %s for deck %i\n", deck->driver->name, i);
} else {
DEBUG_PRINT("Calling INIT for deck %i\n", i);
}
deck->driver->init(deck);
}
}
}
bool deckTest()
{
bool pass = true;
int nDecks;
int i;
nDecks = deckCount();
for (i=0; i<nDecks; i++) {
DeckInfo *deck = deckInfo(i);
if (deck->driver->test) {
if (deck->driver->test()) {
DEBUG_PRINT("Deck %i test [OK].\n", i);
} else {
DEBUG_PRINT("Deck %i test [FAIL].\n", i);
pass = false;
}
}
}
return pass;
}
/**
* || ____ _ __
* +------+ / __ )(_) /_______________ _____ ___
* | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2011-2012 Bitcraze AB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, in version 3.
*
* This program 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* deck_drivers.c - Deck drivers loading and handling
*/
#define DEBUG_MODULE "DECK_DRIVERS"
#include <stdlib.h>
#include <string.h>
#include "deck.h"
#include "debug.h"
#ifdef DEBUG
#define DECK_DRV_DBG_PRINT(fmt, ...) DEBUG_PRINT(fmt, ## __VA_ARGS__)
#else
#define DECK_DRV_DBG_PRINT(...)
#endif
/* Symbols set by the linker script */
extern const struct deck_driver * _deckDriver_start;
extern const struct deck_driver * _deckDriver_stop;
static const struct deck_driver ** drivers;
static int driversLen;
// Init the toc access variables. Lazy initialisation: it is going to be done
// the first time any api function is called.
static void deckdriversInit() {
static bool init = false;
if (!init) {
int i;
drivers = &_deckDriver_start;
driversLen = &_deckDriver_stop - &_deckDriver_start;
init = true;
DECK_DRV_DBG_PRINT("Found %d drivers\n", driversLen);
for (i=0; i<driversLen; i++) {
if (drivers[i]->name) {
DECK_DRV_DBG_PRINT("VID:PID %02x:%02x (%s)\n", drivers[i]->vid, drivers[i]->pid, drivers[i]->name);
} else {
DECK_DRV_DBG_PRINT("VID:PID %02x:%02x\n", drivers[i]->vid, drivers[i]->pid);
}
}
}
}
int deckDriverCount() {
deckdriversInit();
return driversLen;
}
const struct deck_driver* deckGetDriver(int i) {
deckdriversInit();
if (i<driversLen) {
return drivers[i];
}
return NULL;
}
const DeckDriver* deckFindDriverByVidPid(uint8_t vid, uint8_t pid) {
int i;
deckdriversInit();
for (i=0; i<driversLen; i++) {
if ((vid == drivers[i]->vid) && (pid == drivers[i]->pid)) {
return drivers[i];
}
}
return NULL;
}
const DeckDriver* deckFindDriverByName(char* name) {
int i;
deckdriversInit();
for (i=0; i<driversLen; i++) {
if (!strcmp(name, drivers[i]->name)) {
return drivers[i];
}
}
return NULL;
}
/**
* || ____ _ __
* +------+ / __ )(_) /_______________ _____ ___
* | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2015 Bitcraze AB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, in version 3.
*
* This program 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* deck_ow.c - Functions to decode the decks oneWire memory content
*/
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define DEBUG_MODULE "DECK_INFO"
#include "deck.h"
#include "ow.h"
#include "crc32.h"
#include "debug.h"
#include "static_mem.h"
#ifdef DEBUG
#define DECK_INFO_DBG_PRINT(fmt, ...) DEBUG_PRINT(fmt, ## __VA_ARGS__)
#else
#define DECK_INFO_DBG_PRINT(...)
#endif
static int count = 0;
NO_DMA_CCM_SAFE_ZERO_INIT static DeckInfo deckInfos[DECK_MAX_COUNT];
static void enumerateDecks(void);
static void checkPeriphAndGpioConflicts(void);
static void scanRequiredSystemProperties(void);
static StateEstimatorType requiredEstimator = anyEstimator;
static bool registerRequiredEstimator(StateEstimatorType estimator);
static bool requiredLowInterferenceRadioMode = false;
#ifndef DECK_FORCE
#define DECK_FORCE
#endif
#define xstr(s) str(s)
#define str(s) #s
static char* deck_force = xstr(DECK_FORCE);
void deckInfoInit()
{
static bool isInit = false;
if (isInit) return;
enumerateDecks();
checkPeriphAndGpioConflicts();
scanRequiredSystemProperties();
isInit = true;
}
int deckCount(void)
{
return count;
}
DeckInfo * deckInfo(int i)
{
if (i<count) {
return &deckInfos[i];
}
return NULL;
}
// Dummy driver for decks that do not have a driver implemented
static const DeckDriver dummyDriver;
#ifndef IGNORE_OW_DECKS
static const DeckDriver * findDriver(DeckInfo *deck)
{
char name[30];
const DeckDriver *driver = &dummyDriver;
deckTlvGetString(&deck->tlv, DECK_INFO_NAME, name, 30);
if (deck->vid) {
driver = deckFindDriverByVidPid(deck->vid, deck->pid);
} else if (strlen(name)>0) {
driver = deckFindDriverByName(name);
}
if (driver == NULL)
driver = &dummyDriver;
return driver;
}
#endif
void printDeckInfo(DeckInfo *info)
{
char name[30] = "NoName";
char rev[10] = "NoRev";
if (deckTlvHasElement(&info->tlv, DECK_INFO_NAME)) {
deckTlvGetString(&info->tlv, DECK_INFO_NAME, name, 30);
}
if (deckTlvHasElement(&info->tlv, DECK_INFO_REVISION)) {
deckTlvGetString(&info->tlv, DECK_INFO_REVISION, rev, 10);
}
DECK_INFO_DBG_PRINT("Deck %02x:%02x %s (Rev. %s)\n", info->vid, info->pid, name, rev);
DECK_INFO_DBG_PRINT("Used pin: %08x\n", (unsigned int)info->usedPins);
if (info->driver == &dummyDriver) {
DEBUG_PRINT("Warning! No driver found for deck.\n");
} else {
DECK_INFO_DBG_PRINT("Driver implements: [ %s%s]\n",
info->driver->init?"init ":"", info->driver->test?"test ":"");
}
}
#ifndef IGNORE_OW_DECKS
static bool infoDecode(DeckInfo * info)
{
uint8_t crcHeader;
uint8_t crcTlv;
if (info->header != DECK_INFO_HEADER_ID) {
DEBUG_PRINT("Memory error: wrong header ID\n");
return false;
}
crcHeader = crc32CalculateBuffer(info->raw, DECK_INFO_HEADER_SIZE);
if(info->crc != crcHeader) {
DEBUG_PRINT("Memory error: incorrect header CRC\n");
return false;
}
if(info->raw[DECK_INFO_TLV_VERSION_POS] != DECK_INFO_TLV_VERSION) {
DEBUG_PRINT("Memory error: incorrect TLV version\n");
return false;
}
crcTlv = crc32CalculateBuffer(&info->raw[DECK_INFO_TLV_VERSION_POS], info->raw[DECK_INFO_TLV_LENGTH_POS]+2);
if(crcTlv != info->raw[DECK_INFO_TLV_DATA_POS + info->raw[DECK_INFO_TLV_LENGTH_POS]]) {
DEBUG_PRINT("Memory error: incorrect TLV CRC %x!=%x\n", (unsigned int)crcTlv,
info->raw[DECK_INFO_TLV_DATA_POS + info->raw[DECK_INFO_TLV_LENGTH_POS]]);
return false;
}
info->tlv.data = &info->raw[DECK_INFO_TLV_DATA_POS];
info->tlv.length = info->raw[DECK_INFO_TLV_LENGTH_POS];
return true;
}
#endif
static void enumerateDecks(void)
{
uint8_t nDecks = 0;
bool noError = true;
owInit();
if (owScan(&nDecks))
{
DECK_INFO_DBG_PRINT("Found %d deck memor%s.\n", nDecks, nDecks>1?"ies":"y");
} else {
DEBUG_PRINT("Error scanning for deck memories, "
"no deck drivers will be initialised\n");
nDecks = 0;
}
#ifndef IGNORE_OW_DECKS
for (int i = 0; i < nDecks; i++)
{
DECK_INFO_DBG_PRINT("Enumerating deck %i\n", i);
if (owRead(i, 0, sizeof(deckInfos[0].raw), (uint8_t *)&deckInfos[i]))
{
if (infoDecode(&deckInfos[i]))
{
deckInfos[i].driver = findDriver(&deckInfos[i]);
printDeckInfo(&deckInfos[i]);
} else {
#ifdef DEBUG
DEBUG_PRINT("Deck %i has corrupt OW memory. "
"Ignoring the deck in DEBUG mode.\n", i);
deckInfos[i].driver = &dummyDriver;
#else
DEBUG_PRINT("Deck %i has corrupt OW memory. "
"No driver will be initialized!\n", i);
noError = false;
#endif
}
}
else
{
DEBUG_PRINT("Reading deck nr:%d [FAILED]. "
"No driver will be initialized!\n", i);
noError = false;
}
}
#else
DEBUG_PRINT("Ignoring all OW decks because of compile flag.\n");
nDecks = 0;
#endif
// Add build-forced driver
if (strlen(deck_force) > 0) {
DEBUG_PRINT("DECK_FORCE=%s found\n", deck_force);
//split deck_force into multiple, separated by colons, if available
char delim[] = ":";
char temp_deck_force[strlen(deck_force) + 1];
strcpy(temp_deck_force, deck_force);
char * token = strtok(temp_deck_force, delim);
while (token) {
deck_force = token;
const DeckDriver *driver = deckFindDriverByName(deck_force);
if (!driver) {
DEBUG_PRINT("WARNING: compile-time forced driver %s not found\n", deck_force);
} else if (driver->init || driver->test) {
if (nDecks <= DECK_MAX_COUNT)
{
nDecks++;
deckInfos[nDecks - 1].driver = driver;
DEBUG_PRINT("compile-time forced driver %s added\n", deck_force);
} else {
DEBUG_PRINT("WARNING: No room for compile-time forced driver\n");
}
}
token = strtok(NULL, delim);
}
}
if (noError) {
count = nDecks;
}
return;
}
static void checkPeriphAndGpioConflicts(void)
{
bool noError = true;
uint32_t usedPeriph = 0;
uint32_t usedGpio = 0;
for (int i = 0; i < count; i++)
{
if (usedPeriph & deckInfos[i].driver->usedPeriph) {
DEBUG_PRINT("ERROR: Driver Periph usage conflicts with a "
"previously enumerated deck driver. No decks will be "
"initialized!\n");
noError = false;
}
if (usedGpio & deckInfos[i].driver->usedGpio) {
DEBUG_PRINT("ERROR: Driver Gpio usage conflicts with a "
"previously enumerated deck driver. No decks will be "
"initialized!\n");
noError = false;
}
usedPeriph |= deckInfos[i].driver->usedPeriph;
usedGpio |= deckInfos[i].driver->usedGpio;
}
if (!noError) {
count = 0;
}
}
/****** Key/value area handling ********/
static int findType(TlvArea *tlv, int type) {
int pos = 0;
while (pos < tlv->length) {
if (tlv->data[pos] == type) {
return pos;
} else {
pos += tlv->data[pos+1]+2;
}
}
return -1;
}
bool deckTlvHasElement(TlvArea *tlv, int type) {
return findType(tlv, type) >= 0;
}
int deckTlvGetString(TlvArea *tlv, int type, char *string, int length) {
int pos = findType(tlv, type);
int strlength = 0;
if (pos >= 0) {
strlength = tlv->data[pos+1];
if (strlength > (length-1)) {
strlength = length-1;
}
memcpy(string, &tlv->data[pos+2], strlength);
string[strlength] = '\0';
return strlength;
} else {
string[0] = '\0';
return -1;
}
}
char* deckTlvGetBuffer(TlvArea *tlv, int type, int *length) {
int pos = findType(tlv, type);
if (pos >= 0) {
*length = tlv->data[pos+1];
return (char*) &tlv->data[pos+2];
}
return NULL;
}
void deckTlvGetTlv(TlvArea *tlv, int type, TlvArea *output) {
output->length = 0;
output->data = (uint8_t *)deckTlvGetBuffer(tlv, type, &output->length);
}
static void scanRequiredSystemProperties(void)
{
bool isError = false;
for (int i = 0; i < count; i++)
{
isError = isError || registerRequiredEstimator(deckInfos[i].driver->requiredEstimator);
requiredLowInterferenceRadioMode |= deckInfos[i].driver->requiredLowInterferenceRadioMode;
}
if (isError) {
count = 0;
}
}
static bool registerRequiredEstimator(StateEstimatorType estimator)
{
bool isError = false;
if (anyEstimator != estimator)
{
if (anyEstimator == requiredEstimator)
{
requiredEstimator = estimator;
}
else
{
if (requiredEstimator != estimator) {
isError = true;
DEBUG_PRINT("WARNING: Two decks require different estimators\n");
}
}
}
return isError;
}
StateEstimatorType deckGetRequiredEstimator()
{
return requiredEstimator;
}
bool deckGetRequiredLowInterferenceRadioMode()
{
return requiredLowInterferenceRadioMode;
}
/**
* ,---------, ____ _ __
* | ,-^-, | / __ )(_) /_______________ _____ ___
* | ( O ) | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* | / ,--´ | / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* +------` /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2021 Bitcraze AB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, in version 3.
*
* This program 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
* deck_memory.c - implements functionality for reading and writing deck memory
* using the memory subsystem, including updating firmware
* and binary data in decks.
*
*/
#include <string.h>
#include "deck_memory.h"
#include "deck_core.h"
#include "mem.h"
#include "test_support.h"
static const uint32_t DECK_MEM_MAX_SIZE = 0x10000000;
static uint32_t handleMemGetSize(void) { return DECK_MEM_MAX_SIZE * (DECK_MAX_COUNT + 1); }
TESTABLE_STATIC bool handleMemRead(const uint32_t memAddr, const uint8_t readLen, uint8_t* buffer);
TESTABLE_STATIC bool handleMemWrite(const uint32_t memAddr, const uint8_t writeLen, const uint8_t* buffer);
static const MemoryHandlerDef_t memoryDef = {
.type = MEM_TYPE_DECK_MEM,
.getSize = handleMemGetSize,
.read = handleMemRead,
.write = handleMemWrite,
};
static const uint8_t VERSION = 1;
static const int DECK_MEMORY_INFO_SIZE = 0x20;
static const int OFFS_BITFIELD = 0x00;
static const int OFFS_REQ_HASH = 0x01;
static const int OFFS_REQ_LEN = 0x05;
static const int OFFS_BASE_ADDR = 0x09;
static const int OFFS_NAME = 0x0D;
static const int NAME_LEN_EX_ZERO_TREM = 18;
static const uint8_t MASK_IS_VALID = 1;
static const uint8_t MASK_IS_STARTED = 2;
static const uint8_t MASK_SUPPORTS_READ = 4;
static const uint8_t MASK_SUPPORTS_WRITE = 8;
static const uint8_t MASK_SUPPORTS_UPGRADE = 16;
static const uint8_t MASK_UPGRADE_REQUIRED = 32;
static const uint8_t MASK_BOOTLOADER_ACTIVE = 64;
static uint8_t populateBitfield(const DeckMemDef_t* memDef) {
uint8_t result = MASK_IS_VALID;
const uint8_t properties = memDef->properties();
if (properties & DECK_MEMORY_MASK_STARTED) {
result |= MASK_IS_STARTED;
}
if (properties & DECK_MEMORY_MASK_UPGRADE_REQUIRED) {
result |= MASK_UPGRADE_REQUIRED;
}
if (properties & DECK_MEMORY_MASK_BOOT_LOADER_ACTIVE) {
result |= MASK_BOOTLOADER_ACTIVE;
}
if (memDef->read) {
result |= MASK_SUPPORTS_READ;
}
if (memDef->write) {
result |= MASK_SUPPORTS_WRITE;
}
if (memDef->supportsUpgrade) {
result |= MASK_SUPPORTS_UPGRADE;
}
return result;
}
static void populateDeckMemoryInfo(uint8_t buffer[], const uint8_t deckNr) {
DeckInfo* info = deckInfo(deckNr);
memset(buffer, 0, DECK_MEMORY_INFO_SIZE);
const DeckMemDef_t* deckMemDef = info->driver->memoryDef;
if (deckMemDef) {
uint32_t baseAddress = (deckNr + 1) * DECK_MEM_MAX_SIZE;
buffer[OFFS_BITFIELD] = populateBitfield(deckMemDef);
memcpy(&buffer[OFFS_REQ_HASH], &deckMemDef->requiredHash, 4);
memcpy(&buffer[OFFS_REQ_LEN], &deckMemDef->requiredSize, 4);
memcpy(&buffer[OFFS_BASE_ADDR], &baseAddress, 4);
strncpy((char*)&buffer[OFFS_NAME], info->driver->name, NAME_LEN_EX_ZERO_TREM);
}
}
static bool handleInfoSectionRead(const uint32_t memAddr, const uint8_t readLen, uint8_t* buffer, const int nrOfDecks) {
uint32_t index = 0;
uint8_t bytesLeft = readLen;
memset(buffer, 0, readLen);
// First byte is the version
if (0 == (memAddr + index) && bytesLeft > 0) {
buffer[index] = VERSION;
index++;
bytesLeft--;
}
// Deck memory infos
while (bytesLeft > 0) {
int deckNr = (memAddr + index - 1) / DECK_MEMORY_INFO_SIZE;
if (deckNr >= nrOfDecks) {
break;
}
uint8_t deckMemoryInfo[DECK_MEMORY_INFO_SIZE];
populateDeckMemoryInfo(deckMemoryInfo, deckNr);
int startAddrOfThisInfo = deckNr * DECK_MEMORY_INFO_SIZE + 1;
int firstByteToUse = memAddr + index - startAddrOfThisInfo;
int bytesToUse = DECK_MEMORY_INFO_SIZE - firstByteToUse;
if (bytesLeft < bytesToUse) {
bytesToUse = bytesLeft;
}
memcpy(buffer + index, (uint8_t*)(&deckMemoryInfo) + firstByteToUse, bytesToUse);
bytesLeft -= bytesToUse;
index += bytesToUse;
}
return true;
}
static bool handleDeckSectionRead(const uint32_t memAddr, const uint8_t readLen, uint8_t* buffer, const int deckNr) {
bool result = false;
const DeckInfo* info = deckInfo(deckNr);
const DeckMemDef_t* deckMemDef = info->driver->memoryDef;
if (deckMemDef) {
if (deckMemDef->read) {
uint32_t baseAddress = (deckNr + 1) * DECK_MEM_MAX_SIZE;
uint32_t deckAddress = memAddr - baseAddress;
result = deckMemDef->read(deckAddress, readLen, buffer);
}
}
return result;
}
static bool handleDeckSectionWrite(const uint32_t memAddr, const uint8_t writeLen, const uint8_t* buffer, const int deckNr) {
bool result = false;
const DeckInfo* info = deckInfo(deckNr);
const DeckMemDef_t* deckMemDef = info->driver->memoryDef;
if (deckMemDef) {
if (deckMemDef->write) {
uint32_t baseAddress = (deckNr + 1) * DECK_MEM_MAX_SIZE;
uint32_t deckAddress = memAddr - baseAddress;
result = deckMemDef->write(deckAddress, writeLen, buffer);
}
}
return result;
}
TESTABLE_STATIC bool handleMemRead(const uint32_t memAddr, const uint8_t readLen, uint8_t* buffer) {
bool result = false;
int nrOfDecks = deckCount();
// Assume the buffer is fully within one section. It may not be true, but unlikely
// and not an important use case to support
const uint32_t section = memAddr / DECK_MEM_MAX_SIZE;
if (section == 0) {
result = handleInfoSectionRead(memAddr, readLen, buffer, nrOfDecks);
} else {
int deckNr = section - 1;
if (deckNr < nrOfDecks) {
result = handleDeckSectionRead(memAddr, readLen, buffer, deckNr);
}
}
return result;
}
TESTABLE_STATIC bool handleMemWrite(const uint32_t memAddr, const uint8_t writeLen, const uint8_t* buffer) {
bool result = false;
// Assume the buffer is fully within one section. It may not be true, but unlikely
// and not an important use case to support
const uint32_t section = memAddr / DECK_MEM_MAX_SIZE;
if (section > 0) {
int nrOfDecks = deckCount();
int deckNr = section - 1;
if (deckNr < nrOfDecks) {
result = handleDeckSectionWrite(memAddr, writeLen, buffer, deckNr);
}
}
return result;
}
void deckMemoryInit() {
memoryRegisterHandler(&memoryDef);
}
/*
* || ____ _ __
* +------+ / __ )(_) /_______________ _____ ___
* | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2015 Bitcraze AB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, in version 3.
*
* This program 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* deck_test.c - Test utility functions for testing decks.
*/
#include <string.h>
#include "stm32fxxx.h"
#include "deck.h"
#include "deck_test.h"
#include "debug.h"
#ifndef DECK_TEST_PRINT_ALL_FAILED
#define STATUS_EVAL (*status)
#else
#define STATUS_EVAL 1
#endif
void decktestEval(bool result, char *failString, bool *status)
{
if (STATUS_EVAL)
{
if (!result)
{
consolePrintf("%s [FAIL]\n", failString);
*status = false;
}
else
{
*status = true;
}
}
}
void decktestSaveGPIOStatesABC(GpioRegBuf *gpioRegBuf)
{
// Save GPIO registers
memcpy(&gpioRegBuf->gpioBuffA, GPIOA, sizeof(GPIO_TypeDef));
memcpy(&gpioRegBuf->gpioBuffB, GPIOB, sizeof(GPIO_TypeDef));
memcpy(&gpioRegBuf->gpioBuffC, GPIOC, sizeof(GPIO_TypeDef));
}
void decktestRestoreGPIOStatesABC(GpioRegBuf *gpioRegBuf)
{
// Restore GPIO registers
memcpy(GPIOA, &gpioRegBuf->gpioBuffA, sizeof(GPIO_TypeDef));
memcpy(GPIOB, &gpioRegBuf->gpioBuffB, sizeof(GPIO_TypeDef));
memcpy(GPIOC, &gpioRegBuf->gpioBuffC, sizeof(GPIO_TypeDef));
}
/**
* || ____ _ __
* +------+ / __ )(_) /_______________ _____ ___
* | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2019 Bitcraze AB
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* lighthouse.h: lighthouse tracking system receiver
*/
#pragma once
#define LIGHTHOUSE_BITSTREAM_CRC 0x112bc794
#define LIGHTHOUSE_BITSTREAM_SIZE 104093
/**
* || ____ _ __
* +------+ / __ )(_) /_______________ _____ ___
* | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2016 Bitcraze AB
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* locodeck.h: Dwm1000 deck driver.
*/
#ifndef __LOCODECK_H__
#define __LOCODECK_H__
#include <stddef.h>
#include <stdint.h>
#include "FreeRTOS.h"
#include "libdw1000.h"
#include "stabilizer_types.h"
// Timestamp counter frequency
#define LOCODECK_TS_FREQ (499.2e6 * 128)
#define LOCODECK_ANTENNA_OFFSET 154.6 // In meters
#define LOCODECK_ANTENNA_DELAY ((LOCODECK_ANTENNA_OFFSET * LOCODECK_TS_FREQ) / SPEED_OF_LIGHT) // In radio ticks
typedef enum uwbEvent_e {
eventTimeout,
eventPacketReceived,
eventPacketSent,
eventReceiveTimeout,
eventReceiveFailed,
} uwbEvent_t;
typedef uint64_t locoAddress_t;
#define LPS_NUMBER_OF_ALGORITHMS 3
#define LPS_AUTO_MODE_SWITCH_PERIOD M2T(1000)
typedef enum {
lpsMode_auto = 0,
lpsMode_TWR = 1,
lpsMode_TDoA2 = 2,
lpsMode_TDoA3 = 3,
} lpsMode_t;
typedef struct {
// The status of anchors. A bit field (bit 0 - anchor 0, bit 1 - anchor 1 and so on)
// where a set bit indicates that an anchor reentry has been detected
volatile uint16_t rangingState;
// Requested and current ranging mode
lpsMode_t userRequestedMode;
lpsMode_t currentRangingMode;
// State of the ranging mode auto detection
bool modeAutoSearchDoInitialize;
bool modeAutoSearchActive;
uint32_t nextSwitchTick;
} lpsAlgoOptions_t;
bool locoDeckGetAnchorPosition(const uint8_t anchorId, point_t* position);
uint8_t locoDeckGetAnchorIdList(uint8_t unorderedAnchorList[], const int maxListSize);
uint8_t locoDeckGetActiveAnchorIdList(uint8_t unorderedAnchorList[], const int maxListSize);
// Callbacks for uwb algorithms
typedef struct uwbAlgorithm_s {
void (*init)(dwDevice_t *dev);
uint32_t (*onEvent)(dwDevice_t *dev, uwbEvent_t event);
bool (*isRangingOk)();
bool (*getAnchorPosition)(const uint8_t anchorId, point_t* position);
uint8_t (*getAnchorIdList)(uint8_t unorderedAnchorList[], const int maxListSize);
uint8_t (*getActiveAnchorIdList)(uint8_t unorderedAnchorList[], const int maxListSize);
} uwbAlgorithm_t;
#include <FreeRTOS.h>
#define MAX_TIMEOUT portMAX_DELAY
// Send a short configuration packet to the LPS system
// Returns true if packet will be send, false instead
bool lpsSendLppShort(uint8_t destId, void* data, size_t length);
typedef struct {
uint8_t dest;
uint8_t length;
uint8_t data[30];
} lpsLppShortPacket_t;
// Poll if there is a LPS short configuration packet to send
// Return true if the packet data has been filled in shortPacket
// Return false if no packet to send
// Function to be used by the LPS algorithm
bool lpsGetLppShort(lpsLppShortPacket_t* shortPacket);
uint16_t locoDeckGetRangingState();
void locoDeckSetRangingState(const uint16_t newState);
// LPP Packet types and format
#define LPP_HEADER_SHORT_PACKET 0xF0
#define LPP_SHORT_ANCHORPOS 0x01
struct lppShortAnchorPos_s {
float x;
float y;
float z;
} __attribute__((packed));
#endif // __LOCODECK_H__
/**
* || ____ _ __
* +------+ / __ )(_) /_______________ _____ ___
* | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2016 Bitcraze AB
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* lpsTdma.h: Generic TDMA utility defines for LPS algorithms
*/
#ifndef __LPS_TDMA_H__
#define __LPS_TDMA_H__
#ifndef TDMA_NSLOTS_BITS
#ifdef LPS_TDMA_ENABLE
#warning "Number of slots bits for TDMA not defined! Defaulting to 1 (2 slots)."
#endif
#define TDMA_NSLOTS_BITS 1
#endif
#ifndef TDMA_SLOT
#define TDMA_SLOT -1
#endif
#define TDMA_SLOT_BITS 27
#define TDMA_FRAME_BITS (TDMA_SLOT_BITS + TDMA_NSLOTS_BITS)
#define TDMA_SLOT_LEN (1ull<<(unsigned long long)(TDMA_SLOT_BITS+1))
#define TDMA_FRAME_LEN (1ull<<(unsigned long long)(TDMA_FRAME_BITS+1))
#define TDMA_LAST_FRAME(NOW) ( NOW & ~(TDMA_FRAME_LEN-1) )
#endif //__LPS_TDMA_H__
#ifndef __LPS_TDOA2_TAG_H__
#define __LPS_TDOA2_TAG_H__
#include "locodeck.h"
#include "libdw1000.h"
#include "mac.h"
extern uwbAlgorithm_t uwbTdoa2TagAlgorithm;
#ifdef LOCODECK_NR_OF_ANCHORS
#define LOCODECK_NR_OF_TDOA2_ANCHORS LOCODECK_NR_OF_ANCHORS
#else
#define LOCODECK_NR_OF_TDOA2_ANCHORS 8
#endif
typedef struct {
const locoAddress_t anchorAddress[LOCODECK_NR_OF_TDOA2_ANCHORS];
point_t anchorPosition[LOCODECK_NR_OF_TDOA2_ANCHORS];
bool combinedAnchorPositionOk;
} lpsTdoa2AlgoOptions_t;
typedef struct {
uint8_t type;
uint8_t sequenceNrs[LOCODECK_NR_OF_TDOA2_ANCHORS];
uint32_t timestamps[LOCODECK_NR_OF_TDOA2_ANCHORS];
uint16_t distances[LOCODECK_NR_OF_TDOA2_ANCHORS];
} __attribute__((packed)) rangePacket2_t;
// Protocol version
#define PACKET_TYPE_TDOA2 0x22
// Positions in payload for received LPP packets
#define LPS_TDOA2_LPP_HEADER (sizeof(rangePacket2_t))
#define LPS_TDOA2_LPP_TYPE (sizeof(rangePacket2_t) + 1)
#define LPS_TDOA2_LPP_PAYLOAD (sizeof(rangePacket2_t) + 2)
// Positions for sent LPP packets
#define LPS_TDOA2_TYPE_INDEX 0
#define LPS_TDOA2_SEND_LPP_PAYLOAD_INDEX 1
#define TDOA2_LPP_PACKET_SEND_TIMEOUT (LOCODECK_NR_OF_TDOA2_ANCHORS * 5)
#define TDOA2_RECEIVE_TIMEOUT 10000
void lpsTdoa2TagSetOptions(lpsTdoa2AlgoOptions_t* newOptions);
#endif // __LPS_TDOA2_TAG_H__
#ifndef __LPS_TDOA3_TAG_H__
#define __LPS_TDOA3_TAG_H__
#include "locodeck.h"
extern uwbAlgorithm_t uwbTdoa3TagAlgorithm;
#endif // __LPS_TDOA3_TAG_H__
#ifndef __LPS_TWR_TAG_H__
#define __LPS_TWR_TAG_H__
#include "locodeck.h"
#include "libdw1000.h"
#include "mac.h"
#define LPS_TWR_POLL 0x01 // Poll is initiated by the tag
#define LPS_TWR_ANSWER 0x02
#define LPS_TWR_FINAL 0x03
#define LPS_TWR_REPORT 0x04 // Report contains all measurement from the anchor
#define LPS_TWR_LPP_SHORT 0xF0
#define LPS_TWR_TYPE 0
#define LPS_TWR_SEQ 1
// LPP payload can be in the ANSWER packet
#define LPS_TWR_LPP_HEADER 2
#define LPS_TWR_LPP_TYPE 3
#define LPS_TWR_LPP_PAYLOAD 4
#define LPS_TWR_SEND_LPP_PAYLOAD 1
#ifdef LOCODECK_NR_OF_ANCHORS
#define LOCODECK_NR_OF_TWR_ANCHORS LOCODECK_NR_OF_ANCHORS
#else
#define LOCODECK_NR_OF_TWR_ANCHORS 8
#endif
extern uwbAlgorithm_t uwbTwrTagAlgorithm;
typedef struct {
uint8_t pollRx[5];
uint8_t answerTx[5];
uint8_t finalRx[5];
float pressure;
float temperature;
float asl;
uint8_t pressure_ok;
} __attribute__((packed)) lpsTwrTagReportPayload_t;
typedef struct {
const uint64_t antennaDelay;
const int rangingFailedThreshold;
locoAddress_t tagAddress;
const locoAddress_t anchorAddress[LOCODECK_NR_OF_TWR_ANCHORS];
// TWR data
point_t anchorPosition[LOCODECK_NR_OF_TWR_ANCHORS];
bool combinedAnchorPositionOk;
// TWR-TDMA options
bool useTdma;
int tdmaSlot;
} lpsTwrAlgoOptions_t;
void uwbTwrTagSetOptions(lpsTwrAlgoOptions_t* newOptions);
float lpsTwrTagGetDistance(const uint8_t anchorId);
#define TWR_RECEIVE_TIMEOUT 1000
#endif // __LPS_TWR_TAG_H__