35 #if defined(PIOS_INCLUDE_PPM)
38 static int32_t PIOS_PPM_Get(uintptr_t rcvr_id, uint8_t channel);
44 #define PIOS_PPM_IN_MIN_NUM_CHANNELS 4
45 #define PIOS_PPM_IN_MAX_NUM_CHANNELS PIOS_PPM_NUM_INPUTS
46 #define PIOS_PPM_STABLE_CHANNEL_COUNT 10 // frames
47 #define PIOS_PPM_IN_MIN_SYNC_PULSE_US 3000 // microseconds
48 #define PIOS_PPM_IN_MIN_CHANNEL_PULSE_US 750 // microseconds
49 #define PIOS_PPM_IN_MAX_CHANNEL_PULSE_US 2250 // microseconds
52 static TIM_ICInitTypeDef TIM_ICInitStructure;
54 static void PIOS_PPM_Supervisor(uintptr_t ppm_id);
56 enum pios_ppm_dev_magic {
57 PIOS_PPM_DEV_MAGIC = 0xee014d8b,
61 enum pios_ppm_dev_magic
magic;
65 uint32_t PreviousTime;
68 uint32_t CaptureValue[PIOS_PPM_IN_MAX_NUM_CHANNELS];
69 uint32_t CaptureValueNewFrame[PIOS_PPM_IN_MAX_NUM_CHANNELS];
70 uint32_t LargeCounter;
72 int8_t NumChannelsPrevFrame;
73 uint8_t NumChannelCounter;
76 volatile bool Tracking;
80 static bool PIOS_PPM_validate(
struct pios_ppm_dev * ppm_dev)
82 return (ppm_dev->magic == PIOS_PPM_DEV_MAGIC);
85 static struct pios_ppm_dev * PIOS_PPM_alloc(
void)
87 struct pios_ppm_dev * ppm_dev;
89 ppm_dev = (
struct pios_ppm_dev *)
PIOS_malloc(
sizeof(*ppm_dev));
90 if (!ppm_dev)
return(NULL);
92 ppm_dev->magic = PIOS_PPM_DEV_MAGIC;
96 static void PIOS_PPM_tim_overflow_cb (uintptr_t
id, uintptr_t context, uint8_t channel, uint16_t
count);
97 static void PIOS_PPM_tim_edge_cb (uintptr_t
id, uintptr_t context, uint8_t channel, uint16_t
count);
99 .
overflow = PIOS_PPM_tim_overflow_cb,
100 .edge = PIOS_PPM_tim_edge_cb,
108 struct pios_ppm_dev * ppm_dev;
110 ppm_dev = (
struct pios_ppm_dev *) PIOS_PPM_alloc();
111 if (!ppm_dev)
goto out_fail;
117 ppm_dev->PulseIndex = 0;
118 ppm_dev->PreviousTime = 0;
119 ppm_dev->CurrentTime = 0;
120 ppm_dev->DeltaTime = 0;
121 ppm_dev->LargeCounter = 0;
122 ppm_dev->NumChannels = -1;
123 ppm_dev->NumChannelsPrevFrame = -1;
124 ppm_dev->NumChannelCounter = 0;
125 ppm_dev->Tracking =
false;
126 ppm_dev->Fresh =
false;
128 for (uint8_t
i = 0;
i < PIOS_PPM_IN_MAX_NUM_CHANNELS;
i++) {
145 TIM_ICInitTypeDef TIM_ICInitStructure = cfg->
tim_ic_init;
146 TIM_ICInitStructure.TIM_Channel = chan->
timer_chan;
147 TIM_ICInit(chan->
timer, &TIM_ICInitStructure);
152 TIM_ITConfig(chan->
timer, TIM_IT_CC1 | TIM_IT_Update, ENABLE);
155 TIM_ITConfig(chan->
timer, TIM_IT_CC2 | TIM_IT_Update, ENABLE);
158 TIM_ITConfig(chan->
timer, TIM_IT_CC3 | TIM_IT_Update, ENABLE);
161 TIM_ITConfig(chan->
timer, TIM_IT_CC4 | TIM_IT_Update, ENABLE);
168 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
169 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
170 TIM_ICInitStructure.TIM_ICFilter = 0x0;
176 *ppm_id = (uintptr_t)ppm_dev;
191 static int32_t PIOS_PPM_Get(uintptr_t rcvr_id, uint8_t channel)
193 struct pios_ppm_dev * ppm_dev = (
struct pios_ppm_dev *)rcvr_id;
195 if (!PIOS_PPM_validate(ppm_dev)) {
200 if (channel >= PIOS_PPM_IN_MAX_NUM_CHANNELS) {
204 return ppm_dev->CaptureValue[channel];
207 static void PIOS_PPM_tim_overflow_cb (uintptr_t tim_id, uintptr_t context, uint8_t channel, uint16_t
count)
209 struct pios_ppm_dev * ppm_dev = (
struct pios_ppm_dev *)context;
211 if (!PIOS_PPM_validate(ppm_dev)) {
216 ppm_dev->LargeCounter +=
count;
222 static void PIOS_PPM_tim_edge_cb (uintptr_t tim_id, uintptr_t context, uint8_t chan_idx, uint16_t count)
225 struct pios_ppm_dev * ppm_dev = (
struct pios_ppm_dev *)context;
227 if (!PIOS_PPM_validate(ppm_dev)) {
232 if (chan_idx >= ppm_dev->cfg->num_channels) {
238 ppm_dev->PreviousTime = ppm_dev->CurrentTime;
241 ppm_dev->CurrentTime =
count;
244 ppm_dev->CurrentTime += ppm_dev->LargeCounter;
247 ppm_dev->DeltaTime = ppm_dev->CurrentTime - ppm_dev->PreviousTime;
249 ppm_dev->PreviousTime = ppm_dev->CurrentTime;
252 if (ppm_dev->DeltaTime > PIOS_PPM_IN_MIN_SYNC_PULSE_US) {
253 if (ppm_dev->PulseIndex == ppm_dev->NumChannelsPrevFrame
254 && ppm_dev->PulseIndex >= PIOS_PPM_IN_MIN_NUM_CHANNELS
255 && ppm_dev->PulseIndex <= PIOS_PPM_IN_MAX_NUM_CHANNELS)
259 if (ppm_dev->NumChannelCounter < PIOS_PPM_STABLE_CHANNEL_COUNT)
260 ppm_dev->NumChannelCounter++;
262 ppm_dev->NumChannels = ppm_dev->PulseIndex;
264 ppm_dev->NumChannelCounter = 0;
268 if (ppm_dev->PulseIndex == ppm_dev->NumChannels && ppm_dev->Tracking) {
270 ppm_dev->Fresh =
true;
272 for (uint32_t
i = 0;
i < ppm_dev->NumChannels;
i++) {
273 ppm_dev->CaptureValue[
i] = ppm_dev->CaptureValueNewFrame[
i];
275 for (uint32_t
i = ppm_dev->NumChannels;
276 i < PIOS_PPM_IN_MAX_NUM_CHANNELS;
i++) {
281 ppm_dev->Tracking =
true;
282 ppm_dev->NumChannelsPrevFrame = ppm_dev->PulseIndex;
283 ppm_dev->PulseIndex = 0;
288 }
else if (ppm_dev->Tracking) {
290 if (ppm_dev->DeltaTime > PIOS_PPM_IN_MIN_CHANNEL_PULSE_US
291 && ppm_dev->DeltaTime < PIOS_PPM_IN_MAX_CHANNEL_PULSE_US
292 && ppm_dev->PulseIndex < PIOS_PPM_IN_MAX_NUM_CHANNELS) {
294 ppm_dev->CaptureValueNewFrame[ppm_dev->PulseIndex] = ppm_dev->DeltaTime;
295 ppm_dev->PulseIndex++;
298 ppm_dev->Tracking =
false;
299 for (uint32_t
i = 0;
i < PIOS_PPM_IN_MAX_NUM_CHANNELS ;
i++) {
306 static void PIOS_PPM_Supervisor(uintptr_t ppm_id) {
308 struct pios_ppm_dev * ppm_dev = (
struct pios_ppm_dev *)ppm_id;
310 if (!PIOS_PPM_validate(ppm_dev)) {
320 #define SUPERVISOR_TICK_PERIOD_US 1600
321 #define PPM_FRAME_PERIOD_US 20000
322 #define SUPERVISOR_TICK_DIVIDER (2 * PPM_FRAME_PERIOD_US * PIOS_PPM_STABLE_CHANNEL_COUNT / SUPERVISOR_TICK_PERIOD_US)
323 #if SUPERVISOR_TICK_DIVIDER * SUPERVISOR_TICK_PERIOD_US > 500000
324 #error Unsafe supervisor timeout
326 if(++(ppm_dev->supv_timer) < SUPERVISOR_TICK_DIVIDER) {
330 ppm_dev->supv_timer = 0;
332 if (!ppm_dev->Fresh) {
333 ppm_dev->Tracking =
false;
335 for (int32_t
i = 0;
i < PIOS_PPM_IN_MAX_NUM_CHANNELS ;
i++) {
341 ppm_dev->Fresh =
false;
int32_t(* read)(uintptr_t id, uint8_t channel)
Main PiOS header to include all the compiled in PiOS options.
#define PIOS_DEBUG_Assert(test)
void * PIOS_malloc(size_t size)
void(* overflow)(uintptr_t tim_id, uintptr_t context, uint8_t chan_idx, uint16_t count)
bool PIOS_RTC_RegisterTickCallback(void(*fn)(uintptr_t id), uintptr_t data)
static struct flyingpicmd_cfg_fa cfg
const struct pios_tim_channel * channels
TIM_ICInitTypeDef tim_ic_init
int32_t PIOS_TIM_InitChannels(uintptr_t *tim_id, const struct pios_tim_channel *channels, uint8_t num_channels, const struct pios_tim_callbacks *callbacks, uintptr_t context)
int32_t PIOS_PPM_Init(uintptr_t *ppm_id, const struct pios_ppm_cfg *cfg)
const struct pios_rcvr_driver pios_ppm_rcvr_driver