OSAL移植到STM8

 

 

最近需要用STM8S105做驱动控制器,涉及到使用485与上位机通讯,上位机的蓝牙模块中使用CC2541。这是个新产品,没有可借鉴的代码,涉及到的协议解算和逻辑结构又比较多,规划了一下架构并尝试写了几行代码,发现在编程幼稚园中学的状态机式编程实在难以胜任,于是打算上一个操作系统。

考虑到ucos代码量比较大,不适用于这种小片子,一时难以抉择。忽然想到已经在BLE上耕耘了大半年了,使用OSAL非常得心应手,于是想把CC2541中的OSAL移植过来。

严格意义上来讲,OSAL不是真正的嵌入式实时操作系统,它的本质是状态机式的伪操作系统,它和Contiki有点像,和uCOS的架构则完全不同(因为uCOS底层是真正要做任务切换的,会把寄存器压入任务栈)。OSAL是把状态机伪装成嵌入式操作系统的接口方式,用起来很方便,每个事件任务处单独处理,并实现了轻量级。而这对于我就够了,因为我只是不想靠脑子去理清那么复杂的下一步、下一步应该到哪,那种感觉我一想起来都觉得不寒而栗。

系统具体原理和使用方法这里就不多讲了,TI官方有OSAL手册。接下来直接切入正题,实现移植。

把OSAL从CC2541工程移植到STM8上需要复制以下这些系统文件:

接下来要创建三个文件,如下图,接下来详述:

首先创建是的时钟文件,这里我起名为app_timer.c , 它配置和使用timer4,负责提供系统调度的时基,文件中代码如下:

/**
  ******************************************************************************
  Timer 文件,产生1ms时基
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
#include "stm8s_eval.h"
#include "app_uart.h"
#include "app_bsp.h"
#include "OSAL_Clock.h"

#define TIM4_PERIOD 124

volatile uint32_t sysTick;  /*系统时间计数器*/

void TIM4_TimeBase_Init(void)
{
  /* TIM4 configuration:
   - TIM4CLK is set to 16 MHz, the TIM4 Prescaler is equal to 128 so the TIM1 counter
   clock used is 16 MHz / 128 = 125 000 Hz
  - With 125 000 Hz we can generate time base:
      max time base is 2.048 ms if TIM4_PERIOD = 255 --> (255 + 1) / 125000 = 2.048 ms
      min time base is 0.016 ms if TIM4_PERIOD = 1   --> (  1 + 1) / 125000 = 0.016 ms
  - In this example we need to generate a time base equal to 1 ms
   so TIM4_PERIOD = (0.001 * 125000 - 1) = 124 */
  sysTick = 0;  /*初始化系统时间计数器*/
  TIM4_DeInit();
  /* Time base configuration */
  TIM4_TimeBaseInit(TIM4_PRESCALER_128, TIM4_PERIOD);  /*1ms中断*/
  /* Clear TIM4 update flag */
  TIM4_ClearFlag(TIM4_FLAG_UPDATE);
  /* Enable update interrupt */
  TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);
  /* enable interrupts */
  //enableInterrupts();
  /* Enable TIM4 */
  TIM4_Cmd(ENABLE);
  //TIM4->CR1 |= TIM4_CR1_CEN;  /* Enable TIM4 同上,二选一*/
}

void TIM4_TimeBase_Interrupt(void)  /*1ms中断*/
{
  /* Cleat Interrupt Pending bit */
  TIM4_ClearITPendingBit(TIM4_IT_UPDATE);
  /*User Hook Function*/
  TimerBase_UART_Hook();
  /*系统时间*/
  sysTick++;
  osalTimeUpdate(); /*1ms更新OS时基*/
}

uint32_t getMcuTickCount(void)
{
  return sysTick;
}

/******************************End File*****************************/

接下来新建一个app_OSAL.c文件,该文件用于初始化用户任务:

/**************************************************************************************************
 *                                            INCLUDES
 **************************************************************************************************/
#include "hal_types.h"
#include "OSAL.h"
#include "OSAL_Tasks.h"
#include "app.h"
/* HAL */
#include "hal_drivers.h"

/*********************************************************************
 * GLOBAL VARIABLES
 */

// The order in this table must be identical to the task initialization calls below in osalInitTask.
const pTaskEventHandlerFn tasksArr[] =
{
  Hal_ProcessEvent,                                 // task 0
  App_ProcessEvent                                  // task 1

};

const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );
uint16 *tasksEvents;

/*********************************************************************
 * FUNCTIONS
 *********************************************************************/

/*********************************************************************
 * @fn      osalInitTasks
 *
 * @brief   This function invokes the initialization function for each task.
 *
 * @param   void
 *
 * @return  none
 */
void osalInitTasks( void )
{
  uint8 taskID = 0;

  tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
  osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));

  /* Hal Task */
  Hal_Init( taskID++ );
  /* Application */
  App_Init( taskID );

}

/*********************************************************************
*********************************************************************/

接下来要修改OSAL文件中的OSAL_ClockBLE.c文件,里面osalTimeUpdate这个函数是用于刷新系统驱动时钟的,因为原来它是借助于BLE的时隙时钟为625us,做了比较复杂的换算成1ms,但是因为上面我自己改造了时钟函数,可以产生1ms时基,所以这里注释掉换算代码,直接用自己的时基:

 

//extern volatile uint32_t sysTick;  /*系统时间计数器*/
void osalTimeUpdate( void )
{
//  uint32 tmp;
//  uint32 ticks1ms;
//  uint16 elapsedMSec = 0;
//  static uint32 test =0 ;
//
//  // Get the free-running count of 625us timer ticks
//  //tmp = ll_McuPrecisionCount();
//  tmp = getMcuTickCount();
//  //tmp = sysTick;
//
//  if ( tmp != previousLLTimerTick )
//  {
//    // Calculate the elapsed ticks of the free-running timer.
//    ticks1ms = tmp - previousLLTimerTick;
//
//    // Store the LL Timer tick count for the next time through this function.
//    previousLLTimerTick = tmp;
//
//    /* It is necessary to loop to convert the usecs to msecs in increments so as
//     * not to overflow the 16-bit variables.
//     */
////    while ( ticks1ms > MAXCALCTICKS )
////    {
////      ticks625us -= MAXCALCTICKS;
////      elapsedMSec += MAXCALCTICKS * 5 / 8;
////      remUsTicks += MAXCALCTICKS * 5 % 8;
////    }
////
////    // update converted number with remaining ticks from loop and the
////    // accumulated remainder from loop
////    tmp = (ticks625us * 5) + remUsTicks;
////
////    // Convert the 625 us ticks into milliseconds and a remainder
////    elapsedMSec += tmp / 8;
////    remUsTicks = tmp % 8;
//
//    // Update OSAL Clock and Timers
//    elapsedMSec = ticks1ms;
//    if ( elapsedMSec )
//    {
//      osalClockUpdate( elapsedMSec );
//      osalTimerUpdate( elapsedMSec );
//    }
//  }
      osalClockUpdate( 1 );
      osalTimerUpdate( 1 );
}

 

最后一步,在main.c文件中增加OSAL相关语句,我工程中的main.c文件内容如下:

void main()
{
  /* system_clock / div = 1 */
  CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);

  BSP_Init(&Board_Address);
#if !defined(__DEBUG) && !defined(__DEBUG_MODBUS) && !defined(__DEBUG_UART) && !defined(__DEBUG_I2C)
  UART_APP_Init(); /*APP mode*/
#else
  UART_Debug_Init();  /*Use debug mode, don't init app uart*/
#endif
  /* Output a message on Hyperterminal using printf function */
  DEBUG("Start done! Version:%s \n",__DATE__);
//  I2C_APP_Init();
  ModbusInit(Board_Address);
  TIM4_TimeBase_Init();
  ADC_APP_Init();
  /* Initialize the operating system */
  osal_init_system();
  /* Enable interrupts */
  HAL_ENABLE_INTERRUPTS();
  osal_set_event( App_TaskID, SBP_I2C_INIT_EVT ); /*初始化I2C和9930的任务*/
  /* Start OSAL */
  osal_start_system(); // No Return from here
}

 

最后一句启动了OSAL后,由系统托管了应用程序,再也不会在main中编写代码了。Bye Bye, main! ^-^

用户任务代码都放在app.c文件中,新建该文件,示例用法概要如下:

/*********************************************************************
 * @fn      App_Init
 */
void App_Init( uint8 task_id )
{
  App_TaskID = task_id;

/*用户新增功能初始化*/
  UserAppInit();

  // Setup a delayed profile startup
  osal_set_event( App_TaskID, SBP_START_DEVICE_EVT );

}


/*********************************************************************
 * @fn      App_ProcessEvent
 *
 * @brief   Simple BLE Peripheral Application Task event processor.  This function
 *          is called to process all events for the task.  Events
 *          include timers, messages and any other user defined events.
 */
uint16 App_ProcessEvent( uint8 task_id, uint16 events )
{

  VOID task_id; // OSAL required parameter that isn't used in this function
  //static uint8 cnt = 0;
  if ( events & SYS_EVENT_MSG )
  {
    uint8 *pMsg;

    if ( (pMsg = osal_msg_receive( App_TaskID )) != NULL )
    {
      app_ProcessOSALMsg( (osal_event_hdr_t *)pMsg );

      // Release the OSAL message
      VOID osal_msg_deallocate( pMsg );
    }

    // return unprocessed events
    return (events ^ SYS_EVENT_MSG);
  }

  if ( events & SBP_START_DEVICE_EVT )
  {
    // Set timer for first periodic event
    osal_start_timerEx( App_TaskID, SBP_PERIODIC_EVT, SBP_PERIODIC_EVT_PERIOD );
//    osal_start_timerEx( eye_TaskID, SBP_REPORT_TEMP_EVT, SBP_REPORT_TEMP_EVT_PERIOD );
//    osal_start_reload_timer( App_TaskID, SBP_RUNTIME_CNT_EVT, SBP_RUNTIME_CNT_EVT_PERIOD );
    //osal_set_event( eye_TaskID, SBP_SW_LIGHT_EVT );
    return ( events ^ SBP_START_DEVICE_EVT );
  }
……
继续处理其他事件
……
  // Discard unknown events
  return 0;
}

 

至于接下来用户怎样使用OSAL,还是请参考TI官方手册,毕竟系统是人家写的,不服不行。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/mmhh3000/article/details/83896567