闫刚 px4队列采集传感器数据的新算法

  • Post author:
  • Post category:其他




WorkQueueManager线程

在很早以前px4的传感器数据是通过hrt在定时器中断服务程序中阻塞方式通过spi接口读取数据,由于spi的单个transfer的时间大约在几us,这种方式,当前线程,专门处理spi的请求,用来读取传感器数据

  • spi dma
  • queue
  • sem_wait
  • c++ oop



spi dma

#ifdef CONFIG_STM32F7_SPI_DMA
static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
                         FAR void *rxbuffer, size_t nwords)
{
  FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)dev;

  DEBUGASSERT(priv != NULL);

#ifdef CONFIG_STM32F7_DMACAPABLE
  if ((txbuffer && !stm32_dmacapable((uint32_t)txbuffer, nwords, priv->txccr)) ||
      (rxbuffer && !stm32_dmacapable((uint32_t)rxbuffer, nwords, priv->rxccr)))
    {
      /* Unsupported memory region, fall back to non-DMA method. */

      spi_exchange_nodma(dev, txbuffer, rxbuffer, nwords);
    }
  else
#endif
    {
      static uint8_t rxdummy[ARMV7M_DCACHE_LINESIZE]
        __attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
      static const uint16_t txdummy = 0xffff;
      size_t buflen = nwords;

      if (spi_9to16bitmode(priv))
        {
          buflen = nwords * sizeof(uint16_t);
        }

      spiinfo("txbuffer=%p rxbuffer=%p nwords=%d\n", txbuffer, rxbuffer, nwords);
      DEBUGASSERT(priv->spibase != 0);

      /* Setup DMAs */

      spi_dmarxsetup(priv, rxbuffer, (uint16_t *)rxdummy, nwords);
      spi_dmatxsetup(priv, txbuffer, &txdummy, nwords);

      /* Flush cache to physical memory */

      if (txbuffer)
        {
          arch_flush_dcache((uintptr_t)txbuffer, (uintptr_t)txbuffer + buflen);
        }

      /* Start the DMAs */

      spi_dmarxstart(priv);
      spi_dmatxstart(priv);

      /* Then wait for each to complete */

      spi_dmarxwait(priv);
      spi_dmatxwait(priv);

      /* Force RAM re-read */

      if (rxbuffer)
        {
          arch_invalidate_dcache((uintptr_t)rxbuffer,
                                 (uintptr_t)rxbuffer + buflen);
        }
      else
        {
          arch_invalidate_dcache((uintptr_t)rxdummy,
                                 (uintptr_t)rxdummy + sizeof(rxdummy));
        }
    }
}



信号量最高效率

等待信号量

spi_dmarxwait(priv);

spi_dmatxwait(priv);

//启动DMA,注册毁掉函数
static void spi_dmarxstart(FAR struct stm32_spidev_s *priv)
{
  priv->rxresult = 0;
  stm32_dmastart(priv->rxdma, spi_dmarxcallback, priv, false);
}

//执行回调函数
static void spi_dmarxcallback(DMA_HANDLE handle, uint8_t isr, void *arg)
{
  FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)arg;

  /* Wake-up the SPI driver */

  priv->rxresult = isr | 0x080;  /* OR'ed with 0x80 to assure non-zero */
  spi_dmarxwakeup(priv);
}

//发出信号量
static inline void spi_dmarxwakeup(FAR struct stm32_spidev_s *priv)
{
  (void)sem_post(&priv->rxsem);
}



queue

单次触发hrt

void
MPU6000::start()
	//定义周期
	uint32_t last_call_interval = _call_interval;
	_call_interval = last_call_interval;
	ScheduleOnInterval(_call_interval - MPU6000_TIMER_REDUCTION, 1000);

	//等待周期到达执行回调
	-> hrt_call_every(&_call, delay_us, interval_us, (hrt_callout)&ScheduledWorkItem::schedule_trampoline, this);

	//把当前对象添加到队列中
        ->dev->ScheduleNow();
	  -> inline void ScheduleNow() { if (_wq != nullptr) _wq->Add(this); }



c++ oop

px4_add_library(px4_work_queue

ScheduledWorkItem.cpp

WorkItem.cpp

WorkQueue.cpp

WorkQueueManager.cpp

)

int WorkQueueManagerStart()
{
	//创建任务
	int task_id = px4_task_spawn_cmd("wq:manager",
					 SCHED_DEFAULT,
					 PX4_WQ_HP_BASE,
					 1200,
					 (px4_main_t)&WorkQueueManagerRun,
					 nullptr);
       //执行队列中的对象
       -> static void WorkQueueManagerRun()
	_wq_manager_wqs_list = new BlockingList<WorkQueue *>();
	_wq_manager_create_queue = new BlockingQueue<const wq_config_t *, 1>();

	while (!_wq_manager_should_exit.load()) {
		// create new work queues as needed
		const wq_config_t *wq = _wq_manager_create_queue->pop();


class MPU6000 : public cdev::CDev, public px4::ScheduledWorkItem
{
private:
	void Run() override;


static void *WorkQueueRunner(void *context)
{
	wq_config_t *config = static_cast<wq_config_t *>(context);
	WorkQueue wq(*config);

	// add to work queue list
	_wq_manager_wqs_list->add(&wq);

	wq.Run();



版权声明:本文为yangang185原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。