Low Level programing using c++

Hi all,

This might sound like a weird question...
Just a quick query really, since the new Due's Atmel Arm bases Cortex M3 uses Thumb2 as low level instruction set, how easy (or hard) is it to write stuff on that level in C++? (if needed, probably not)
Bypassing Wire of course.

Thanks in advance.
Deian

I assume Thumb2 is the name of the processor's machine language (or assembly language) instruction set????

I've never tried it...

I think you have to check your compiler's documentation. Look for "assembly". "ASSEMBLER", or "ASM". I don't have my C/C++ references handy, and I don't remember if this is part of the ISO/ANSI language standard, or if it's optional. (If you program purely in assembly, then technically you use an assembler instead of a compiler.)

I found [u]this[/u] for the arduino/AVR processor.

I believe it gets rather tricky when you combine C/C++ with assembly because you have to save the state of the processor (internal registers, etc.) and restore them before returning to your C/C++ program. Maybe the compiler sometimes takes care of that, but I'm not sure.

as long as you can find a compiler that supports that instruction set, you can write C++ code for it easily.

You could even wrap the registers in classes, so instead of saying

DDRB |= _BV(3);

you might say

Port portB(PINB, PORTB, DDRB);
portB.setDir(3, OUTPUT);

which makes it more C++-y and less C-y

The Due is using the CMSIS abstraction layer, this defines a heap of structures with elements that match the underlying hardware, so you can reference registers directly like this

NVIC->ISER = x;

to write x into the Nested Vector Interrupt Controller’s ISER register. Same applies for the UARTs, timers and everything else. NVIC in this case is the address of the controller and ISER and element in the structure at the same offset as the ISER reg in the hardware.

Another example

LPC_UART0->THR = *BufferPtr;

This writes a character from a buffer into the Transmit Holding Reg of UART0. (NOTE: this is for an LPC, the names will change for SAM but the basic idea is the same).

So all the places we used to do

DDRB |= _BV(3);

Will now be something like

PIOB->PIO_SODR |= (1 << 3); // _BV may still work if the macro has been ported

But don’t quote me on the names used, I’m not very familiar with the SAM register names yet.

I assume Thumb2 is the name of the processor’s machine language (or assembly language) instruction set

Correct.

As for genuine assembly language, given the above and the great optimisation of modern compilers it’s hard to imagine when it would be required, but the GCC compiler allows it in the same way we currently do inline assembler with the AVRs. eg

asm (“valid asm code here”);

An alternative is to have a separate assembly file with just ASM code in that and link it into the project.


Rob

deian:
Bypassing Wire of course.

What do you mean?

i meant Wiring, you'd use wiring first, then if that isn't the answer to ur dreams u do it in C/C++, then if that doesn't give u the power to do what you want then it's assembler (thumb2).
It was just a theoretical question really. I don't know much about it tbh, it just that we are starting to cover assembly language based on ARM7 in uni now.

One suggestion and one question -

I have checked this procedure for viewing the assembly of both Teensy3.0 and Arduino Due, it works on both the new platforms as well as the current AVR compiler and will give you an idea of what you are up against if you want to go that low -

And the question, does anyone have a link to a good document or book on the CMSIS ?

Thanks

Duane B

rcarduino.blogspot.com

I know it's awful stuff, but it's nice to know the possibilities, who knows, I might get into it if I enjoy this microprocessor and digital module in yr 2 uni.
Thanks

then if that doesn't give u the power to do what you want then it's assembler (thumb2).

Thumb isn't about speed/power efficiency, it's about space efficiency, and I can't imagine why anyone would want to write any explicitly.

I work on systems running to many MLOCs of C and C++, and about the only time we ever see ARM assembler is for a very few critical memory fill or copy operations.

Disclaimer: I can (just about) read ARM assembler (very, very occasionally, I have to follow code down to debug it), but I've certainly never written any.

Hi,
Like many here ARM is totally new to me, can anyone just expand a little on what Thumb, Thumb2 and CMSIS are and how they relate ?

Duane B

rcarduino.blogspot.com

ARM is a RISC processor, and all native instructions are 32 bits wide.
Thumb is a special mode the processor has that allows it to execute a set of 16 bit instructions, allowing you, in theory, to get twice as many instructions into a given memory space. Obviously, there are compromises to be made, usually performance.
Thumb2 is a further extension, with the aim of reducing the space/performance trade-off.

Thumb/Thumb2 are a subset of the full ARM instruction set, the instructions fit into 16 bits and therefore are more efficient WRT flash usage.

CMSIS is really (AFAIK) just a lot of defines and structs that tend to provide an abstraction layer, but it’s only one level about dicking around with raw addresses. So my example

LPC_UART0->THR

is really just a human-friendly version of the address 0x40008000, while the Transmit Holding Reg of UART1

LPC_UART1->THR

is at 0x4000C000

Here is an example of the USART0 part of a header file that implements the CMSIS stuff

typedef struct {                            /*!< (@ 0x40008000) UART0 Structure        */
  
  union {
    __IO uint32_t DLL;                      /*!< (@ 0x40008000) Divisor Latch LSB. Least significant byte of the baud rate divisor value. The full divisor is used to generate a baud rate from the fractional rate divider. (DLAB = 1) */
    __IO uint32_t THR;                      /*!< (@ 0x40008000) Transmit Holding Register. The next character to be transmitted is written here. (DLAB=0) */
    __I  uint32_t RBR;                      /*!< (@ 0x40008000) Receiver Buffer Register. Contains the next received character to be read. (DLAB=0) */
  };
  
  union {
    __IO uint32_t IER;                      /*!< (@ 0x40008004) Interrupt Enable Register. Contains individual interrupt enable bits for the 7 potential UART interrupts. (DLAB=0) */
    __IO uint32_t DLM;                      /*!< (@ 0x40008004) Divisor Latch MSB. Most significant byte of the baud rate divisor value. The full divisor is used to generate a baud rate from the fractional rate divider. (DLAB = 1) */
  };
  
  union {
    __IO uint32_t FCR;                      /*!< (@ 0x40008008) FIFO Control Register. Controls UART FIFO usage and modes. */
    __I  uint32_t IIR;                      /*!< (@ 0x40008008) Interrupt ID Register. Identifies which interrupt(s) are pending. */
  };
  __IO uint32_t LCR;                        /*!< (@ 0x4000800C) Line Control Register. Contains controls for frame formatting and break generation. */
  __IO uint32_t MCR;                        /*!< (@ 0x40008010) Modem control register */
  __I  uint32_t LSR;                        /*!< (@ 0x40008014) Line Status Register. Contains flags for transmit and receive status, including line errors. */
  __I  uint32_t MSR;                        /*!< (@ 0x40008018) Modem status register  */
  __IO uint32_t SCR;                        /*!< (@ 0x4000801C) Scratch Pad Register. Eight-bit temporary storage for software. */
  __IO uint32_t ACR;                        /*!< (@ 0x40008020) Auto-baud Control Register. Contains controls for the auto-baud feature. */
  __I  uint32_t RESERVED0[1];
  __IO uint32_t FDR;                        /*!< (@ 0x40008028) Fractional Divider Register. Generates a clock input for the baud rate divider. */
  __I  uint32_t RESERVED1[1];
  __IO uint32_t TER;                        /*!< (@ 0x40008030) Transmit Enable Register. Turns off UART transmitter for use with software flow control. */
  __I  uint32_t RESERVED2[6];
  __IO uint32_t RS485CTRL;                  /*!< (@ 0x4000804C) RS-485/EIA-485 Control. Contains controls to configure various aspects of RS-485/EIA-485 modes. */
  __IO uint32_t RS485ADRMATCH;              /*!< (@ 0x40008050) RS-485/EIA-485 address match. Contains the address match value for RS-485/EIA-485 mode. */
  __IO uint32_t RS485DLY;                   /*!< (@ 0x40008054) RS-485/EIA-485 direction control delay. */
  __I  uint32_t FIFOLVL;                    /*!< (@ 0x40008058) FIFO Level register. Provides the current fill levels of the transmit and receive FIFOs. */
} LPC_UART0_Type;

The SAM will have similar but I’m having a hard time finding it in the 1.5 install.


Rob

Whether it is thumb2 or thumb200 has no bearing on if it can be coded via C or C++.

OK, found it

\hardware\arduino\sam\system\CMSIS\Device\ATMEL\sam3xa\include\sam3x8e.h

Gives you the base addresses of the peripherals on the SAM3X8E, and

\hardware\arduino\sam\system\CMSIS\Device\ATMEL\sam3xa\include\instance*

Holds a stack of .H files (one for each peripheral) with all the defines for the register addresses.

So at first glance it seems that the way the SAM is done is different to the LPC implementation.

LPC_UART0->THR

on an LPC would be

REG_USART0_THR

on the Due. Kind of makes you wonder what the point of CMSIS is, not much of an abstraction layer for the peripherals but maybe OK for the ARM core itself.

Where are all the beta testers, they should be experts by now and be able to describe this.


Rob