Hello;
I need to generate two timer outputs with my Beaglebone black. They are high-speed signals so I cannot do it toggling a GPIO input after the timer ISR, so I want to automatically toggle the timer pin on every overflow interrupt, removing any potential latency introduced by the GPIO instructions. I have selected TIMER4 and TIMER7 for this purpose and I perform all the DMtimer operations, ISR Configuration included, in my code (Register, Priority Set, Enable, Reset, Counter Set, Configure....). However, when running and checking with my oscilloscope, I observe that only TIMER4 is toggling the GPIO output, while the TIMER7 pin remains low. Only one works.
How can I do so both timers toggle their respective outputs?
Next, I attach my code.
#include "consoleUtils.h"
#include "soc_AM335x.h"
#include "beaglebone.h"
#include "interrupt.h"
#include "dmtimer.h"
#include "error.h"
#include "hw_control_AM335x.h"
/*
#include "cache.h"
#include "mmu.h"
#include "hw_cm_wkup.h"
#include "hw_cm_per.h"
#include "hw_types.h"
*/
/******************************************************************************
** INTERNAL MACRO DEFINITIONS
*******************************************************************************/
#define TIMER_INITIAL_COUNT_4 (0xFFFFFFFFu-1)//(0xFF000000u)
#define TIMER_RLD_COUNT_4 (0xFFFFFFFFu-1) //(0xFF000000u)
#define TIMER_INITIAL_COUNT_7 (0xFFFFFFFFu-1)//(0xFF000000u)
#define TIMER_RLD_COUNT_7 (0xFFFFFFFFu-1) //(0xFF000000u)
/*
#define START_ADDR_DDR (0x80000000)
#define START_ADDR_DEV (0x44000000)
#define START_ADDR_OCMC (0x40300000)
#define NUM_SECTIONS_DDR (512)
#define NUM_SECTIONS_DEV (960)
#define NUM_SECTIONS_OCMC (1)
*/
/******************************************************************************
** INTERNAL FUNCTION PROTOTYPES
*******************************************************************************/
static void DMTimerAintcConfigure(void);
static void DMTimerSetUp(void);
static void DMTimerIsr4(void);
static void DMTimerIsr7(void);
/******************************************************************************
** MMU Config / Enable
*******************************************************************************/
/*
#ifdef __TMS470__
#pragma DATA_ALIGN(pageTable, 16384);
static volatile unsigned int pageTable[4*1024];
#elif defined(__IAR_SYSTEMS_ICC__)
#pragma data_alignment=16384
static volatile unsigned int pageTable[4*1024];
#else
static volatile unsigned int pageTable[4*1024] __attribute__((aligned(16*1024)));
#endif
void MMUConfigAndEnable(void)
{
REGION regionDdr = {
MMU_PGTYPE_SECTION, START_ADDR_DDR, NUM_SECTIONS_DDR,
MMU_MEMTYPE_NORMAL_NON_SHAREABLE(MMU_CACHE_WT_NOWA,
MMU_CACHE_WB_WA),
MMU_REGION_NON_SECURE, MMU_AP_PRV_RW_USR_RW,
(unsigned int*)pageTable
};
REGION regionOcmc = {
MMU_PGTYPE_SECTION, START_ADDR_OCMC, NUM_SECTIONS_OCMC,
MMU_MEMTYPE_NORMAL_NON_SHAREABLE(MMU_CACHE_WT_NOWA,
MMU_CACHE_WB_WA),
MMU_REGION_NON_SECURE, MMU_AP_PRV_RW_USR_RW,
(unsigned int*)pageTable
};
REGION regionDev = {
MMU_PGTYPE_SECTION, START_ADDR_DEV, NUM_SECTIONS_DEV,
MMU_MEMTYPE_DEVICE_SHAREABLE,
MMU_REGION_NON_SECURE,
MMU_AP_PRV_RW_USR_RW | MMU_SECTION_EXEC_NEVER,
(unsigned int*)pageTable
};
MMUInit((unsigned int*)pageTable);
MMUMemRegionMap(®ionDdr);
MMUMemRegionMap(®ionOcmc);
MMUMemRegionMap(®ionDev);
MMUEnable((unsigned int*)pageTable);
}
*/
/******************************************************************************
** FUNCTION DEFINITIONS
*******************************************************************************/
int main(void)
{
// MMUConfigAndEnable();
// CacheEnable(CACHE_ALL);
/* This function will enable clocks for the DMTimer4 & DMTimer7 instance */
DMTimer4ModuleClkConfig();
DMTimer7ModuleClkConfig();
/* Configure pinmuxing */
HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_ADVN_ALE) = CONTROL_CONF_MUXMODE(2);
HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_OEN_REN) = CONTROL_CONF_MUXMODE(2);
/* Enable IRQ in CPSR */
IntMasterIRQEnable();
/* Register DMTimer4 & DMTimer7 interrupts on to AINTC */
DMTimerAintcConfigure();
/* Perform the necessary configurations for DMTimer */
DMTimerSetUp();
/* Enable the DMTimer interrupts */
DMTimerIntEnable(SOC_DMTIMER_4_REGS, DMTIMER_INT_OVF_EN_FLAG);
DMTimerIntEnable(SOC_DMTIMER_7_REGS, DMTIMER_INT_OVF_EN_FLAG);
/* Start the DMTimers */
DMTimerEnable(SOC_DMTIMER_4_REGS);
DMTimerEnable(SOC_DMTIMER_7_REGS);
/* Halt the program */
while(1);
}
/*
** Do the necessary DMTimer configurations on to AINTC.
*/
static void DMTimerAintcConfigure(void)
{
/* Initialize the ARM interrupt control */
IntAINTCInit();
/* Registering DMTimerIsr */
IntRegister(SYS_INT_TINT4, DMTimerIsr4);
IntRegister(SYS_INT_TINT7, DMTimerIsr7);
/* Set the priority */
IntPrioritySet(SYS_INT_TINT4, 0, AINTC_HOSTINT_ROUTE_IRQ);
IntPrioritySet(SYS_INT_TINT7, 0, AINTC_HOSTINT_ROUTE_IRQ);
/* Enable the system interrupt */
IntSystemEnable(SYS_INT_TINT4);
IntSystemEnable(SYS_INT_TINT7);
}
/*
** Setup the timer for one-shot and compare mode.
*/
static void DMTimerSetUp(void)
{
DMTimerPreScalerClkDisable(SOC_DMTIMER_4_REGS);
DMTimerPreScalerClkDisable(SOC_DMTIMER_7_REGS);
DMTimerReset(SOC_DMTIMER_4_REGS);
DMTimerReset(SOC_DMTIMER_7_REGS);
/* Load the counter with the initial count value */
DMTimerCounterSet(SOC_DMTIMER_4_REGS, TIMER_INITIAL_COUNT_4);
DMTimerCounterSet(SOC_DMTIMER_7_REGS, TIMER_INITIAL_COUNT_7);
/* Load the load register with the reload count value */
DMTimerReloadSet(SOC_DMTIMER_4_REGS, TIMER_RLD_COUNT_4);
DMTimerReloadSet(SOC_DMTIMER_7_REGS, TIMER_RLD_COUNT_7);
/* Configure the DMTimer for Auto-reload and compare mode */
DMTimerModeConfigure(SOC_DMTIMER_4_REGS, DMTIMER_AUTORLD_NOCMP_ENABLE);
DMTimerModeConfigure(SOC_DMTIMER_7_REGS, DMTIMER_AUTORLD_NOCMP_ENABLE);
DMTimerPostedModeConfig(SOC_DMTIMER_4_REGS, DMTIMER_POSTED);
DMTimerPostedModeConfig(SOC_DMTIMER_7_REGS, DMTIMER_POSTED);
HWREG(SOC_DMTIMER_4_REGS + DMTIMER_TCLR) |= 0x00000400; // Trigger on overflow
HWREG(SOC_DMTIMER_4_REGS + DMTIMER_TCLR) |= DMTIMER_TCLR_PT; // Toggle...
HWREG(SOC_DMTIMER_7_REGS + DMTIMER_TCLR) |= 0x00000400; // Trigger on overflow
HWREG(SOC_DMTIMER_7_REGS + DMTIMER_TCLR) |= DMTIMER_TCLR_PT; // Toggle...
}
/*
** DMTimer interrupt service routine. This will send a character to serial
** console.
*/
static void DMTimerIsr4(void)
{
/* Disable the DMTimer interrupts */
//DMTimerIntDisable(SOC_DMTIMER_4_REGS, DMTIMER_INT_OVF_EN_FLAG);
/* Clear the status of the interrupt flags */
DMTimerIntStatusClear(SOC_DMTIMER_4_REGS, DMTIMER_INT_OVF_IT_FLAG);
//flagIsr = 1;
/* Enable the DMTimer interrupts */
//DMTimerIntEnable(SOC_DMTIMER_4_REGS, DMTIMER_INT_OVF_EN_FLAG);
}
/*
** DMTimer interrupt service routine. This will send a character to serial
** console.
*/
static void DMTimerIsr7(void)
{
/* Disable the DMTimer interrupts */
//DMTimerIntDisable(SOC_DMTIMER_7_REGS, DMTIMER_INT_OVF_EN_FLAG);
/* Clear the status of the interrupt flags */
DMTimerIntStatusClear(SOC_DMTIMER_7_REGS, DMTIMER_INT_OVF_IT_FLAG);
//flagIsr7 = 1;
/* Enable the DMTimer interrupts */
//DMTimerIntEnable(SOC_DMTIMER_7_REGS, DMTIMER_INT_OVF_EN_FLAG);
}