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
1. Install compiling environment of PRU
2. Enable PRU
3. Enable ADC
4. 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 ]
2. If you downloaded the archive, unpack it somewhere under your home directory.
3. 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.
4. 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).
5. 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.
6. 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.
//
//
// (C) 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_