-2

I'm trying to run the following code in c on a beaglebone black (microcontroller running Debian). The code compiles but terminates right when the pwm_init() function is called.

No printf will execute after this line, even the first in the pwm_init() function.

I tried removing pwm_init(), and then wait_for_pwm() will run normally.

This is a code to setup an interrupt timer on the beaglebone in order to communicate with a DAC through SPI.

The code was running and could communicate before this adding.

/*
 *Filename: mems.c
 *SPI test program to communicate with AD5666 DAC on Micro Mirror Driver board */


#include <stdint.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include "iolib.h"
#include <unistd.h>


#define DELAY_NS 62500  // Timer period in ns

// PRU Interrupt control registers
#define PRU_INTC 0x00020000 // Start of PRU INTC registers TRM 4.3.1.2
#define PRU_INTC_GER ((volatile uint32_t *)(PRU_INTC + 0x10)) // Global Interrupt Enable, TRM 4.5.3.3
#define PRU_INTC_SICR ((volatile uint32_t *)(PRU_INTC + 0x24)) // Interrupt, TRM 4.5.3.6
#define PRU_INTC_GPIR ((volatile uint32_t *)(PRU_INTC + 0x80)) // Interrupt, TRM 4.5.3.11

// PRU ECAP control registers (i.e. PWM used as a timer)
#define ECAP 0x00030000 // ECAP0 offset, TRM 4.3.1.2
// Using APWM mode (TRM 15.3.2.1) to get timer (TRM 15.3.3.5.1)
#define ECAP_TSCTR ((volatile uint32_t *)(ECAP + 0x00)) // 32-bit counter register, TRM 15.3.4.1.1
#define ECAP_APRD ((volatile uint32_t *)(ECAP + 0x10)) // Period shadow, TRM 15.3.4.1.5, aka CAP3
#define ECAP_ECCTL2 ((volatile uint32_t *)(ECAP + 0x2a)) // Control 2, TRM 15.3.4.1.8
#define ECAP_ECEINT ((volatile uint16_t *)(ECAP + 0x2c)) // Enable interrupt, TRM 15.3.4.1.9
#define ECAP_ECCLR ((volatile uint16_t *)(ECAP + 0x30)) // Clear flags, TRM 15.3.4.1.11

// R30 is the GPIO register
// R31 is the interrupt register

#define NUMBER_OF_COEFS 87

int xn[NUMBER_OF_COEFS] = { 0 };

int ynn[NUMBER_OF_COEFS] = { 0 };

int xy[2];

static double coefs[NUMBER_OF_COEFS] = { -0.003874396983162784,-0.0037425007502381417,0.0007168162935488041,-0.0015837981969284466,0.001324731958160302,0.000940030114550933,0.002909179571989647,0.002970492669088027,0.0037475240063036684,0.003135242276391628,0.002431551570668268,0.0007465565198417194,-0.0010918847362976609,-0.0032610680167253635,-0.0050886443383995035,-0.0064219306251743396,-0.0067757336585719885,-0.00603689840577871,-0.004073405037328031,-0.001084864753089533,0.002607744624181485,0.006446336960328277,0.009805149887731802,0.012005211009068262,0.01248315933178856,0.010855477027307714,0.007038206816858291,0.0013011753812607633,-0.005726736257811221,-0.013085733616184817,-0.019608024169477135,-0.024024160014903175,-0.025137566107801428,-0.022018671074884637,-0.01412798218138592,-0.0014477915111131118,0.015482420337480308,0.03556527369143834,0.057256428960766804,0.07871540989639365,0.09799912606296178,0.1132905004893123,0.12311069228747347,0.1265004803246064,0.12311069228747347,0.1132905004893123,0.09799912606296178,0.07871540989639365,0.057256428960766804,0.03556527369143834,0.015482420337480308,-0.0014477915111131118,-0.01412798218138592,-0.022018671074884637,-0.025137566107801428,-0.024024160014903175,-0.019608024169477135,-0.013085733616184817,-0.005726736257811221,0.0013011753812607633,0.007038206816858291,0.010855477027307714,0.01248315933178856,0.012005211009068262,0.009805149887731802,0.006446336960328277,0.002607744624181485,-0.001084864753089533,-0.004073405037328031,-0.00603689840577871,-0.0067757336585719885,-0.0064219306251743396,-0.0050886443383995035,-0.0032610680167253635,-0.0010918847362976609,0.0007465565198417194,0.002431551570668268,0.003135242276391628,0.0037475240063036684,0.002970492669088027,0.002909179571989647,0.000940030114550933,0.001324731958160302,-0.0015837981969284466,0.0007168162935488041,-0.0037425007502381417,-0.003874396983162784};


#define REF_ON 0x01000008 //command to turn on internal VREF
#define X_OFFSET 3
#define Y_OFFSET 0
#define X_DRIVE  1
#define Y_DRIVE  2
#define SIZEMAT 2


float tabx[SIZEMAT] = { -100, 100 };
float taby[SIZEMAT] = { -100, 100 };


// Forward definitions
int convert_spi(int dac_val,int channel); //formats bytes for write function
inline void pwm_init();
inline void wait_for_pwm_timer();
int* fir_filterXY(int x, int y);



int main(int argc, char **argv){
    int i, fd, debug=0, loop=0, user_loop=0;
    int x_off=-1, y_off=-1;
    int x_val=-1, y_val=-1;
    int freq = -1;
    unsigned int buf = REF_ON;
    unsigned int dac_value = 1; // 0 to 65535 value to set dac output
    unsigned int spi_bytes = 0; // spi communication bytes to send
    char direction = 0; // Direction of triangle wave ramp

    fd = open("/dev/spidev1.0", O_RDWR);
    if(fd < 0) printf("spi failed to open\n");

    iolib_init();
    //Set LDAC control pin to output
    iolib_setdir(9,15,1);
    //Tying LDAC low will update dac channel as soon as it has new data
    pin_low(9,15); //sel0
    write(fd,&buf,4); //set internal vref on


        //  User loop
        int valx = 0;
        int valy = 0;

        int* ass;

        int assx = 0;
        int assy = 0;


        int i = 0;
        int freqcnt = 0;
        int freqi = 0;


        if (freq>1000)
        {
            freq = 1000;
        }
        if (freq<1)
        {
            freq = 1;
        }

        freqcnt = (int)((1000000000/DELAY_NS)/freq - 1);



        spi_bytes = convert_spi(32000, X_OFFSET);//format bytes for write function
        write(fd, &spi_bytes, 4);

        spi_bytes = convert_spi(32000, Y_OFFSET);//format bytes for write function
        write(fd, &spi_bytes, 4);   

        printf("In user loop with movement frequency of:%i\n", freq);

        pwm_init();

        valx = 32000;
        valy = 32000;

        assx = 32000;
        assy = 32000;

        printf("starting\n");
        while (1){
            wait_for_pwm_timer();

            spi_bytes = convert_spi(assx, X_DRIVE);//format bytes for write function
            write(fd, &spi_bytes, 4);

            spi_bytes = convert_spi(assy, Y_DRIVE);//format bytes for write function
            write(fd, &spi_bytes, 4);

            freqi++;

            if(freqi >= freqcnt){
                valx = (int)((tabx[i]+100) * 320);
                valy = (int)((taby[i]+100) * 320);
                freqi = 0;
                i++;
                if (i >= SIZEMAT)
                    i = 0;
            }

            ass = fir_filterXY(valx, valy);

            assx = *(ass);
            assy = *(ass+1);

        }




    return 0;
}



/* Function: convert_spi
 *
 * Takes a dac value (0-65535) and a dac channel (or all channels) and generates the appropriate 32bits to send to AD5666 via SPI
 *
 * INPUTS
 * dac_val: sets the voltage output with voltage output= 2.5*(dac_val/65535)
 * channel: selects which dac channel to update with dac_val. 0=DACA ,1=DACB, 2=DACC, 3=DACD, 16=all
 *
 * RETURNS
 * spi_data: integer value to send via spi using to update channel with new dac value
*/

int convert_spi(int dac_val,int channel){
    int spi_data=0;
    unsigned int nibble1;
    unsigned int nibble2;
    unsigned int nibble3;
    unsigned int nibble4;

    nibble1= dac_val & 0xF000;
    nibble2= dac_val & 0x0F00;
    nibble3= dac_val & 0x00F0;
    nibble4= dac_val & 0x000F;

    spi_data |=(nibble1>>4);
    spi_data |=(nibble2<<12);
    spi_data |=(nibble3<<12);
    spi_data |=(nibble4<<28);
    spi_data |=(channel<<12);
    return spi_data;

}


// Initializes the PWM timer, used to control output transitions.
// Every DELAY_NS nanoseconds, interrupt 15 will fire
inline void pwm_init(){
    printf("Intereupt setup");
    *PRU_INTC_GER = 1; // Enable global interrupts
    printf("1");
    *ECAP_APRD = DELAY_NS / 5 - 1; // Set the period in cycles of 5 ns
    printf("2");
    *ECAP_ECCTL2 = (1<<9) /* APWM */ | (1<<4) /* counting */;
    printf("3");
    *ECAP_TSCTR = 0; // Clear counter
    printf("4");
    *ECAP_ECEINT = 0x80; // Enable compare equal interrupt
    printf("5");
    *ECAP_ECCLR = 0xff; // Clear interrupt flags
    printf("done\n");
}

// Wait for the PWM timer to fire.
// see TRM 15.2.4.26x
inline void wait_for_pwm_timer() {
    register unsigned int __R31;
    while (!(__R31 & (1 << 30))) {} // Wait for timer compare interrupt
    *PRU_INTC_SICR = 15; // Clear interrupt
    *ECAP_ECCLR = 0xff; // Clear interrupt flags
}


int* fir_filterXY(int x, int y){

    int i = 0;
    double temp = 0;
    for (i = 0; i < NUMBER_OF_COEFS - 1; i++)
    {
        xn[i] = xn[i + 1]; //xn est au bout
    }
    xn[NUMBER_OF_COEFS-1] = x;

    //multiplier par les coef
    for (i = 0; i < NUMBER_OF_COEFS; i++)
    {
        temp += xn[NUMBER_OF_COEFS - i] * coefs[i];
    }
    xy[0] = (int)(temp+0.5);

    for (i = 0; i < NUMBER_OF_COEFS - 1; i++)
    {
        ynn[i] = ynn[i + 1];
    }
    ynn[NUMBER_OF_COEFS-1] = y;

    temp = 0;
    for (i = 0; i < NUMBER_OF_COEFS; i++)
    {
        temp += ynn[NUMBER_OF_COEFS - i] * coefs[i];
    }
    xy[1] = (int)(temp + 0.5);

    return xy;

}
Pablo
  • 12,254
  • 3
  • 31
  • 52
Léo Caussan
  • 19
  • 1
  • 6
  • 1
    You should try to submit a [mcve], your code is too long to read. – Patrick Mevzek Feb 16 '18 at 02:19
  • Did you try removing things? Sacrficie the attempt to setup anything and just try to get the first print inside pwm_init() executed. If necessary remoce everything down to a HelloWorld, then start adding again. Note when the misbehavior returns. – Yunnosch Sep 15 '18 at 05:58

1 Answers1

0

A couple of recommendations:

  • printf() can occasionally lag in its output. To be very sure that nothing is being printed, call fflush(stdout) after the print line. This will flush the stdout buffer-- if nothing is printed after the flush, then the println() really is not being executed.

  • How is your program terminating? If execution does not continue past the pwm_init() function, that almost certainly means that something bad is happening with the memory locations you are writing to. Double check that your register values are correct and that your program isn't being killed due to invalid memory access.

Reece Stevens
  • 384
  • 2
  • 7
  • Tried the fflush but still nothing. The problem deaper than that, I tried creating a basic test function with only a printf in it and execute it juste before the pwm_init but again nothing. Also, the program terminates because nothing after that happen, it doesnt print anything else or enter any pther function. It just goes back to the terminal on the Beaglebone – Léo Caussan Feb 15 '18 at 23:11
  • try using fprintf(stderr,"..."); for outputting messages. Also, 'if(fd < 0) printf("spi failed to open\n");' will print a message if the 'open' fails, but while it prints an error message, your program keeps running and could later on use an invalid file descriptor, for example in this line ' write(fd, &spi_bytes, 4);'. Finally, in this line 'freqcnt = (int)((1000000000/DELAY_NS)/freq - 1);' it appears that freq is 1, thus you have division by zero. – thurizas Feb 15 '18 at 23:20
  • I had no problem before when running my code. fprintf() doesnt change anything. freq -1 is executed after the division so no division by zero. – Léo Caussan Feb 15 '18 at 23:25
  • Is there a stack trace or anything that prints to the console when the program runs? Could you post the command you are using to compile your program? – Reece Stevens Feb 15 '18 at 23:28
  • hmmm....freq is set to -1 on line 4 of main. Reading down in main I do not see freq begin used till the two if blocks starting on line 36. The first if block is not taken, but the second one is executed so on line 42 we have freq set to 1. Two lines later we have 'freq-1' which should result in division by zero. – thurizas Feb 15 '18 at 23:32
  • I printed freqcnt and it prints out the good value. No division by zero – Léo Caussan Feb 15 '18 at 23:38
  • Also I compile it using a Makefile. I then use **sudo ./mems -u 10** to execute the code. (arguments handling not shown because code would've been too confusing but this basically run this piece of code with a freq = 10) – Léo Caussan Feb 15 '18 at 23:40