1
votes

I have a software project that is to use an A20-OLinuXino-MICRO-4GB board. I have no control of which board to use, so suggestions about alternates are not helpful.

That has an Allwinner A20 dual core Cortex-A7 processor (armv7a).

I tried doing the work from linux, but even with maximum priority, PTHREAD_EXPLICIT_SCHED and SCHED_FIFO, I could not prevent interrupts of a time critical section of control code (need to process every 10 microseconds, but got 40 microsecond gaps about 40 times a second).

With above constraint, suggestions to access SPI and UART from linux are not helpful either. The timing constraints on the second thread (whole cpu core being dedicated to it), mean that regular linux is not currently a viable alternative. Maybe a full real time linux would do the job, but I do not have the resources to get that built, just to see if it might work.

Current development environment:

Gentoo 4.3.3-hardened-r4
crossdev --kernel =3.18 --libc =2.21-r2 --binutils =2.24-r3 --gcc =4.8.5 

Building u-boot does not currently work with 5.x versions of gcc, so not too much room to move there.

So moved to writing as standalone code that is to be started from u-boot. No extra delays there, but now I am missing something to configure other modules of the core. When I try to initialize and configure SPI or UART devices (other than UART0, which is used for the u-boot console), all registers report zero, and stay there even after setting them. It acts as if there is nothing (no hardware) there. UART0 has reasonable/expected values, and configuring standard GPIO pins (input and output) works fine. Configuring the multiplexed GPIO pins to be used by SPI or UART also appear to work, but the modules stubbornly refuse to admit they exist.

Sample code, Makefile, and output for attempting to talk to the SPI modules can be found in the olimex forum. Note that the sample uses include files from the build of u-boot The main documentation used to create that code is A20 User Manual.

Has anyone worked with A20, Cortex-A7, armv7a or similar chips, and figured out how to get access to the capabilities outside of linux?

Does someone know where to get some better documentation about programming at that level?

The user manual I have has lots of information about register addresses, offsets, bit masks, but nothing in the way of code examples. I expect that a simple standalone C (or even assembler) example, that configured any of the (device) modules, and setup an interrupt to handle it, would be so helpful in figuring out the rest.

I actually got the SPI communications to work by bit-banging the I/O pins. That is not going to work for the UART, and SPI looks like a simpler case to work on first.

I've been programming for a lot of years on big systems, and some on very small (6502, 8085, arduinio) systems, but no real experience with development in this kind of environment. I'm not a kernel programmer, or anything close.

EDIT: I added the SPI1 Clock setup into the sample code, but all of the SPI register still show as all zeros, before and after setting them. The code changes:

#include <asm/arch-sunxi/clock_sun4i.h>
struct sunxi_ccm_reg * clockRegister;
#define SPI_SCLK_GATING_CLKON   0x80000000
#define SPI_CLK_SRC_OSC24M      0x00000000
#define SPI_CLK_DIV_RATION_8    0x00030000
// ...
printf ("SPI1 clk cfg %08x\n", clockRegister->spi1_clk_cfg);
clockRegister->spi1_clk_cfg =
  SPI_SCLK_GATING_CLKON | SPI_CLK_SRC_OSC24M | SPI_CLK_DIV_RATION_8 | 15;
printf ("SPI1 clk cfg %08x\n", clockRegister->spi1_clk_cfg);

That shows that the clock configuration DID change from 0x00000000 to 0x8003000f

1
I'd actually expect such a device to have either a FIFO or DMA attached to the peripheral.too honest for this site
It does (both). However, still need to enable, turn on, configure, initialize, SOMETHING the device/modulemMerlin
Since you're past the hurdles of compiling, booting and getting code to read and write MMIO, you can safely forget about Cortex-A7, this is all about peripherals on the A20 SoC, not whatever CPU happens to be wired up to them - if you dropped a MIPS core in there instead it wouldn't change the nature of the problem one bit. Typically on a mobile part you'd need some faffing around with PLLs and possibly regulators to get non-boot-essential peripherals clocked and powered - what does the A20 demand in that regard?Notlikethat
I have had others locally mention the possibility of needing to get different parts powered up. I have not found anything in the documentation for that. All I can find reference to is standby power management and that only splits between the RTC and everything else. The original question MIGHT be how to power it up.mMerlin
I DID find pieces for getting the SPI clock setup. That is not in the sample code, because I did not realize the clock might be needed before the configuration registers would be visible/active.mMerlin

1 Answers

0
votes

I also posted this question on the Microcontroller Based Projects google+ community, and Nikolai Kondrashov (spbnick) there spotted and correctly interpreted a pieced of information in the documentation.

To get access to the SPI registers, both the Gating AHB Clock for SPI«n» bit in AHB_GATTING_REG0, and the SCLK_GATING bit in SPI«n»_CLK_REG have to be set. Once those are set, the SPI«n» module registers themselves become accessible.

Potentially confusing side note: Setting the AHB gating bit first, then trying to reference the SPI register before setting the SCLK gating bit causes a total freeze. Since in a working application, those will normally be set together, this normally not an issue. Only showed up with the debug output, checking to see just when the SPI registers became visible.

I still find the documentation rather lacking. A few code examples would improve it a lot. This discovery is probably enough to get access to most of the SoC modules/devices.

Fairly minimal example code. This works with the same Makefile shown for the original question. Which pulls in an additional u-boot include file.

#include <common.h>

// Global memory pointers
uint32_t
    (*SPIarry1)[11],
    *SPI1_Cfg,
    *AHB_Gate0,
    *SPI1_ClkCfg;

int spi_test (void);

int spi_test (void)
{
    AHB_Gate0 = (uint32_t *)(SUNXI_CCM_BASE + 0x60);
    SPI1_ClkCfg = (uint32_t *)(SUNXI_CCM_BASE + 0xa4);
    SPIarry1 = (uint32_t (*)[11])SUNXI_SPI1_BASE;

    printf ("SPI1 Cfg Reg 0x%08x\n", (*SPIarry1)[2]);
    *SPI1_ClkCfg = 0x80000000;
    printf ("SPI1 Cfg Reg 0x%08x\n", (*SPIarry1)[2]);
    *AHB_Gate0 |= 0x00200000;
    printf ("SPI1 Cfg Reg 0x%08x\n", (*SPIarry1)[2]);
    return (0);
}

captured sample program output

## Starting application at 0x42000000 ...
SPI1 Cfg Reg 0x00000000
SPI1 Cfg Reg 0x00000000
SPI1 Cfg Reg 0x0012001c
## Application terminated, rc = 0x0