I’ve tried to find some example of ADC reading by PRU for my project, but I couldn’t find it.
And I made that of source code and attach here for some people who have the same problem with me.
I hope it will be helpful.
[ AM335x ARM-CORE PRU ADC Example ]
- Sequence of example
- Install compiling environment of PRU
- Enable PRU
- Enable ADC
- Example source
- This example source collects ADC data from AIN0 pin with 16khz sampling rate.
- The collected data are saved into “Results.txt” file.
- The example source are “Makefile”, “ADCCollector.c”, “ADCCollector.p”, “ADCCollector.hp”
[ Install compile environment ]
- Get a copy of the am335x_pru_package → https://github.com/beagleboard/am335x_pru_package
You also can download the am335x_pru_package here → https://github.com/beagleboard/am335x_pru_package/archive/master.zip - If you downloaded the archive, unpack it somewhere under your home directory.
- Make a new directory /usr/include/pruss/ and copy the files prussdrv.h
and pruss_intc_mapping.h into it (from am335x_pru_package-master/pru_sw/app_loader/include).
Check the permissions; if you used the .zip file, these headers will likely have the execute bits on.
It doesn’t really hurt anything, but is certainly not what you want. - Change directory to am335x_pru_package-master/pru_sw/app_loader/interface
then run: CROSS_COMPILE= make (note the space between the = and the command). - The previous step should have created four files in am335x_pru_package-master/pru_sw/app_loader/lib: libprussdrv.a, libprussdrvd.a, libprussdrvd.so and libprussdrv.so.
Copy these all to /usr/lib then run ldconfig. - Change directory to am335x_pru_package-master/pru_sw/utils/pasm_source
then run source linuxbuild to create a pasm executable one directory level up.
- If linuxbuild doesn’t have permission to execution, give the permission by run this
: chmod +x linuxbuild
Copy it to /usr/bin and make sure you can run it.
If you invoke it with no arguments, you should get a usage statement.
[ Enable PRU ]
Before using PRU, we need to enable the PRU core, you can do it as shown below
echo BB-BONE-PRU-01 > /sys/devices/bone_capemgr.8/slots
[ Enable ADC ]
Before using ADC, we also need to enable ADC, you can do it as shown below
echo cape-bone-iio > /sys/devices/bone_capemgr.*/slots
[ ADC Example - Makefile]
CFLAGS+=-Wall -Werror
LDLIBS+= -lpthread -lprussdrv
all: ADCCollector.bin ADCCollector
clean:
rm -f ADCCollector *.o *.bin
ADCCollector.bin: ADCCollector.p
pasm -b $^
ADCCollector: ADCCollector.o
[ ADC Example - ADCCollector.p]
// Developed by Youngtae Jo in Kangwon National University (April-2014)
// This program collects ADC from AIN0 with certain sampling rate.
// The collected data are stored into PRU shared memory(buffer) first.
// The host program(ADCCollector.c) will read the stored ADC data
// This program uses double buffering technique.
// The host program can recognize the buffer status by buffer status variable
// 0 means empty, 1 means first buffer is ready, 2 means second buffer is ready.
// When each buffer is ready, host program read ADC data from the buffer.
.origin 0 // offset of the start of the code in PRU memory
.entrypoint START // program entry point, used by debugger only
#include “ADCCollector.hp”
#define BUFF_SIZE 0x00000FA0 //Total buff size: 4kbyte(Each buffer has 2kbyte: 500 piece of data)
#define HALF_SIZE BUFF_SIZE / 2
#define SAMPLING_RATE 16000 //Sampling rate(16khz)
#define DELAY_MICRO_SECONDS (1000000 / SAMPLING_RATE) //Delay by sampling rate
#define CLOCK 200000000 // PRU is always clocked at 200MHz
#define CLOCKS_PER_LOOP 2 // loop contains two instructions, one clock each
#define DELAYCOUNT DELAY_MICRO_SECONDS * CLOCK / CLOCKS_PER_LOOP / 1000 / 1000 * 3
.macro DELAY
MOV r10, DELAYCOUNT
DELAY:
SUB r10, r10, 1
QBNE DELAY, r10, 0
.endm
.macro READADC
//Initialize buffer status (0: empty, 1: first buffer is ready, 2: second buffer is ready)
MOV r2, 0
SBCO r2, CONST_PRUSHAREDRAM, 0, 4
INITV:
MOV r5, 0 //Shared RAM address of ADC Saving position
MOV r6, BUFF_SIZE //Counting variable
READ:
//Read ADC from FIFO0DATA
MOV r2, 0x44E0D100
LBBO r3, r2, 0, 4
//Add address counting
ADD r5, r5, 4
//Write ADC to PRU Shared RAM
SBCO r3, CONST_PRUSHAREDRAM, r5, 4
DELAY
SUB r6, r6, 4
MOV r2, HALF_SIZE
QBEQ CHBUFFSTATUS1, r6, r2 //If first buffer is ready
QBEQ CHBUFFSTATUS2, r6, 0 //If second buffer is ready
QBA READ
//Change buffer status to 1
CHBUFFSTATUS1:
MOV r2, 1
SBCO r2, CONST_PRUSHAREDRAM, 0, 4
QBA READ
//Change buffer status to 2
CHBUFFSTATUS2:
MOV r2, 2
SBCO r2, CONST_PRUSHAREDRAM, 0, 4
QBA INITV
//Send event to host program
MOV r31.b0, PRU0_ARM_INTERRUPT+16
HALT
.endm
// Starting point
START:
// Enable OCP master port
LBCO r0, CONST_PRUCFG, 4, 4
CLR r0, r0, 4
SBCO r0, CONST_PRUCFG, 4, 4
//C28 will point to 0x00012000 (PRU shared RAM)
MOV r0, 0x00000120
MOV r1, CTPPR_0
ST32 r0, r1
//Init ADC CTRL register
MOV r2, 0x44E0D040
MOV r3, 0x00000005
SBBO r3, r2, 0, 4
//Enable ADC STEPCONFIG 1
MOV r2, 0x44E0D054
MOV r3, 0x00000002
SBBO r3, r2, 0, 4
//Init ADC STEPCONFIG 1
MOV r2, 0x44E0D064
MOV r3, 0x00000001 //continuous mode
SBBO r3, r2, 0, 4
//Read ADC and FIFOCOUNT
READADC
[ ADC Example - ADCCollector.c]
/******************************************************************************
- Include Files *
******************************************************************************/
// Standard header files
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
// Driver header file
#include <pruss/prussdrv.h>
#include <pruss/pruss_intc_mapping.h>
/******************************************************************************
- Local Macro Declarations *
******************************************************************************/
#define PRU_NUM 0
#define OFFSET_SHAREDRAM 2048 //equivalent with 0x00002000
#define PRUSS0_SHARED_DATARAM 4
#define SAMPLING_RATE 16000 //16khz
#define BUFF_LENGTH SAMPLING_RATE
#define PRU_SHARED_BUFF_SIZE 500
#define CNT_ONE_SEC SAMPLING_RATE / PRU_SHARED_BUFF_SIZE
/******************************************************************************
- Functions declarations *
******************************************************************************/
static void Enable_ADC();
static void Enable_PRU();
static unsigned int ProcessingADC1(unsigned int value);
/******************************************************************************
- Global variable Declarations *
******************************************************************************/
static void *sharedMem;
static unsigned int *sharedMem_int;
/******************************************************************************
- Main *
*****************************************************************************/
int main (int argc, char argv[])
{
FILE *fp_out;
unsigned int ret;
tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;
int i = 0, cnt = 0, total_cnt = 0;
int target_buff = 1;
int sampling_period = 0;
if(argc != 2){
printf("\tERROR: Sampling period is required by second\n");
printf("\t %s [sampling period]\n", argv[0]);
return 0;
}
sampling_period = atoi(argv[1]);
/* Enable PRU /
Enable_PRU();
/ Enable ADC /
Enable_ADC();
/ Initializing PRU /
prussdrv_init();
ret = prussdrv_open(PRU_EVTOUT_0);
if (ret){
printf("\tERROR: prussdrv_open open failed\n");
return (ret);
}
prussdrv_pruintc_init(&pruss_intc_initdata);
printf("\tINFO: Initializing.\r\n");
prussdrv_map_prumem(PRUSS0_SHARED_DATARAM, &sharedMem);
sharedMem_int = (unsigned int) sharedMem;
/* Open save file */
fp_out = fopen(“Results.txt”, “w”);
if(fp_out == NULL){
printf("\tERROR: file open failed\n");
return 0;
}
/* Executing PRU. /
printf("\tINFO: Sampling is started for %d seconds\n", sampling_period);
printf("\tINFO: Collecting");
prussdrv_exec_program (PRU_NUM, “./ADCCollector.bin”);
/ Read ADC */
while(1){
while(1){
if(sharedMem_int[OFFSET_SHAREDRAM] == 1 && target_buff == 1){ // First buffer is ready
for(i=0; i<PRU_SHARED_BUFF_SIZE; i++){
fprintf(fp_out, “%d\n”, ProcessingADC1(sharedMem_int[OFFSET_SHAREDRAM + 1 + i]));
}
target_buff = 2;
break;
}else if(sharedMem_int[OFFSET_SHAREDRAM] == 2 && target_buff == 2){ // Second buffer is ready
for(i=0; i<PRU_SHARED_BUFF_SIZE; i++){
fprintf(fp_out, “%d\n”, ProcessingADC1(sharedMem_int[OFFSET_SHAREDRAM + PRU_SHARED_BUFF_SIZE + 1 + i]));
}
target_buff = 1;
break;
}
}
if(++cnt == CNT_ONE_SEC){
printf(".");
total_cnt += cnt;
cnt = 0;
}
if(total_cnt == CNT_ONE_SEC * sampling_period){
printf("\n\tINFO: Sampling completed …\n");
break;
}
}
fclose(fp_out);
printf("\tINFO: PRU completed transfer.\r\n");
prussdrv_pru_clear_event (PRU_EVTOUT_0, PRU0_ARM_INTERRUPT);
/* Disable PRU*/
prussdrv_pru_disable(PRU_NUM);
prussdrv_exit();
return(0);
}
/*****************************************************************************
- Local Function Definitions *
****************************************************************************/
/ Enable ADC */
static int Enable_ADC()
{
FILE *ain;
ain = fopen("/sys/devices/bone_capemgr.8/slots", “w”);
if(!ain){
printf("\tERROR: /sys/devices/bone_capemgr.8/slots open failed\n");
return -1;
}
fseek(ain, 0, SEEK_SET);
fprintf(ain, “cape-bone-iio”);
fflush(ain);
return 0;
}
/* Enable PRU */
static int Enable_PRU()
{
FILE *ain;
ain = fopen("/sys/devices/bone_capemgr.8/slots", “w”);
if(!ain){
printf("\tERROR: /sys/devices/bone_capemgr.8/slots open failed\n");
return -1;
}
fseek(ain, 0, SEEK_SET);
fprintf(ain, “BB-BONE-PRU-01”);
fflush(ain);
return 0;
}
/*
- FIFO0DATA register includes both ADC and channelID
- so we need to remove the channelID
*/
static unsigned int ProcessingADC1(unsigned int value)
{
unsigned int result = 0;
result = value << 20;
result = result >> 20;
return result;
}
[ ADC Example - ADCCollector.hp]
// *****************************************************************************/
// file: PRU_memAccess_DDR_PRUsharedRAM.hp
//
// brief: PRU_memAccess_DDR_PRUsharedRAM assembly constants.
//
//
// © Copyright 2012, Texas Instruments, Inc
//
// author M. Watkins
// *****************************************************************************/
#ifndef PRU_memAccess_DDR_PRUsharedRAM_HP
#define PRU_memAccess_DDR_PRUsharedRAM_HP
// ***************************************
// * Global Macro definitions *
// ***************************************
// Refer to this mapping in the file - \prussdrv\include\pruss_intc_mapping.h
#define PRU0_PRU1_INTERRUPT 17
#define PRU1_PRU0_INTERRUPT 18
#define PRU0_ARM_INTERRUPT 19
#define PRU1_ARM_INTERRUPT 20
#define ARM_PRU0_INTERRUPT 21
#define ARM_PRU1_INTERRUPT 22
#define CONST_PRUCFG C4
#define CONST_PRUDRAM C24
#define CONST_PRUSHAREDRAM C28
#define CONST_DDR C31
// Address for the Constant table Block Index Register (CTBIR)
#define CTBIR 0x22020
// Address for the Constant table Programmable Pointer Register 0(CTPPR_0)
#define CTPPR_0 0x22028
// Address for the Constant table Programmable Pointer Register 1(CTPPR_1)
#define CTPPR_1 0x2202C
.macro LD32
.mparam dst,src
LBBO dst,src,#0x00,4
.endm
.macro LD16
.mparam dst,src
LBBO dst,src,#0x00,2
.endm
.macro LD8
.mparam dst,src
LBBO dst,src,#0x00,1
.endm
.macro ST32
.mparam src,dst
SBBO src,dst,#0x00,4
.endm
.macro ST16
.mparam src,dst
SBBO src,dst,#0x00,2
.endm
.macro ST8
.mparam src,dst
SBBO src,dst,#0x00,1
.endm
// ***************************************
// * Global Structure Definitions *
// ***************************************
.struct Global
.u32 regPointer
.u32 regVal
.ends
// ***************************************
// * Global Register Assignments *
// ***************************************
.assign Global, r2, *, global
#endif //PRU_memAccess_DDR_PRUsharedRAM