DL40 Module Questions

I’m a little confused as to how to use this module.

i am trying to use the timer/counter for the the module to count external pulses.
If i was using registers to access it on a mainboard in c# it would look something like this

            
            Register SYSAHBCLKCTRL =  new Register(0x40048080);
            SYSAHBCLKCTRL.SetBits(1 << 7);//enable timer b0

            // Select PIO0_2 /CT16B0_CAP0
            Register PINSEL0_2 = new Register(0x40044000);
            PINSEL0_2.SetBits((3 << 0));//set bits 0 and 1  ---- enable pin


            // System AHB clock divider register

            Register AHB = new Register(0x40048078);
            AHB.SetBits((1 << 0));//set bits 0 and 1  ---- enable pin

            Register T0CTCR = new Register(0x4000C070);
            T0CTCR.Write(2 << 0 | 0 << 2);//count on falling edge and use CAP0.
  
            // To enable timer/counter
            Register T0TCR = new Register(0x4000C000 + 0x004);
            T0TCR.SetBits(1 << 0);

            // set prescale to 0
            Register T0PR = new Register(0x4000C000 + 0x00C);
            T0PR.Write(0);

            // should be 0 for a counter
            Register T0CCR = new Register(0x4000C000 + 0x028);
            T0CCR.ClearBits(0x07);

            // Don't do anything on match
            Register T0MCR = new Register(0x4000C000 + 0x014);
            T0MCR.Write(0);

            // To start the counter
            T0TCR.SetBits((1 << 1));
            T0TCR.ClearBits((1 << 1));


            // To read
            Register T0TC = new Register(0x4000C000 + 0x008);
            while (true)
            {
                  uint count = T0TC.Read();

                Debug.Print("Total count: " + count);
                T0TCR.SetBits((1 << 1));
                T0TCR.ClearBits((1 << 1));
                Thread.Sleep(1000);

            }
              

Can I implement this just using the generic daisylink already on board of the DL40?
If so how?

If not do i need to change the firmware to do this?
if so would I just need to modify the DL40.c file in Keil?

Let me caveat what I say here with two things, firstly I am quite new to the ARM processors in general and secondly I have only just started playing with the DL40. So take this into for what it is worth.

You will definitely need need to modify the DL40 firmware. The easiest way to count the pulses using the default firmware as a starting point is to use an interrupt and maintain an int variable with the current count.

If you look at the default project you will see that the GPIO interrupts are setup to call one of the following functions


PIOINT0_IRQHandler // Interrupt on Port 0 pins
PIOINT1_IRQHandler // Interrupt on Port 1 pins
PIOINT2_IRQHandler // Interrupt on Port 2 pins
PIOINT3_IRQHandler // Interrupt on Port 3 pins

You can see the NVIC setup in startup_LPC11xx.s

There are default implementations which maintain a counter for each port and for pin 1 on each port. You can see the implementation in gpio.h, the following variables are maintained


gpio0_counter // Count of interrupts on Port 0
gpio1_counter // Count of interrupts on Port 1
gpio2_counter // Count of interrupts on Port 2
gpio3_counter // Count of interrupts on Port 3

p0_1_counter // Count of interrupts on Port 0 pin 1
p1_1_counter // Count of interrupts on Port 1 pin 1
p2_1_counter // Count of interrupts on Port 2 pin 1
p3_1_counter // Count of interrupts on Port 3 pin 1

Alternatively you need to provide your implementation of one of these function if you want to count on a different pin

  1. Check which pin raised the interrupt (GPIOIntStatus)
  2. If it was your pin, increment your variable
  3. Clear the interrupt for the pin (GPIOIntClear)

You will need to call GPIOSetInterrupt(…) to setup the interrupt on the pin to determine when you want an interrupt eg. on the rising edge, falling edge, both etc.

Then you will need to modify the daisy link register reading so that you can read the counter values. I am not going to go into the whole description of the daisy link register structure, you can see the module builders guide and the source code for the generic daisy link as a reference for that.

Every time you read from the a register the function DL_Platform_ReadRegister in DL40.c is called, so when you read an integer, this function will be called 4 times, once for each byte of the integer. It will be up to you to identify in this function that one of your integer counter registers are being read and using the offset argument you will return the relevant byte, then the integer must be reassembled on the client side.

I have been using Keil, but I have also played with using CoIDE + GCC, and it works as well. But using Keil you can start with the generic daisy link firmware which is much easier.

I hope this very brief and high-level overview will get you started. It is actually simpler than I have made it sound. Good luck!

Thanks for the info Taylorza.
That makes sense if it was implemented in software using interrupts.
I am origionally a VB programmer and am learning c# to use these devices. I have no experience in c++ so i’m trying to simplify this as much as possible.

From the manual the chip has a few counters/timers available to use that are already implemented in the chip.
Wouldn’t it be easier to setup the registers on the chip and let it do the counting and just send the count then reset the counter like the code i supplied?

The counters can be used, but I do not have a sample at hand while the much of what you need is already in the in the generic Daisy Link firmware if you go with the interrupts. Of course using one of the 32/16 bit counters would be a better option.

You will definately have to use C to do this on the chip, there is no getting around that.

I have been looking for a good sample project to provide for the DL40, so if I get sometime this weekend I will put together a sample using the counter to do this.

@ MikeCormier - I got sometime today and implemented the code required to use the DL40 to count pulses using the counter. Here is a summary of what I did

DaisyLink.c - DL_Initialize()

Added the following code to setup 32 bit Timer 0 as a counter, This is on PIN 1.5


// Enable PIN 1.5
DrvGPIO_ClrBit(1, 5);
DrvGPIO_Open(1, 5,  E_IO_INPUT);
			
// Setup 32 bit counter	
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<9);
LPC_IOCON->PIO1_5 &= ~0x07;	/*  Timer0_32 I/O config */
LPC_IOCON->PIO1_5 |= 0x02;	/* Timer0_32 CAP0 */
	
// Clear counter control register to use pin as clock
LPC_TMR32B0->CCR = 0;
	
// Use pin 1.5 as clock
LPC_TMR32B0->CTCR = (0x1 << 1);
	
// Enable Timer
LPC_TMR32B0->TCR = 1;

DL40.c
Modify the Reg_t structure to contain the counter


struct Reg_t
{
  struct DL_Regs dl;
  BYTE Activate;
  uint32_t Counter;
}

Modify main() to load the value of the timer counter into the Reg_t.Counter member


int main (void)
{
  HAL_Init_SysTick100us();
  GPIOInit();
	
  memset(&Reg, 0, REGS_SIZE);
  DL_Initialize((struct DL_Regs*)&Reg, MANUFACTURER_GHI, MODULE_TYPE, MODULE_VERSION);

  while(TRUE)
  {
    // Wait until we are ready to begin the state machine
    if( 0 == DL_Process() || Reg.Activate == 0x00 )
    {
      continue;
    }
    Reg.Activate = 0;
    Reg.Counter = LPC_TMR32B0->TC;		
  }// End state machine loop
}

DL40.h
Make sure the REGS_SIZE matches the size of your register structure


 #define REGS_SIZE (DL_REGS_SIZE + 5 )

That is it for the DL40 side of things. Now I did not go into the whole thing of supporting multi-byte registers, which the DaisyLink protocol does support, but the Generic Daisy Link driver does not support. I am working on a more developer friendly DL40 framework for both the native and the managed components.

On the managed side, using the standard Generic DaisyLink Module driver you can use the following code to read the counter


// Trigger the DL Update
genericDaisylink.WriteRegister(0, 1);

// Read the register values for the counter
byte b1 = genericDaisylink.ReadRegister(9);
byte b2 = genericDaisylink.ReadRegister(10);
byte b3 = genericDaisylink.ReadRegister(11);
byte b4 = genericDaisylink.ReadRegister(12);

// Reconstitute the bytes into a 32bit int
int value = b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
Debug.Print(value.ToString());

I hope this helps.

1 Like

@ taylorza,
Thanks so much for this.
i’ll try it out and see how it goes on my end

@ MikeCormier - It’s a huge pleasure. If you do not come right, I can send you the project I used to test this with.

@ taylorza,
Imodified the dl40 firmware but it won’t compile.
can you send me the modified firmware you used so i can try it?
thanks

@ MikeCormier - I tried attaching the code as a zip file to the post, but they only allow images. So I went ahead and created a Code Share for the sample.
http://www.tinyclr.com/codeshare

Update: I see the zip browser is not working, but if you download the zip file you will find all the code.

i just downloaded and compiled it thanks so much
i’ll try it today or tomorrow.

@ taylorza,
Any tips on trying to reflash the DL40?
I am using the program i downloaded from the wiki, i recompiled under 4.2 but it is hanging on “connecting…”
i have tried a spider in socket 11 and a mountaineer in socket 3 but the same thing happens.

edit
i found this thread http://www.tinyclr.com/forum/topic?id=9195 and it worked on socket 2 on the mountaineer board but not three
thanks

@ taylorza - This works great!!!
Can the counter be reset after it sends the count?

I am really glad that worked for you, I find the DL40 a very exciting proposition and just plain fun to tinker with.

You can have the value reset immediately after activating for read. In the DL40.c file you just add the following after the value is coppied to the ‘Counter’ register.


LPC_TMR32B0->TC = 0; 

So your code should look some thing like this


int main (void)
{
  HAL_Init_SysTick100us();
  GPIOInit();
	
  memset(&Reg, 0, REGS_SIZE);
  DL_Initialize((struct DL_Regs*)&Reg, MANUFACTURER_GHI, MODULE_TYPE, MODULE_VERSION);

  while(TRUE)
  {
    // Wait until we are ready to begin the state machine
    if( 0 == DL_Process() || Reg.Activate == 0x00 )
    {
      continue;
    }
    Reg.Activate = 0;
    Reg.Counter = LPC_TMR32B0->TC; // Copy the timer value to the Counter register
    LPC_TMR32B0->TC = 0;                   // Reset the timer to 0
  }
}

What is happening here, is before you read you signal the Activate register (this is on the client side) this triggers the timer value to be copied to the Counter register after which you can clear the timer counter.