Read pin on V71 - bare metal

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


I tried using SPI communication in START but the framework is too slow for what I'm trying to do.  As a result, I'm looking to bitbang it out but the START framework is too slow for that as well.  Right now, I'm having no problems bit banging out the clock but I'm having trouble reading the status of a pin.  We had a bit of code that just toggled on and off a pin (shown below):

 

uchar8 ANALOG_MEAS_adc_isr( void )
{
	if(PIOC->PIO_ODSR&0x10000000) 
	{
		PIOC->PIO_CODR=0x10000000;  //Clear Output Data Register
	}
	else 
	{
		PIOC->PIO_SODR=0x10000000;	//Set Output Data Register
	}
}

I created a function based on this and came up with the following function:

 

void ANALOG_MEAS_bitbang_read_adc( )
{
       bool analog_meas_bl_read_data_array[96];
       
       #define SPI0_ADC_CLK_MASK  0x00400000    //PD22
       #define SPI0_ADC_MOSI_MASK 0x00200000    //PD21
       #define SPI0_ADC_MISO_MASK 0x00100000    //PD20
       
       gpio_set_pin_direction( UC_SPI0_INT_MOSI, GPIO_DIRECTION_OUT );
       gpio_set_pin_function( UC_SPI0_INT_MOSI, GPIO_PIN_FUNCTION_OFF );
       
       gpio_set_pin_direction( UC_SPI0_INT_CLK, GPIO_DIRECTION_OUT );
       gpio_set_pin_function( UC_SPI0_INT_CLK, GPIO_PIN_FUNCTION_OFF );
       
       gpio_set_pin_direction( UC_SPI0_INT_MISO, GPIO_DIRECTION_IN );
       gpio_set_pin_function( UC_SPI0_INT_MISO, GPIO_PIN_FUNCTION_OFF );
       
       for (int i = 0; i < 96; i++ )
       {
              analog_meas_bl_read_data_array[ i ] = ( PIOD->PIO_ODSR & SPI0_ADC_MISO_MASK );

              PIOD->PIO_SODR = SPI0_ADC_CLK_MASK;      //Set Output Data Register
              
              PIOD->PIO_CODR = SPI0_ADC_CLK_MASK;      //Clear Output Data Register
       }
       
       return;
}

So, the goal is to read the pin status on the rising edge into the array.  I placed a breakpoint on the "return" line and read the value of the array but it's all false.  I have a scope hooked up and it appears to have data on the pin so I don't believe that is the issue (the ADC is sending the correct data out and I'm clocking out correctly). 

 

I figure it's probably one of two things:

 

1) The GPIO for the MISO line is setup wrong (and it's not reading data correctly because it's not ACTUALLY setup as an input like I thought it was)

2) I’m reading the pin data wrong (maybe I’m clearing the entire register rather than the bit I need when bitbanging the clock?)

 

I'm leaning towards #2 and I'm probably just reading the pin wrong.  I tried following the START framework to see what commands are called but I can't seem to dig any deeper than this to see what's going on at a register level:

 

Can anyone help me determine the root of my problem?  I imagine it's probably something really simple and I'm pretty close . . . any help you can give me would be greatly appreciated.  Thanks!

This topic has a solution.

Last Edited: Thu. Oct 3, 2019 - 04:17 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First up, it is (usually ) easier to use bit numbers. Expressing everything as binary is cumbersome and error prone - how many zeroes?

#define SPI0_ADC_CLK_MASK  0x00400000    //PD22

 

could be

#define SPI0_ADC_CLK_MASK  (1<<PD22)    //assuming there's a header file with PD22 defined as 22

 

 

This looks a little suspect:

analog_meas_bl_read_data_array[ i ] = ( PIOD->PIO_ODSR & SPI0_ADC_MISO_MASK );

 

the result of your right hand expression will be 0 or (1<<PD20) and you assign this to a boolean. This may or may not work. I'd suggest you put in some printf() to see what is actually happening. Or use the debugger to single step through this part.

As for whether you're reading the correct register, I've not read the datasheet, so this may be a problem. Again, You can use printf() to print out the actual value your are reading. You can then use a bit of wire to set this input high or low and observe the results or use the debugger to observe the actual port registers.

 

Another potential problem is that the logic signal takes a finite amount of time to propagate through the logic to the register. This is probably less likely as hopefully there's a few cycles consumed by the code that will obviate this problem. Nevertheless, something to look out for.

 

I haven't given you a concise response, as I'd have to read the 1000+ page datasheet, but hopefully I've given some techniques for you to resolve your problem.

 

[edit] Curiosity got the better of me.

 

According to the datasheet, ODSR is reading the value of the output register - not what you want. You want the PDSR. See section 32.5.8 of the datasheet.

 

 

Last Edited: Wed. Oct 2, 2019 - 05:39 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have no intention of reading your datasheet.
.
Most ARM chips require
1. Enable the clock for this PORT
2. Set individual bit mode e.g. drive, speed, ..., toggle
3. Set individual direction
4. Read a Port, check bit
5. Write an individual bit
.
3, 5 are often write-only "steering" registers. Fast and convenient.
.
But the whole procedure is only a few statements. And regular operations like 4, 5 are optimised. M0 chips are a bit crap. M3, M4 are often much faster. SAM7 is likely to be good.
It is your job to read SAM7 datasheet. Most importantly, how fast your external electronics can work.
.
David.

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

cradleinflames wrote:
I tried using SPI communication in START but the framework is too slow for what I'm trying to do.

If the framework is too slow I would say the next step is to try using the SPI HW directly, not trying to bitbang SPI.

/Lars

 

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

I would say that the obvious question is:  What do you want to do?

 

Wizards are very useful for setting up a Peripheral.   But the actual operation is easily done with direct statements.

e.g.  reading a GPIO port or reading data from an SPI device.

 

Put some real numbers to your application.  e.g. read an SPI device at 108MHz or read an SPI device at 125kHz.

 

Some external electronics will work at very high speed.   Many typical devices work at moderate speed.

 

David.

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

Kartman wrote:

 

According to the datasheet, ODSR is reading the value of the output register - not what you want. You want the PDSR. See section 32.5.8 of the datasheet.

 

 

Yeah, you nailed it on this one.  I actually found it right at the end of the day but forgot to post it here (sorry about that).  Was out sick yesterday and just now getting around to responding.  I knew it had to be something simple like that cuz, like David suggested (bluntly as he did), there's not much to it, it's pretty straight forward.  Only a handful of things it could be so it makes sense it would be misuse of a register on my part. 

 

To be fair, I'm not surprised the framework is too slow, it was kind of expected.  The decision was made early on for this project to pick a framework and START was selected (ASF was obsolete at that point, START was abandoned, and microchip's framework didn't exist).  Kind of an odd place to be in.  Regardless, the START framework works well enough for the most part, with us bitbanging things as needed.  The SPI protocol isn't particularly complicated so it's easy enough to configure it.  I think when we get into some of the more complicated frameworks like CAN, I think we're going to be happy to have that framework . . . heh. 

 

Thanks for your help!

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

Kartman wrote:

First up, it is (usually ) easier to use bit numbers. Expressing everything as binary is cumbersome and error prone - how many zeroes?

#define SPI0_ADC_CLK_MASK  0x00400000    //PD22

 

could be

#define SPI0_ADC_CLK_MASK  (1<<PD22)    //assuming there's a header file with PD22 defined as 22

 

 

This looks a little suspect:

analog_meas_bl_read_data_array[ i ] = ( PIOD->PIO_ODSR & SPI0_ADC_MISO_MASK );

 

the result of your right hand expression will be 0 or (1<<PD20) and you assign this to a boolean. This may or may not work. I'd suggest you put in some printf() to see what is actually happening. Or use the debugger to single step through this part.

As for whether you're reading the correct register, I've not read the datasheet, so this may be a problem. Again, You can use printf() to print out the actual value your are reading. You can then use a bit of wire to set this input high or low and observe the results or use the debugger to observe the actual port registers.

 

 

Oh, regarding these, I'm in the process of rewriting all my functions so this was purely a placeholder for the time being.  As far as the other function, it works but, I agree it's probably not the best way.  Bool functions usually check to see if it's 0 or if it's "not zero".  So I should be shifting it but, at least for this particular compiler, it works this way without the shifting.  That said, when I start working to have it meet coding guidelines, these kinds of things will be fixed.  Right now, I'm just doing a "proof of concept", then I'm going to write it correctly . . . heh.  Been throwing a lot at it so quick and dirty is enough to prove it works.  Then I need to be smarter about it. 

 

Just wanted to address these, since you took the time to respond.  Thanks again!

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

Lajon wrote:

cradleinflames wrote:
I tried using SPI communication in START but the framework is too slow for what I'm trying to do.

If the framework is too slow I would say the next step is to try using the SPI HW directly, not trying to bitbang SPI.

/Lars

 

 

One of the problems I ran into with the framework (not sure if it would be the same with the HW directly) was that it's supposed to clock on the rising edge but it seemed to be too slow and I ended up having to read the initial state before the read command and then shifting everything by a bit.  Not a huge deal but it's lost time.  With all the workarounds, this seemed easier.  Maybe I'll give it a shot though.  Thanks for the suggestion!

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

Ouch.

 

Read the datasheet.  Use the appropriate SPI mode.

 

It is a wise decision to use a "Framework" setup your peripherals.    Which tends to be a bit fiddly.

 

Use the "Framework" functions to read or write.   You can always replace a slow function with an equivalent bare-metal function.

 

David.