Hi,
I want to generate a clock out(3.2MHz) from the DIO pin in CC1310.
As I am new to RTOS, please suggest some document which I can refer and lower the core clock (48 MHz) to 3.2 MHz.
Thanks & regards,
Ankur
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.
Hi Ankur,
sorry for the late reply. I suggest to use one of the General Purpose Timer modules and a PWM output. TI-RTOS 2.20 will have a high-level PWM driver. It is supposed to be released in 1-2 weeks. Otherwise you would have to do it the hard way and access register directly. Please refer to the DriverLib documentation how to use the timer and also this answer how to integrate it into TI-RTOS power management.
Hi Richard,
Thanks for the reply. First of all about my application:
The first priority is RF RX, second is RF TX and the third is the data pulses(@ 2MHz ,with any duty cycle upto 40msec continuous) and cycle continues and RF packet arrives again after 1sec.
I created three task based on priorities with highest to RF Rx and lowest to data pulses.
As suggested by you and with the help of example , I could able to put everything in the code for the timer but there are two issues that I would like to take your help.
1) I am not able to see the change in pulse repetitive frequency(prf) with different values of prescalar. How to get all the different prfs using prescalar?
2) Timer becomes Hwi and it hampers the series of operation in sequence RF Rx , RF Tx and the data pulses. How to get the correct sequence of operation using timers?
Below is my code:
/***** Includes *****/
#include <stdlib.h>
#include <xdc/std.h>
#include <xdc/cfg/global.h>
#include <xdc/runtime/System.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/knl/Clock.h>
#include <ti/sysbios/family/arm/m3/Timer.h>
//#include <ti/sysbios/family/arm/m3/Hwi.h>
/* Drivers */
#include <ti/drivers/rf/RF.h>
#include <ti/drivers/PIN.h>
#include <driverlib/rf_prop_mailbox.h>
#include <ti/drivers/SPI.h>
#include <ti/drivers/Power.h>
#include <ti/drivers/power/PowerCC26XX.h>
#include <driverlib/timer.h>
//#include <ti/drivers/sdspi/SPICC26XXDMA.h>
/* Board Header files */
#include "Board.h"
#include "RFQueue.h"
#include "smartrf_settings/smartrf_settings.h"
#include <stdlib.h>
/* Pin driver handle */
static PIN_Handle ledPinHandle;
static PIN_State ledPinState;
Hwi_Struct timerHwi;
/*
* Application LED pin configuration table:
* - All LEDs board LEDs are off.
*/
PIN_Config pinTable[] =
{
Board_LED4 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
Board_LED3 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
Board_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
Board_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
Board_LCD_MODE | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
PIN_TERMINATE
};
/***** Defines *****/
#define RX_TASK_STACK_SIZE 1024
#define RX_TASK_PRIORITY 3
/* TX Configuration */
#define DATA_ENTRY_HEADER_SIZE 8 /* Constant header size of a Generic Data Entry */
#define MAX_LENGTH 30 /* Max length byte the radio will accept */
#define NUM_DATA_ENTRIES 2 /* NOTE: Only two data entries supported at the moment */
#define NUM_APPENDED_BYTES 2 /* The Data Entries data field will contain:
* 1 Header byte (RF_cmdPropRx.rxConf.bIncludeHdr = 0x1)
* Max 30 payload bytes
* 1 status byte (RF_cmdPropRx.rxConf.bAppendStatus = 0x1) */
/***** Defines *****/
#define TX_TASK_STACK_SIZE 1024
#define TX_TASK_PRIORITY 2
/* TX Configuration */
#define PAYLOAD_LENGTH 3
#define PACKET_INTERVAL (uint32_t)(2*4000000*0.5f) /* Set packet interval to 1sec */
/***** Prototypes *****/
static void txTaskFunction(UArg arg0, UArg arg1);
static void rxTaskFunction(UArg arg0, UArg arg1);
static void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e);
static void UWBclk(UArg arg0, UArg arg1);
void interruptTimerA(UArg arg0);
/***** Variable declarations *****/
static Task_Params rxTaskParams;
Task_Struct rxTask; /* not static so you can see in ROV */
static uint8_t rxTaskStack[RX_TASK_STACK_SIZE];
static Task_Params txTaskParams;
Task_Struct txTask; /* not static so you can see in ROV */
static uint8_t txTaskStack[TX_TASK_STACK_SIZE];
static Task_Params UWBclkTaskParams;
Task_Struct UWBclkTask; /* not static so you can see in ROV */
static uint8_t UWBclkTaskStack[TX_TASK_STACK_SIZE];
Semaphore_Struct semTxStruct;
Semaphore_Handle semTxHandle;
Semaphore_Struct semRxStruct;
Semaphore_Handle semRxHandle;
Semaphore_Struct semUWBclkStruct;
Semaphore_Handle semUWBclkHandle;
static RF_Object rfObject;
static RF_Handle rfHandle;
#if defined(__TI_COMPILER_VERSION__)
#pragma DATA_ALIGN (rxDataEntryBuffer, 4);
#elif defined(__IAR_SYSTEMS_ICC__)
#pragma data_alignment = 4
#endif
static uint8_t rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
MAX_LENGTH,
NUM_APPENDED_BYTES)];
/* Receive dataQueue for RF Core to fill in data */
static dataQueue_t dataQueue;
static rfc_dataEntryGeneral_t* currentDataEntry;
static uint8_t packetLength;
static uint8_t* packetDataPointer;
uint32_t time;
static uint8_t txPacket[PAYLOAD_LENGTH];
//static uint16_t seqNumber;
static PIN_Handle pinHandle;
static uint8_t packet[MAX_LENGTH + NUM_APPENDED_BYTES - 1]; /* The length byte is stored in a separate variable */
uint32_t num,num1;
int key;
/***** Function definitions *****/
void RxTask_init(PIN_Handle ledPinHandle) {
pinHandle = ledPinHandle;
Task_Params_init(&rxTaskParams);
rxTaskParams.stackSize = RX_TASK_STACK_SIZE;
rxTaskParams.priority = RX_TASK_PRIORITY;
rxTaskParams.stack = &rxTaskStack;
rxTaskParams.arg0 = (UInt)1000000;
Task_construct(&rxTask, rxTaskFunction, &rxTaskParams, NULL);
// key = Hwi_disable();
/* Initialization of done & UWB TX to zero */
PIN_setOutputValue(pinHandle,Board_LCD_MODE ,0);
PIN_setOutputValue(pinHandle, Board_LED3,1);
PIN_setOutputValue(pinHandle, Board_LED4,0);
}
static void rxTaskFunction(UArg arg0, UArg arg1)
{
RF_Params rfParams;
RF_Params_init(&rfParams);
if( RFQueue_defineQueue(&dataQueue,
rxDataEntryBuffer,
sizeof(rxDataEntryBuffer),
NUM_DATA_ENTRIES,
MAX_LENGTH + NUM_APPENDED_BYTES))
{
/* Failed to allocate space for all data entries */
while(1);
}
/* Modify CMD_PROP_RX command for application needs */
RF_cmdPropRx.pQueue = &dataQueue; /* Set the Data Entity queue for received data */
RF_cmdPropRx.rxConf.bAutoFlushIgnored = 0; /* Discard ignored packets from Rx queue */
RF_cmdPropRx.rxConf.bAutoFlushCrcErr = 0; /* Discard packets with CRC error from Rx queue */
RF_cmdPropRx.maxPktLen = MAX_LENGTH; /* Implement packet length filtering to avoid PROP_ERROR_RXBUF */
RF_cmdPropRx.pktConf.bRepeatOk = 0;
RF_cmdPropRx.pktConf.bRepeatNok = 0;
if (!rfHandle) {
/* Request access to the radio */
rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
/* Set the frequency */
RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
}
while (1) {
/* Enter RX mode and stay forever in RX */
RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, &callback, IRQ_RX_ENTRY_DONE);
// Semaphore_pend(semRxHandle, BIOS_WAIT_FOREVER);
// Semaphore_pend(semRxHandle, 0);
}
}
void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
{
if (e & RF_EventRxEntryDone)
{
/* Toggle pin to indicate RX */
// PIN_setOutputValue(pinHandle, Board_LED1,!PIN_getOutputValue(Board_LED1));
/* Get current unhandled data entry */
currentDataEntry = RFQueue_getDataEntry();
/* Handle the packet data, located at ¤tDataEntry->data:
* - Length is the first byte with the current configuration
* - Data starts from the second byte */
packetLength = *(uint8_t*)(¤tDataEntry->data);
packetDataPointer = (uint8_t*)(¤tDataEntry->data + 1);
/* Copy the payload + the status byte to the packet variable */
memcpy(packet, packetDataPointer, (packetLength + 1));
if(packet[1] == 0x32)
{
Semaphore_pend(semRxHandle, BIOS_WAIT_FOREVER);
Semaphore_post(semTxHandle);
}
// Semaphore_post(semTxHandle);
RFQueue_nextEntry();
}
}
#if 1
/***** Function definitions *****/
void TxTask_init(PIN_Handle inPinHandle)
{
pinHandle = inPinHandle;
Task_Params_init(&txTaskParams);
txTaskParams.stackSize = TX_TASK_STACK_SIZE;
txTaskParams.priority = TX_TASK_PRIORITY;
txTaskParams.stack = &txTaskStack;
txTaskParams.arg0 = (UInt)1000000;
Task_construct(&txTask, txTaskFunction, &txTaskParams, NULL);
}
static void txTaskFunction(UArg arg0, UArg arg1)
{
uint32_t time;
RF_Params rfParams;
RF_Params_init(&rfParams);
RF_cmdPropTx.pktLen = PAYLOAD_LENGTH;
RF_cmdPropTx.pPkt = txPacket;
RF_cmdPropTx.startTrigger.triggerType = TRIG_ABSTIME;
RF_cmdPropTx.startTrigger.pastTrig = 1;
//RF_cmdPropTx.startTime = 0;
//uint32_t standbyDurationUs = 6;//1ms
if (!rfHandle) {
/* Request access to the radio */
rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
/* Set the frequency */
RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
}
/* Get current time */
time = RF_getCurrentTime();
while(1)
{
// Semaphore_pend(semTxHandle, BIOS_WAIT_FOREVER);
// PIN_setOutputValue(pinHandle,Board_LCD_MODE ,0);
// PIN_setOutputValue(pinHandle, Board_LED4,0);
// PIN_setOutputValue(pinHandle, Board_LED3,1);
txPacket[0] = 0x99;
txPacket[1] = 0xAA;
txPacket[2] = 0x2B;
// Task_sleep(200);
// PIN_setOutputValue(pinHandle, Board_LED1,!PIN_getOutputValue(Board_LED1));
/* Set absolute TX time to utilize automatic power management */
//time = RF_getCurrentTime();
time += PACKET_INTERVAL;
RF_cmdPropTx.startTime = time;
/* Send packet */
RF_EventMask result = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, NULL, 0);
if (!(result & RF_EventLastCmdDone))
{
/* Error */
while(1);
}
PIN_setOutputValue(pinHandle, Board_LED2,!PIN_getOutputValue(Board_LED2));
// PIN_setOutputValue(pinHandle,Board_LCD_MODE ,0);
Semaphore_pend(semTxHandle, BIOS_WAIT_FOREVER);
// key = Hwi_enable();
Semaphore_post(semUWBclkHandle);
}
}
void interruptTimerA(UArg arg0)
{
uint32_t status = TimerIntStatus(GPT0_BASE, true);
PIN_setOutputValue(ledPinHandle, Board_LED4,1);
if (TIMER_TIMA_TIMEOUT & status)
{
TimerIntClear(GPT0_BASE, TIMER_TIMA_TIMEOUT);
}
PIN_setOutputValue(ledPinHandle, Board_LED4,0);
Semaphore_post(semRxHandle);
}
void UWBclkTask_init(PIN_Handle inPinHandle)
{
pinHandle = inPinHandle;
Task_Params_init(&UWBclkTaskParams);
UWBclkTaskParams.arg0 = (UInt)1000000;
UWBclkTaskParams.stackSize = TX_TASK_STACK_SIZE;
UWBclkTaskParams.priority = 1;
UWBclkTaskParams.stack = &UWBclkTaskStack;
Task_construct(&UWBclkTask,UWBclk, &UWBclkTaskParams, NULL);
}
static void UWBclk(UArg arg0, UArg arg1)
{
/* Switches the peripheral power domain on */
Power_setDependency(PowerCC26XX_PERIPH_GPT0);
/* Prevents the controller from going to standby */
Power_setConstraint(PowerCC26XX_SB_DISALLOW);
// register ISR and enable hardware interrupt for timer
Hwi_Params params;
Hwi_Params_init(¶ms);
params.enableInt = TRUE;
Hwi_construct(&timerHwi, INT_GPT0A, &interruptTimerA, ¶ms, NULL);
/* Configure the timer hardware */
TimerDisable(GPT0_BASE, TIMER_A);
// TimerConfigure(GPT0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC | TIMER_CFG_B_PERIODIC);
TimerConfigure(GPT0_BASE, TIMER_CFG_ONE_SHOT | TIMER_CFG_A_ONE_SHOT);
// TimerConfigure(GPT0_BASE,TIMER_CFG_PERIODIC | TIMER_CFG_A_PERIODIC);
TimerPrescaleSet(GPT0_BASE, TIMER_A, 23); // prescaler is 15 - 3.2MHz prescalar is 29 - 1.655MHz prescalar is 24 -2MHz
TimerLoadSet(GPT0_BASE, TIMER_A, 2);
TimerIntClear(GPT0_BASE, TIMER_TIMA_TIMEOUT);
// TimerIntClear(GPT0_BASE, TIMER_CAPA_MATCH);
TimerIntEnable(GPT0_BASE, TIMER_TIMA_TIMEOUT);
// TimerIntEnable(GPT0_BASE, TIMER_CAPA_MATCH);
TimerEnable(GPT0_BASE, TIMER_A);
// Semaphore_pend(semUWBclkHandle, BIOS_WAIT_FOREVER);
// PIN_setOutputValue(ledPinHandle, Board_LED4,1);
}
#endif
/*
* ======== main ========
*/
int main(void)
{
Semaphore_Params semParams;
/* Call board init functions. */
Board_initGeneral();
/* Open LED pins */
ledPinHandle = PIN_open(&ledPinState, pinTable);
if(!ledPinHandle)
{
System_abort("Error initializing board LED pins\n");
}
/* Construct a Semaphore object to be used as a resource lock, inital count 0 */
Semaphore_Params_init(&semParams);
Semaphore_construct(&semTxStruct, 0, &semParams);
Semaphore_construct(&semRxStruct, 0, &semParams);
Semaphore_construct(&semUWBclkStruct, 0, &semParams);
/* Obtain instance handle */
semTxHandle = Semaphore_handle(&semTxStruct);
semRxHandle = Semaphore_handle(&semRxStruct);
semUWBclkHandle = Semaphore_handle(&semUWBclkStruct);
/* Initialize task */
RxTask_init(ledPinHandle);
/* Initialize task */
TxTask_init(ledPinHandle);
/* Initialize task */
UWBclkTask_init(ledPinHandle);
/* Start BIOS */
BIOS_start();
return (0);
}
Please give your suggestions.
Thanks & regards,
Ankur
Hi Ankur,
some remarks about your code:
/* Switches the peripheral power domain on */
Power_setDependency(PowerCC26XX_PERIPH_GPT0);
/* Prevents the controller from going to standby */
Power_setConstraint(PowerCC26XX_SB_DISALLOW);
// Route the timer pwm output to a physical pin
// EVENT0: GPT0 A
// EVENT1: GPT0 B
// EVENT2: GPT1 A ...
PINCC26XX_setMux(ledPinHandle, Board_LED2, IOC_PORT_MCU_PORT_EVENT0);
// Set up timer A as PWM
TimerConfigure(GPT0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);
// Set 2MHz (count until 24-1 before reset)
TimerLoadSet(GPT0_BASE, TIMER_A, 23);
// Set duty cycle to 50% (12 is not exact, but that's impossible with 23 as load value)
TimerMatchSet(GPT0_BASE, TIMER_A, 12);
// Enable the timer
TimerEnable(GPT0_BASE, TIMER_A);
Hi Richard,
Thank you so much for your valuable comments about my code and the PWM implementation.
I could able to change my code completely using events. As mentioned by you, it provides a better control and avoids the synchronization problems by using a single RF task.
Also by using the PWM example code , the output signal frequency observed to be very accurate.
With regards,
Ankur
Hi Nathaly,
sorry for the delay, I've been on vacation. Routing is done in this line:
PINCC26XX_setMux(ledPinHandle, Board_LED2, IOC_PORT_MCU_PORT_EVENT0);
Board_LED2 is a GPIO id of a physical pin defined in the Board support file. These defines basically map to IOID_0..IOID_31 in <driverlib/ioc.h>. IOC_PORT_MCU_PORT_EVENT0 is an internal signal of the timer module that may be mapped to any physical pin. Each timer provides one event signal. For pin mapping, please refer to the TRM section 11.3.