This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC3120: Porting Simple Link Host Driver to STM32

Part Number: CC3120
Other Parts Discussed in Thread: CC3100

Hello,

I am new in CC3120,

Right now I am working on Visual Studio with Emulation board and CC3120-BOOST.

I would like to port Simple Link driver to STM32 with noOS configuration.

I am trying to implement: http://www.ti.com/lit/ug/swru455e/swru455e.pdf


  • Pawel,

    For development with the CC3120-BOOST, I recommend using Code Composer Studio (www.ti.com/.../CCSTUDIO). This is going to give you the best development environment as well as the most support moving forward. You can view our Getting started guide on the CC3120 to learn how to get your device up and running.

    www.ti.com/.../swru467.pdf

    Thanks,

    VR
  • Thank you Vincent, something strange in my first post (only the half of post had already posted)

    I am doing the port to the STM32 (already working with Visual Studio),
    Some how chapter 16 of www.ti.com/.../swru455e.pdf is not sufficient for me to understand implementation of sl_IfRegIntHdl()

    I have problem with implementation with sl_IfRegIntHdlr(), I don't understand logic begind this...

    How does implementation of my sl_IfRegIntHdlr(InterruptHdl, pValue) shall work ?

    Let's assume for a second:

    #define sl_IfRegIntHdlr(InterruptHdl, pValue) stm32intr(InterruptHdl, pValue);

    in cc_pal.c:

    SL_P_EVENT_HANDLER interruptRoutine = NULL;

    retVal stm32int(InterruptHdl, pValue) {
    interruptRoutine = interruptHdl;
    }

    and right now in external interrupt handler in host MCU i shall only invoke (assuming that this is global variable) interruptRoutine(0), and that's it ?

    Thank you,
    PZ
  • Hi Pawel,

    Your understanding of the sl_IfRegIntHdlr() function is correct.
    All that function does is that it sets the hostIrq handler function. In most cases that's all there is to do with that function.

    The interruptHdl that you assign as the interrupt routine is used whenever the hostIrq is triggered through an edge on the hostIrq line. The external interrupt in your case also just interruptRoutine(0) because the default interruptRoutine that you assign handles all of the hostIrq events you can get, but in theory you could have additional actions within your external interrupt handler to handle something else.

    By the way, there is an existing port of the SimpleLink CC3100 host driver to the STM32 platform which can be found in the CC3100 SDK:
    www.ti.com/.../cc3100sdk

    While there are some changes between the CC3100 and CC3120 host driver, it should prove useful as a guide on how to implement the various STM32 platform-specific functions you need.

    Let me know if you have any other questions or need more help with the porting effort.

    Regards,
    Michael
  • Michael Reymond thank you for information,

    Hovewer still have problems;

    I had changed strategy (I have found out that Simple Link required SyncObj and LockObj), so to make it easy I am porting application to stm32 with freeRTOS (driver will be control by only one thread) - user.h, cc_pal.c/.h are attached to post.

    /*
     *   Copyright (C) 2015 Texas Instruments Incorporated
     *
     *   All rights reserved. Property of Texas Instruments Incorporated.
     *   Restricted rights to use, duplicate or disclose this code are
     *   granted through contract.
     *
     *   The program may not be used without the written permission of
     *   Texas Instruments Incorporated or against the terms and conditions
     *   stipulated in the agreement under which this program has been supplied,
     *   and under no circumstances can it be used with non-TI connectivity device.
     *
     */
    /******************************************************************************
    *     msp_pal.c
    *
    *    Simplelink Wi-Fi platform abstraction file for MSP432
    ******************************************************************************/
    #include <ti/drivers/net/wifi/porting/cc_pal.h>
    #include <ti/drivers/net/wifi/simplelink.h>
    #include "stm32f3xx_hal.h"
    #include "FreeRTOS.h"
    #include "task.h"
    /****************************************************************************
       GLOBAL VARIABLES
    ****************************************************************************/
    volatile Fd_t g_SpiFd = 0;
    SL_P_EVENT_HANDLER g_Host_irq_Hndlr = NULL;
    extern SPI_HandleTypeDef hspi3;
    extern P_EVENT_HANDLER cc3120extiHandler;
    /****************************************************************************
       CONFIGURATION VARIABLES
    ****************************************************************************/
    
    
    /****************************************************************************
       CONFIGURATION FUNCTION DEFINITION
    ****************************************************************************/
    
    
    /****************************************************************************
       LOCAL FUNCTION DEFINITIONS
    ****************************************************************************/
    Fd_t spi_Open(char *ifName,
                  unsigned long flags)
    {
    
      return 0;
    }
    
    int spi_Close(Fd_t fd)
    {
      return 0;
    }
    
    int spi_Read(Fd_t fd,
                 unsigned char *pBuff,
                 int len)
    {
      int retVal = -1;
    
      HAL_GPIO_WritePin(cc3120_cs_GPIO_Port, cc3120_cs_Pin, 0x00);
      retVal = HAL_SPI_Receive(&hspi3, pBuff, len, 1000);
      HAL_GPIO_WritePin(cc3120_cs_GPIO_Port, cc3120_cs_Pin, 0x01);
      return retVal;
    
    }
    
    int spi_Write(Fd_t fd,
                  unsigned char *pBuff,
                  int len)
    {
      int retVal = -1;
    
      HAL_GPIO_WritePin(cc3120_cs_GPIO_Port, cc3120_cs_Pin, 0x00);
      retVal = HAL_SPI_Transmit(&hspi3, pBuff, len, 1000);
      HAL_GPIO_WritePin(cc3120_cs_GPIO_Port, cc3120_cs_Pin, 0x01);
      return retVal;
    
      return 0;
    }
    
    int NwpRegisterInterruptHandler(P_EVENT_HANDLER InterruptHdl,
                                    void* pValue)
    {
      cc3120extiHandler = InterruptHdl;
      return 0;
    }
    
    
    void NwpMaskInterrupt()
    {
    }
    
    void NwpUnMaskInterrupt()
    {
    }
    
    void NwpPowerOnPreamble(void)
    {
        /* Maybe start timer here? */
    }
    
    void NwpPowerOn(void)
    {
      HAL_GPIO_WritePin(cc3120_enable_GPIO_Port, cc3120_enable_Pin, 0x01);
      HAL_Delay(500);
    }
    
    void NwpPowerOff(void)
    {
      HAL_GPIO_WritePin(cc3120_enable_GPIO_Port, cc3120_enable_Pin, 0x00);
    }
    
    int SyncObjCreate(SemaphoreP_Handle* pSemHandle)
    {
    	(*pSemHandle) = xSemaphoreCreateBinary();
    
        if(!(*(pSemHandle)))
        {
            return(-1);
        }
    
        return(0);
    }
    
    int SyncObjDelete(SemaphoreP_Handle* pSemHandle) {
      /* To be implemented */
      vSemaphoreDelete(*pSemHandle);
      return 0;
    }
    
    int SyncObjSignal(SemaphoreP_Handle* pSemHandle) {
      /* To be implemented */
    	unsigned char retVal;
    	retVal = xSemaphoreGive(*pSemHandle);
    	if(retVal == pdTRUE) {
    		return 0;
    	}else{
    		return 1;
    	}
    }
    
    int  SyncObjSignalFromIRQ(SemaphoreP_Handle * pSemHandle) {
      /* To be implemented */
    	xSemaphoreGiveFromISR(*pSemHandle, NULL);
      return 0;
    }
    
    int SyncObjWait(SemaphoreP_Handle* pSemHandle, uint32_t Timeout) {
      /* To be implemented */
    	unsigned char retVal;
    	retVal = xSemaphoreTake((*pSemHandle),Timeout);
    	if(retVal == pdTRUE) {
    		return 0;
    	}else{
    		return 1;
    	}
    }
    
    int SemaphoreP_delete_handle(SemaphoreP_Handle* pSemHandle)
    {
    //    SemaphoreP_delete(*(pSemHandle));
    //    return(SemaphoreP_OK);
      return 0;
    }
    
    int LockObjDelete(MutexP_Handle* pMutexHandle) {
      /* To be implemented */
      return 0;
    }
    
    int LockObjLock(MutexP_Handle*pMutexHandle, uint32_t Timeout ) {
      /* To be implemented */
    	unsigned char retVal;
    	retVal = xSemaphoreTake((*pMutexHandle),Timeout);
    	if(retVal == pdTRUE) {
    		return 0;
    	}else{
    		return 1;
    	}
    }
    
    int LockObjUnlock(MutexP_Handle* pLockObj) {
    
    	unsigned char retVal;
    	retVal = xSemaphoreGive(*pLockObj);
    	if(retVal == pdTRUE) {
    		return 0;
    	}else{
    		return 1;
    	}
    }
    
    int SemaphoreP_post_handle(SemaphoreP_Handle* pSemHandle)
    {
    //    SemaphoreP_post(*(pSemHandle));
    //    return(SemaphoreP_OK);
      return 0;
    }
    
    
    int Mutex_create_handle(MutexP_Handle* pMutexHandle)
    {
    	(*pMutexHandle) = xSemaphoreCreateMutex();
    
        if(!(*(pMutexHandle)))
        {
            return(-1);
        }
    
      return 0;
    }
    
    int MutexP_delete_handle(MutexP_Handle* pMutexHandle)
    {
      vSemaphoreDelete(*pMutexHandle);
      return 0;
    }
    
    int Mutex_unlock(MutexP_Handle pMutexHandle)
    {
    //    MutexP_unlock(pMutexHandle, 0);
    //    return (MutexP_OK);
      return 0;
    }
    
    int Mutex_lock(MutexP_Handle pMutexHandle)
    {
    //    MutexP_lock(pMutexHandle);
    //    return (MutexP_OK);
      return 0;
    }
    
    unsigned long TimerGetCurrentTimestamp()
    {
    	TickType_t systemTick;
    	systemTick = xTaskGetTickCount();
    	return (unsigned long)systemTick;
    //    return (ClockP_getSystemTicks());
    }
    
    1586.cc_pal.h4201.user.h

    In my only task, I am invoking:

      /* USER CODE BEGIN 5 */
      osDelay(100);
      Mode = sl_Start(0, 0, 0);
      if(Mode != ROLE_STA)
      {
        /* Set NWP role as STA */
        Mode = sl_WlanSetMode(ROLE_STA);
    
        /* For changes to take affect, we restart the NWP */
        sl_Stop(0);
    
        Mode = sl_Start(0, 0, 0);
      }
    

    What I observed:

    1. function sl_Start(0,0,0) always retured  SL_API_ABORTED (-2005), due to timeout of SyncObj:

                (line 185 of device.c): SL_DRV_SYNC_OBJ_WAIT_TIMEOUT(&g_pCB->ObjPool[ObjIdx].SyncObj,INIT_COMPLETE_TIMEOUT, SL_OPCODE_DEVICE_INITCOMPLETE);

    2. after invoking sl_Start(0,0,0) I always catch interrupt from IRQ pin (rising edge), where I am calling previeous registered function (as mentioned in the post above). And program is enter ( I have checked with debuger) to:

    _SlReturnVal_t _SlDrvRxIrqHandler(void *pValue)

    function in driver.c line 804. If we carefully looked into this implementation we can see that it will call        

    (void)sl_Spawn((_SlSpawnEntryFunc_t)_SlDrvMsgReadSpawnCtx, NULL, SL_SPAWN_FLAG_FROM_SL_IRQ_HANDLER);

    as I am not using multithread solution, os it will just call: _SlNonOsSpawn() from nonos.c line 50. - and no releasing of SyncObj will occured...

    Conclusion: I am receiving SL_API_ABORTED (-2005) after invoking sl_Start(0,0,0), because interrupt handler is not release SyncObj.... Is it a bug? or I missed something ? From my understanding sl_Start() is not invoking any communicaiton on SPI ( And I don't see any on my logic analyzer)

    Thank you for any tips! - I am struggling with this for over the week

    Ps. i will check CC3100 with stm32

    Edit: I had check application fo cc3100 for stm32 - but in cc3100 sdk the SyncObj are not mandatory..... Honestly sdk for CC3120 is really unclear for me...

  • Hi Pawel,

    In the CC3100 SDK the host driver actually does use sync objects, it's just that it uses a hidden internal implementation of them since it's assumed that no such objects are implemented in a noRTOS system.

    There is this other thread where I talked about porting the CC3120 host driver to STM32:
    e2e.ti.com/.../2543517
    In there, I explain a bit about porting the sync objects.

    If you do not want to use an RTOS, you can take the CC3100 host driver's sync object implementations and reuse them in the CC3120 host driver. The CC3120 host driver was engineered to take the sync object implementation from a driver porting layer, but you can take the approach that the CC3100 host driver took and just copy over the custom implementations.

    If you want to keep using FreeRTOS, you should define the SL_PLATFORM_MULTI_THREADED define and add the appropriate functions to call the FreeRTOS thread spawn in addition to using the FreeRTOS semaphores.

    Let me know if you want to use noRTOS, or keep using FreeRTOS and I can help you further.

    Regards,
    Michael
  • Let's stay on single thread freeRTOS implementation (user.h/cc_pal.c/.h files as post above - to simplify mutex and sempahors implementation)

    In that case I am leaving: //#define SL_PLATFORM_MULTI_THREADED (as commented) and use nonOs spawn -Is it ok to do that kind of assumption yours Visual Studio app works in that way

    1. I have two threads, one with sl_Start(0,0,0), and second with sl_Task() invoking in the loop (I have read that this shall be invoked in the loop)

    2. After calling sl_Start(0,0,0) I have got transmission on SPI:

    host->device: 0x65 0x87 0x78 0x56

    driver->host response: 0xBC 0xDC 0xCD 0xAB

    driver->host: 0x08 0x00 0x14 0x00
    driver->host: 0x28 0x00 0x04 0x06 0x00 0x00 0x00 0x00

    driver->host: 0x11 0x11 0x11 0x11 0x00 0x00 0x00 0x30 0x00 0x00 0x00 0x00

    (caputere is attached)

    3. Hovewer it still doesn't work, after debugging we are in:

    _SlReturnVal_t _SlDeviceHandleAsync_InitComplete(void *pVoidBuf)
    {
        InitComplete_t     *pMsgArgs = (InitComplete_t *)_SL_RESP_ARGS_START(
            pVoidBuf);
        SlDeviceInitInfo_t DeviceInitInfo;
    
        SL_DRV_PROTECTION_OBJ_LOCK_FOREVER();
    
        if(g_pCB->pInitCallback)
        {
            DeviceInitInfo.ChipId = pMsgArgs->ChipId;
            DeviceInitInfo.MoreData = pMsgArgs->MoreData;
            g_pCB->pInitCallback(_SlDeviceGetStartResponseConvert(
                                     pMsgArgs->Status), &DeviceInitInfo);
        }
        else
        {
            sl_Memcpy(
                g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].
                pRespArgs,
                pMsgArgs, sizeof(InitComplete_t));
            SL_DRV_SYNC_OBJ_SIGNAL(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.
                                                   ActionIndex].SyncObj);
        }
    
        SL_DRV_PROTECTION_OBJ_UNLOCK();
        if(g_pCB->pInitCallback)
        {
            SL_SET_DEVICE_STARTED;
            SL_UNSET_DEVICE_START_IN_PROGRESS;
            _SlDrvReleasePoolObj(g_pCB->FunctionParams.AsyncExt.ActionIndex);
        }
    
        return(SL_OS_RET_CODE_OK);
    }

    Application is calling sl_Memcpy case, not SL_SET_DEVICE_STARTED.

    Michael, maybe I need start all porting proces?

    It cannot be so hard to start with this..