Differences between AVR UC3 and SAMC21

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

Hi Guys, 

I am programming a control system for an electric bike which basically samples different sensors (current, voltage, speedometer, etc) and uses PIDs and other algorithms to compute throttle control, battery capacity, range, etc. I started programming on an Arduino MEGA which lacked a bit of power and now shifted to a SAMC21 (Xplained Pro). I have now almost entirely implemented my code on the SAM device but am struggling to add the LCD screen functionalities. Actually, the more I read about it the more it seems that this SAM device does not offer any particular advantage compared to an AVR one, particularly as the ASF leads to very heavy and voluminous code size. So concretely what are the differences, advantages and disadvantages, between let's say a SAMC21 and an ATC UC3 C Series? ANy particular insights regarding my specific application would be super helpful!!

Thank you for your help!

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

UC3 is a bit left field? It's a niche controller with no future. Atmel/Microchip are pouring all there 32 bit effort into Cortex M (like pretty much ever other silicon manufacturer on planet earth right now!). I'm intrigued by your:

elt93 wrote:
but am struggling to add the LCD screen functionalities.

comment - why would that be any more difficult on a Cortex M than a Mega or a Tiny or an Xmega or a UC3 or a PIC16 or a PIC18 or a PIC24 or an MSP430 or whatever other micro you happened to pick. Is this purely about 3.3V versus 5V? Because the trend in micros is towards 3.3V (or even lower) then there are 3.3V LCDs available too - you don't have to use something designed in the 1990's if you don't want to!

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

Basically, I haven't been able to find appropriate libraries and am therefore trying to modify AVR ones to work on SAM but I keep reading that the workings of it are very different and that such 8 bit port control is a lot simpler on AVR. However, I am getting from your message that this could be wrong, I will therefore keep trying to make the SAM work.

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

elt93 wrote:
... particularly as the ASF leads to very heavy and voluminous code size.
Could compare ASF with Atmel START.

http://start.atmel.com/#examples

(Board pull-down menu, SAM C21 Xplained Pro)

 

"Dare to be naïve." - Buckminster Fuller

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

At the end of the day an LCD lib is doing nothing more than wiggling some IO wires. That is surely possible on any micro?

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

If you wanted an Arduino like experience, then why did you chose a less popular device like the samC series? Because it was 5V? Had you chosen the samD21, then you'd have Arduino and MDED support that would've eased your integration. I asked in a earlier thread of yours whether the C series is much the same as the D series (apart from the5 vs3.3v) - if this is the case then you can leverage the support i mentioned above. You need to do some research.
Nevertheless, a display library for one micro is going to be much the same for another - it is only the port pins/i2c or spi that differs. You'll need to resolve that difference. If that is too dificult for you, then you need to decide what path you choose.

As an aside, the libraries you speak of are most likely for AVR 8 bit series. AVR32 are a totally different beast. So don't think AVR32 is going to solve your present situation.

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

I did choose the SAM C Series because it was 5V and therefore simplifies a lot the integration into the electrical system.

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

So what is more difficult for you? The software or the hardware?

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

clawson wrote:

 Is this purely about 3.3V versus 5V? Because the trend in micros is towards 3.3V (or even lower) then there are 3.3V LCDs available too - you don't have to use something designed in the 1990's if you don't want to!

 

That's not entirely true.  At the MPU end of the scale, yes the trend is to lower voltages ( Even there, 5V tolerant IO is widely available )

 

However, general purpose and smaller MCUs are trending more to Wide Vcc operation.

 

Examples: The SAM C here, the new ATTiny817 has a xmega core, but in Wide Vcc.

 

Sometimes Wide Vcc simply makes more sense... as in :

 

elt93 wrote:

I did choose the SAM C Series because it was 5V and therefore simplifies a lot the integration into the electrical system.

 

That's fine, there are a growing number of MCUs with 5V operation to choose from. You can even get Arm M4 in 5V now, if you need that level.

 

What does your LCD need for the interface, and how many pixels ?

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

Who-me wrote:

What does your LCD need for the interface, and how many pixels ?

 

I will just use the LCD to display basic system information, such as State of Charge, remaining range, velocity, distance traveled, etc. Hence, I don't have any particular specifications for the LCD. Right now, I chose to go for an alphanumeric 16x4 to save some computational power compared to a TFT one. From what I get right now, all I need to do is select a few digital pins and vary their state according to different functions such as clear screen, etc. However, I don't really understand how the LCD libraries' code are often so short when intuitively I feel like they should be longer as there will be one combination of pin state for each character and function. I am guessing there is a way to create these libs so that you don't have to explicitly write a case for each character?

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

Star by reading this:

 

https://www.sparkfun.com/datashe...

 

If you go for the simplest form of interface there (8bits) then displaying "Hello world" is really very little more than clocking each character 'H', 'e', 'l', 'l', 'o'... into the device in turn.

 

To save wires then these displays have a 4 bit mode where a character code such as 'H' (0x48) must be sent in two halves as 0x4 and then 0x8 which adds a little more complexity.

 

But otherwise it is just like sending characters to a UART or something.

 

There is a slight complication in that as well as receiving data the display can be told to receive commands so you can also send it codes which mean things like "move the cursor to line N, column M" or "clear the display and go to line 1, column 1" and so on.

 

But it's pretty simple.

 

As well as the 4 or 8 data wires there are a few more that do things like selecting between data/command and one that you pulse each time to say "something is ready to be read in" but other than that driving these things is nothing more than outputting 0's and 1's on wires attached to it.

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

Ok thank you very much!

I actually found this library for AVR which looks good: http://community.atmel.com/proje.... and I bought this LCD: http://uk.farnell.com/webapp/wcs... , which is said to use a derivative of the HD44780 so I'm assuming they work in similar ways. Basically, all I would need to change in this library is the command to change the states of the pins right? So replacing such calls: LCD_DB0_PORT&=~_BV(LCD_DB0_PIN)  by  port_pin_set_output_level(LCD_DB0_PIN, 0); ?

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

Yes, as I say all these HD44780 libraries are just either wiggling/reading individual pins (E, RS, RW) or writing 4 bits (D0..D3) or 8 bits (D0..D7) of data so you just change those final bit/nybble/byte output (and perhaps input) accesses for the micro you want to use it on.

 

BTW I'll bet that whatever micro you use you won't be the first to want to drive HD44780 from it so I'll bet that if you google "<whatever micro> HD44780" you will find code already done for any micro.

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

Ok thank you!

And this is the problem I've been having, I really haven't been able to find anything for the SAMC21. Also, this library as has the following macros defined:

// Constants/Macros
#define PIN(x) (*(&x - 2))           // Address of Data Direction Register of Port X
#define DDR(x) (*(&x - 1))           // Address of Input Register of Port X

Which is followed later by:

//PIN defines
#define lcd_db0_pin_get() (((PIN(LCD_DB0_PORT) & _BV(LCD_DB0_PIN))==0)?0:1)
#define lcd_db1_pin_get() (((PIN(LCD_DB1_PORT) & _BV(LCD_DB1_PIN))==0)?0:1)
#define lcd_db2_pin_get() (((PIN(LCD_DB2_PORT) & _BV(LCD_DB2_PIN))==0)?0:1)
#define lcd_db3_pin_get() (((PIN(LCD_DB3_PORT) & _BV(LCD_DB3_PIN))==0)?0:1)
#define lcd_db4_pin_get() (((PIN(LCD_DB4_PORT) & _BV(LCD_DB4_PIN))==0)?0:1)
#define lcd_db5_pin_get() (((PIN(LCD_DB5_PORT) & _BV(LCD_DB5_PIN))==0)?0:1)
#define lcd_db6_pin_get() (((PIN(LCD_DB6_PORT) & _BV(LCD_DB6_PIN))==0)?0:1)
#define lcd_db7_pin_get() (((PIN(LCD_DB7_PORT) & _BV(LCD_DB7_PIN))==0)?0:1)

//DDR defines
#define lcd_rs_ddr_low() DDR(LCD_RS_PORT)&=~_BV(LCD_RS_PIN)
#if RW_LINE_IMPLEMENTED==1
  #define lcd_rw_ddr_low() DDR(LCD_RW_PORT)&=~_BV(LCD_RW_PIN)
#endif
#define lcd_db0_ddr_low() DDR(LCD_DB0_PORT)&=~_BV(LCD_DB0_PIN)
#define lcd_db1_ddr_low() DDR(LCD_DB1_PORT)&=~_BV(LCD_DB1_PIN)
#define lcd_db2_ddr_low() DDR(LCD_DB2_PORT)&=~_BV(LCD_DB2_PIN)
#define lcd_db3_ddr_low() DDR(LCD_DB3_PORT)&=~_BV(LCD_DB3_PIN)
#define lcd_db4_ddr_low() DDR(LCD_DB4_PORT)&=~_BV(LCD_DB4_PIN)
#define lcd_db5_ddr_low() DDR(LCD_DB5_PORT)&=~_BV(LCD_DB5_PIN)
#define lcd_db6_ddr_low() DDR(LCD_DB6_PORT)&=~_BV(LCD_DB6_PIN)
#define lcd_db7_ddr_low() DDR(LCD_DB7_PORT)&=~_BV(LCD_DB7_PIN)

#define lcd_rs_ddr_high() DDR(LCD_RS_PORT)|=_BV(LCD_RS_PIN)
#if RW_LINE_IMPLEMENTED==1
  #define lcd_rw_ddr_high() DDR(LCD_RW_PORT)|=_BV(LCD_RW_PIN)
#endif
#define lcd_db0_ddr_high() DDR(LCD_DB0_PORT)|=_BV(LCD_DB0_PIN)
#define lcd_db1_ddr_high() DDR(LCD_DB1_PORT)|=_BV(LCD_DB1_PIN)
#define lcd_db2_ddr_high() DDR(LCD_DB2_PORT)|=_BV(LCD_DB2_PIN)
#define lcd_db3_ddr_high() DDR(LCD_DB3_PORT)|=_BV(LCD_DB3_PIN)
#define lcd_db4_ddr_high() DDR(LCD_DB4_PORT)|=_BV(LCD_DB4_PIN)
#define lcd_db5_ddr_high() DDR(LCD_DB5_PORT)|=_BV(LCD_DB5_PIN)
#define lcd_db6_ddr_high() DDR(LCD_DB6_PORT)|=_BV(LCD_DB6_PIN)
#define lcd_db7_ddr_high() DDR(LCD_DB7_PORT)|=_BV(LCD_DB7_PIN)

#define lcd_rs_ddr_set(value) if (value) lcd_rs_ddr_high(); else lcd_rs_ddr_low();
#if RW_LINE_IMPLEMENTED==1
  #define lcd_rw_ddr_set(value) if (value) lcd_rw_ddr_high(); else lcd_rw_ddr_low();
#endif
#define lcd_db0_ddr_set(value) if (value) lcd_db0_ddr_high(); else lcd_db0_ddr_low();
#define lcd_db1_ddr_set(value) if (value) lcd_db1_ddr_high(); else lcd_db1_ddr_low();
#define lcd_db2_ddr_set(value) if (value) lcd_db2_ddr_high(); else lcd_db2_ddr_low();
#define lcd_db3_ddr_set(value) if (value) lcd_db3_ddr_high(); else lcd_db3_ddr_low();
#define lcd_db4_ddr_set(value) if (value) lcd_db4_ddr_high(); else lcd_db4_ddr_low();
#define lcd_db5_ddr_set(value) if (value) lcd_db5_ddr_high(); else lcd_db5_ddr_low();
#define lcd_db6_ddr_set(value) if (value) lcd_db6_ddr_high(); else lcd_db6_ddr_low();
#define lcd_db7_ddr_set(value) if (value) lcd_db7_ddr_high(); else lcd_db7_ddr_low();

I am not sure what this does exactly as it seems to do something similar than just setting the respective pins high or low.

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

You'd kind of hope that the macro names kind of describe what they do! So I would read something like

lcd_db3_ddr_low()

as setting the DDR bit for the LCD data bit 3 to be low etc.

 

The code there is using a bit of a "trick" that only works for AVR:

#define PIN(x) (*(&x - 2))           // Address of Data Direction Register of Port X
#define DDR(x) (*(&x - 1))           // Address of Input Register of Port X

This relies on the fact in memory each 3 register group for a port on an AVR is:

n + 0: DDR
n + 1: PIN
n + 2: PORT

So if someone gives you nothing but PORTC you can work out PINC as it will be the address of PORTC minus 1 and DDRC will be at address of PORTC - 2. That is what you can see going on in those PIN(x) and PORT(x) macros. So PIN(PORTC) will just come out as the address that is PINC and so on.

 

To be honest I think you picked some code that, while utilitarian, is too complex to start with as your first port.

 

There is a page of (good!) LCD code here:

 

http://www.johanekdahl.se/rwiki/...

 

I'd maybe start with something like this:

 

http://www.johanekdahl.se/rwiki/...

 

Or, because 8 bit is actually easier in terms of code, if you micro has enough spare pins then this:

 

http://www.johanekdahl.se/rwiki/...

 

That is simple and well explained. Should be easy to port that to any micro.

 

If you want it even simpler remove a level of macros from it. Just replace all LCD_DATA_PORT with PORTD and so on. Then you'd be looking at code that is doing nothing but setting bits in well known AVR GPIO registers. After that it's just a case of finding the equivalent for your new micro.

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

Thanks! I am currently trying to implement the 8 bit example. This code uses PORT to call pins and as I understand this is specific to AVR in that with SAM devices I have to call each pin individually, I can't just send a byte to a PORT. Also, I am not sure what DDR represents, is this a specific pin or a specific layer to control pins in AVR?

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

The AVR DDR is similar to the SAM DIR, both are data direction registers.

David (aka frog_jr)

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

OK, I guess I was misled when you started with:

elt93 wrote:
I started programming on an Arduino MEGA

so I sort of assumed you were starting out on a basis of knowing what DDR/PORT were in relation to an AVR.

 

The fact is that the tiny/mega AVRs have 3 registers for each port. The ports are A, B, C, D, etc so you have things like DDRB, PORTA, PINC and so on. Each is generally a group of 8 pins relating to the 8 bits in each register. To configure a port you generally star with the DDRx register. By default all 8 bits are 0 which means all 8 pins of that port are inputs at power on. You set bits to 1 in this register to make the corresponding bit an output. So if you see something like:

DDRB |= (1 << 3);

which is setting bit 3 to one then this is making pin 3 of port B an output. Once a pin is made output then its 0/1 state is controlled by the corresponding bit in the PORTx register. So in this case:

PORTB |= (1 << 3);

would set the output line high and

PORTB &= ~(1 << 3);

would set the output line low.

 

If back in DDR the bit for a pin is 0 then it is an input and is typically read using the PINx register using code like:

if (PINC & (1 << 5)) {
    // input is high - act on it
}

So back over in Johan's simple 8bit code you see stuff like:

  // Toggle the E line
  LCD_CTRL_PORT |= (1<<LCD_E);   // Going up..
  // Short delay needed here...
  _delay_us(50);
  LCD_CTRL_PORT &= ~(1<<LCD_E);  // ..and down.

Well LCD_E is just a pin number from 0 to 7 (in fact it is  "#define LCD_E    2") and LCD_CTRL_PORT is just "#define LCD_CTRL_PORT PORTC", so this code really says nothing more than:

  // Toggle the E line
  PORTC |= (1 << 2);   // Going up..
  // Short delay needed here...
  _delay_us(50);
  PORTC &= ~(1 << 2);  // ..and down.

So it's taking bit 2 of PORTC high then low. To be able to drive it as an output the code has previously done:

  LCD_CTRL_DDR |= (1<<LCD_E);

where:

#define LCD_CTRL_DDR  DDRC

so this is just:

  DDRC |= (1 << 2);

so that set bit 2 to 1 to make the pin an output.

 

Somehow in your SAM chip there will be a way to make individual pins output (or input) and a way to set such output pins high/low when acting as outputs. You just need to replace each:

DDRx |= (1 << n);

with

sam_way_to_set_output(SomePort, bitN);

and each:

PORTx |= (1 << n);
PORTx &= ~(1 << n);

with:

sam_way_to_drive_output_high(SomePort, bitN);
sam_way_to_drive_output_low(SomePort, bitN);

A quick hunt around in:

 

https://spaces.atmel.com/gf/proj...

 

suggests that the direction stuff is going to have a lot to do with:

 


 208 __always_inline static void arch_ioport_set_port_dir(ioport_port_t port,
 209                 ioport_port_mask_t mask, unsigned char group_direction)
 210 {
 211         if (group_direction == IOPORT_DIR_OUTPUT) {
 212                 arch_ioport_port_to_base(port)->GPIO_ODERS = mask;
 213                 // Always disable the Schmitt trigger for output pins.
 214                 arch_ioport_port_to_base(port)->GPIO_STERC = mask;
 215         } else if (group_direction == IOPORT_DIR_INPUT) {
 216                 arch_ioport_port_to_base(port)->GPIO_ODERC = mask;
 217                 // Always enable the Schmitt trigger for input pins.
 218                 arch_ioport_port_to_base(port)->GPIO_STERS = mask;
 219         }
 220 }

So GPIO_ODER[S/C] (Set/Clear) seems to have a lot to do with setting the direction and:

 236 __always_inline static void arch_ioport_set_pin_level(ioport_pin_t pin,
 237                 bool level)
 238 {
 239         if (level) {
 240                 arch_ioport_pin_to_base(pin)->GPIO_OVRS = arch_ioport_pin_to_mask(pin);
 241         } else {
 242                 arch_ioport_pin_to_base(pin)->GPIO_OVRC = arch_ioport_pin_to_mask(pin);
 243         }
 244 }

seems to suggest that the GPIO_OVR[S/C] registers have a lot to do with actually driving the output pins to 0 or  1.

 

So GPIO_ODEx is a lot like the DDR stuff and GPIO_OVRx is a lot like the PORT stuff.

 

Oh and yet another way to approach this is to dig deep into Arduino. There are Arduinos based on mega AVR and there are Arduinos based on SAM Cortex M chips. Both will have LCD/HD44780 code with one doing it the "AVR way" with DDRs and PORTs and the ARM implementation probably hitting these GPIO_xxx registers I just described. So you can just see how they do it and copy the core wire-wiggling code from there.

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

PS forget the Arduino idea. I see how they achieve it and it's not pretty. At the highest level is the LiquidCrystal.cpp/.h code. this is completely abstracted from the hardware as it just uses pinMode() for setting input/output and digitalWrite() for setting outputs to 0's and 1's. All that is fairly inefficient.

 

OTOH I suppose LCD is so "slow" (you can take 100's of ms to get something on the screen!) so maybe the use of inefficient pinMode/digitalWrite does not matter?

 

if you do want to explore the ways Arduino does things for AVR versus the way it does them for SAM I'd suggest starting here:

 

https://github.com/arduino/Ardui...

 

If one follows that down into the AVR code for pinMode() and digitalWrite() you arrive here:

 

https://github.com/arduino/Ardui...

 

While if you go down the same route for the SAM way to do this you get to here:

 

https://github.com/arduino/Ardui...

 

That complicates things with yet another level of indirection (just when you thought Arduino couldn't be any more inefficient!) and arrives here:

 

https://github.com/arduino/Ardui...

 

Actually - to be honest - perhaps that pio.c is all you really need?

 

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

If you are looking for sheer MCU power then obviously the UC3C will beat the SAMC hands down. But for your application SAM C is a lot better.(Reasons below)

 

                                            AVR32                                               SAM C

Clock speed                          66MHz                                               48Mhz

Low latency IO access           Local Bus                                           ARM IOBUS

 

Advantage of UC3 being that there are lot of application notes and resources that you can use to build your application, but at the same time many code examples are not yet ported to run with the latest ASF drivers/IDE. Learning curve is very steep. Dev tools are costly.

 

Advantage of SAM C being that it is built with ruggedness from the ground up, it is a new device. The peripherals are of the latest revisions as well. Dev tools are cheap. It might be a little bit hard to understand the peripherals when you are using DMA + Event system combinations and such.

 

-----------------------------------------------------------------------------

 

Biggest advantage of using the SAMC IC to me is that the DMA has access to the PORT registers. This is really huge.

 

You can have a state machine, LCD frame buffer, edit in the frame buffer and when a change is made in frame buffer give LCD update command(Start DMA). So now a lot of processor time is saved. Even a 128*64 ST7565 will have write 1KB to update the whole screen(128bytes*8pages).

 

Refer to SAM C datasheet section 11.4.2(Figure 11-1) It is mentioned that the DMAC has access to the AHB-APB Bridge B, where the PORT peripheral is connected.

 

+ I think all this should be possible when the MCU is in sleep.

 

I would choose the SAMC just for the DMA port access alone.

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

Adithya Yuri wrote:
If you are looking for sheer MCU power then obviously the UC3C will beat the SAMC hands down.

But if you were looking for "sheer MCU power", you wouldn't choose a Cortex-M0 at all - would you?!

 

That is not the point of  Cortex-M0 !!

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

Agree I'd be using a 120..160MHz Cortex M4 if you want to beat a 66MHz UC3 and are just looking for raw power.

 

As UC3 is deprecated I'm not sure why anyone would now consider it anyway? Clearly Mchip/Atmel are going to pour their endeavours into Cortex for a 32 bit solution from now on. (though there are of course Mchip's own 32 bit offerings)

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

clawson wrote:

Agree I'd be using a 120..160MHz Cortex M4 if you want to beat a 66MHz UC3 and are just looking for raw power.

 

As UC3 is deprecated I'm not sure why anyone would now consider it anyway? Clearly Mchip/Atmel are going to pour their endeavours into Cortex for a 32 bit solution from now on. (though there are of course Mchip's own 32 bit offerings)

It seemed odd at the time, but when I was recently looking at forecasts for part availability from some supply chain analytic services, they tended to show approx 9+ years of estimated availability for many UC3 devices, but nothing longer than ~6 years for any of Atmel's Cortex M devices. That may be a factor to consider if you intend to have a relatively long production run.

Last Edited: Thu. Jan 12, 2017 - 06:10 PM