V71 - Protocol Optimization help

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


Hello everyone!

 

I'm implementing a custom protocol using a V71 (currently just working with the V71 development board) and ran into a problem trying to speed up the communication (questions in red below). 

 

I am currently using the START framework which is (theoretically) versatile but pretty slow . . . as a result, it appears I'm going to have to toggle the bits using baremetal (or find another solution to this). 

 

 

The basic code sets up a task that is meant to generate launch the interrupts every 1 us (based on MCK/8 = 150 MHz / 8 = 18.75 MHz).  Inside that routine, I'm just going to toggle the pins twice to determine the fastest pulses I can get.  The problem I'm running into is the pulses are 3.3 us and the tasks are 16 us apart (rather than the expected 1 us).  This tells me a few things:

 

1)  The code for toggling a pin using the START framework takes way too long for my application.  I'll likely need to use baremetal code to toggle the pin

2)  The add task either takes too long to execute or for some reason, the clock settings aren't correct. 

 

The solution for #1 seems to be to use baremetal code . . . my problem is I can't seem to find how to toggle a pin with baremetal using this processor . . . Does anyone know how I would toggle a pin for the V71 using baremetal code (I'm trying to toggle PD28)?

 

For issue #2, I'm not sure if my issue is a clock setting or if tasks just take a long time to setup and there's not much I can do about it (in which case, I'll have to find another solution to this issue.  Probably just bitbang the protocol out, which I'm hoping to avoid.  Does anyone have any insight into this issue or how to resolve it?

 

Below is essentially the code I'm using (and below that are the START settings I'm using for the timer):

 

#define COMM_SCL GPIO(GPIO_PORTD, 28)
static struct timer_task				comm_task;

void main( void )
{
    /* Initializes MCU, drivers and middleware */
    atmel_start_init( );
    
    comm_init();
    comm_send();
    
    while(1)
    {
        
    }
    return;
}

void comm_init()
{
    comm_task.cb       = comm_cb;
    comm_task.interval = 1;
    comm_task.mode     = TIMER_TASK_ONE_SHOT;
}

void comm_send()
{
    timer_add_task(&COMM_TIMER, &comm_task);
    timer_start(&COMM_TIMER);
}

void comm_cb(const struct timer_task *const timer_task)
{
    gpio_toggle_pin_level(COMM_SCL);
    gpio_toggle_pin_level(COMM_SCL);
    
    timer_add_task(&COMM_TIMER, &comm_task);
}

Below are my START settings:

 

 

Any help you can give me would be greatly appreciated.  Thanks a lot!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why not use Atmel Studio. This results in code that achieve speed expectations. Although the following code is for a SAML21, I am sure the code for a V71 would be almost identical. 

PORT->Group[1].OUTTGL.reg = 0x00000001;    // Toggle PB00

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lachlan wrote:

Why not use Atmel Studio. This results in code that achieve speed expectations. Although the following code is for a SAML21, I am sure the code for a V71 would be almost identical. 

PORT->Group[1].OUTTGL.reg = 0x00000001;    // Toggle PB00

 

 

Yeah, I'd definitely like to be able to . . . but I can't find that command, which is my current issue.  I honestly don't know how to toggle a pin or how to directly access the register.  Unfortunately, the SAML21 is a Cortex-M0 processor and the SAMV71 is a Cortex-M7 processor so the same coding doesn't work.  I can find baremetal sample code in a number of other processors but none of them apply to the V71, unfortunately. 

 

Anyone else know how to do something as simple as toggle a bit using the V71 or any insight on the timing I mentioned above?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For SAMV71, try:

	PIOA->PIO_ODSR ^= (1 << 23);		// toggle PA23
	PIOB->PIO_ODSR ^= (1 << 18);		// toggle PB18

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lachlan wrote:

For SAMV71, try:

	PIOA->PIO_ODSR ^= (1 << 23);		// toggle PA23
	PIOB->PIO_ODSR ^= (1 << 18);		// toggle PB18

 

 

Heh, I actually just drilled down into the START framework and came to the same conclusion you did but I'm having issues with this actually working.  Not sure if I have the implementation correct.  I'm trying to toggle PD28 and I've tried all of the following:

 

    // Did nothing (not sure why)
	PIOD->PIO_ODSR ^= (0x10000000u);
	PIOD->PIO_ODSR ^= (0x10000000u);

    // Did nothing (not sure why)	
	PIOD->PIO_ODSR ^= ( 1 << 28 );
	PIOD->PIO_ODSR ^= ( 1 << 28 );
	
	// Did nothing (not sure why)
	PIOD->PIO_ODSR |= (0x10000000u);
	PIOD->PIO_ODSR &= ~(0x10000000u);
	
	// Did nothing (not sure why)
	PIOD->PIO_ODSR |= ( 1 << 28 );
	PIOD->PIO_ODSR &= ~( 1 << 28 );
	
	// This worked
	PIOD->PIO_SODR = (0x10000000u);
	PIOD->PIO_CODR = (0x10000000u);
	
	// This worked
	PIOD->PIO_SODR = ( 1 << 28 );
	PIOD->PIO_CODR = ( 1 << 28 );

 

It appears I have a solution now but I would like to understand why I'm not able to use PIO_ODSR.  It shows in the datasheet that PIO_ODSR is "Read-only or Read/Write" while PIO_CODR and PIO_SODR are both "write only".  Do I need to do something special to be able to use PIO_ODSR in write mode?  Clearly something isn't working correctly as it doesn't appear to want to let me write anything. 

 

One thing I did notice is that the commands that "didn't work" seemed to alter bit zero of PIO_PDSR while the ones that did work toggled bit 28 of PIO_PDSR.  Maybe I'm doing something wrong or missing a step?

 

Thanks for the reply!  Always good to have someone to bounce stuff off of!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
        // Did nothing (not sure why)

	PIOD->PIO_ODSR ^= (0x10000000u);
	PIOD->PIO_ODSR ^= (0x10000000u);

The above code you have shown twice. If you run both lines, then you have toggled twice and the result will be no change. This would be the same for each not working pair and the results are therefore correct.

If you are running only one of the lines, then I dont see why it should not work, assuming you have enabled the output.

 

If you have a debugger, you can halt the code and manually set/clear the bit in ODSR and see if the change takes. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lachlan wrote:

        // Did nothing (not sure why)

	PIOD->PIO_ODSR ^= (0x10000000u);
	PIOD->PIO_ODSR ^= (0x10000000u);

The above code you have shown twice. If you run both lines, then you have toggled twice and the result will be no change. This would be the same for each not working pair and the results are therefore correct.

If you are running only one of the lines, then I dont see why it should not work, assuming you have enabled the output.

 

If you have a debugger, you can halt the code and manually set/clear the bit in ODSR and see if the change takes. 

No worries, I did that.  I put breakpoints on every line and stepped through the code, watched the local IO in AS7 (to see which bits change, if any) and I also had an oscilloscope hooked up to determine if any changes occurred.  I can confirm that nothing happened when I ran the above lines. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would like to understand why I'm not able to use PIO_ODSR.

 I don't know whether it appiies to the SAMV71, but the SAM3X has a separate register (two registers?) that you need to fiddle with to be able to write the ODSR register directly:

 

the PIO Controller offers a direct con- trol of PIO outputs by single write access to PIO_ODSR (Output Data Status Register). Only bits unmasked by PIO_OWSR (Output Write Status Register) are written. The mask bits in PIO_OWSR are set by writing to PIO_OWER (Output Write Enable Register) and cleared by writing to PIO_OWDR (Output Write Disable Register).

After reset, the synchronous data output is disabled on all the I/O lines as PIO_OWSR resets at 0x0.