]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - apps/tida01555.git/blob - ARM_User_Space_App/arm_user_space_app.c
More description user space app display output
[apps/tida01555.git] / ARM_User_Space_App / arm_user_space_app.c
1 /*
2  * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
3  *
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  *      * Redistributions of source code must retain the above copyright
10  *        notice, this list of conditions and the following disclaimer.
11  *
12  *      * Redistributions in binary form must reproduce the above copyright
13  *        notice, this list of conditions and the following disclaimer in the
14  *        documentation and/or other materials provided with the
15  *        distribution.
16  *
17  *      * Neither the name of Texas Instruments Incorporated nor the names of
18  *        its contributors may be used to endorse or promote products derived
19  *        from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
34 #include <sys/types.h>
35 #include <unistd.h>
36 #include <sys/stat.h>
37 #include <sys/mman.h>
38 #include <fcntl.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <stdint.h>
43 #include <math.h>
44 #include <time.h>
45 #include <string.h>
46 #include <sched.h>
47 #include <pthread.h>
48 #include <limits.h>
49 #include <ncurses.h>
51 #define PING_ADDR               0x9FFC0000
52 #define PONG_ADDR               0x9FFE0000
53 #define PING                    0
54 #define PONG                    1
55 #define DATA_READY              0x0000FFFF
56 #define IN_PROGRESS             0x00000000
57 #define NUM_CHANNELS            48
58 #define NUM_DEVICES             6
59 #define NUM_SAMPLES_PER_CYCLE   640
60 #define MAX_CSV_SAMPLES         65536
62 volatile float min[NUM_CHANNELS];
63 volatile float max[NUM_CHANNELS];
64 volatile float result[NUM_CHANNELS];
65 volatile uint16_t compensation, delay;
66 volatile int16_t csv_samples[MAX_CSV_SAMPLES];
67 volatile uint16_t csv_channel = 0;
68 volatile uint32_t csv_sample_num = 0;
69 volatile uint32_t csv_counter = 0;
71 struct buffer {
72         uint32_t flags;
73         uint32_t comp_delay;
74         uint32_t samples[NUM_CHANNELS*NUM_SAMPLES_PER_CYCLE];
75 };
77 void *capture_func(void *data)
78 {
79         int i, j;
80         struct buffer *ping_ptr, *pong_ptr;
81         uint32_t samples[NUM_CHANNELS*NUM_SAMPLES_PER_CYCLE];
82         uint64_t cur_square_sum = 0;
83         int16_t cur_min = INT16_MAX;
84         int16_t cur_max = INT16_MIN;
85         int16_t signed_val;
86         struct timespec sleep;
87         uint8_t curr_buff = PING;
89         /* Open the /dev/mem device to access the shared buffers */
90         int fd = open("/dev/mem",O_RDWR|O_SYNC);
91         if(fd < 0)
92         {
93                 printf("Can't open /dev/mem\n");
94                 return NULL;
95         }
96         /* mmap 128kB ping and pong buffers */
97         ping_ptr = (struct buffer *) mmap(0, getpagesize()*32, PROT_READ|PROT_WRITE, MAP_SHARED, fd, PING_ADDR);
98         pong_ptr = (struct buffer *) mmap(0, getpagesize()*32, PROT_READ|PROT_WRITE, MAP_SHARED, fd, PONG_ADDR);
99         if(ping_ptr == NULL || pong_ptr == NULL)
100         {
101                 printf("Can't mmap\n");
102                 return NULL;
103         }
105         /* put sine wave in memory */
106         /*
107         for(i = 0; i < NUM_SAMPLES_PER_CYCLE; i++) {
108                 for(j = 0; j < NUM_CHANNELS; j++) {
109                         ping_ptr->samples[i*NUM_CHANNELS+j] = sine_wave[i];
110                         pong_ptr->samples[i*NUM_CHANNELS+j] = sine_wave[i];
111                 }
112         }
113         */
115         /* Configure the sleep delay to 250us */
116         sleep.tv_sec = 0;
117         sleep.tv_nsec = 250000L;
119         /* Wait until PING buffer is in progress before beginning */
120         while (ping_ptr->flags != IN_PROGRESS)
121                 nanosleep(&sleep, NULL);
123         while(1) {
124                 /* Wait for the buffers to be ready and then memcpy the sample
125                  * data to local memory. If the buffer is not ready yet, go to
126                  * sleep for 250us before checking again. This thread is
127                  * running at the highest priority so it needs to sleep when
128                  * not in use or it will starve all other threads.
129                  */
130                 if (curr_buff == PING) {
131                         while (ping_ptr->flags != DATA_READY)
132                                 nanosleep(&sleep, NULL);
133                         compensation = ping_ptr->comp_delay >> 16;
134                         delay = ping_ptr->comp_delay & 0xFFFF;
135                         memcpy(samples, ping_ptr->samples, sizeof(samples));
136                         curr_buff = PONG;
137                 }
138                 else {
139                         while (pong_ptr->flags != DATA_READY)
140                                 nanosleep(&sleep, NULL);
141                         compensation = pong_ptr->comp_delay >> 16;
142                         delay = pong_ptr->comp_delay & 0xFFFF;
143                         memcpy(samples, pong_ptr->samples, sizeof(samples));
144                         curr_buff = PING;
145                 }
147                 /* Iterate through a full cycle for each channel */
148                 for (j = 0; j < NUM_CHANNELS; j++) {
149                         for(i = 0; i < NUM_SAMPLES_PER_CYCLE; i++) {
150                                 /* Convert the ADC code to it's signed equivalent */
151                                 signed_val = (uint16_t)samples[i*NUM_CHANNELS+j] - 0x8000;
152                                 if (j == csv_channel && csv_counter < csv_sample_num)
153                                         csv_samples[csv_counter++] = signed_val;
154                                 /* Check for min and max values throughout the cycle */
155                                 if(signed_val < cur_min)
156                                         cur_min = signed_val;
157                                 if(signed_val > cur_max)
158                                         cur_max = signed_val;
159                                 /* Accumulate the squares to be used in the RMS calc */
160                                 cur_square_sum += signed_val * signed_val;
161                         }
162                         /* Convert the min and max from ADC codes to voltages and store them */
163                         min[j] = (float)cur_min * 0.0003125;
164                         max[j] = (float)cur_max * 0.0003125;
165                         /* Complete the Root Mean Square (RMS) calculation for this channel and store it */
166                         result[j] = (sqrt(cur_square_sum / 640.0)) * 0.0003125;
167                         /* Reset the current variables to defaults for the next channel iteration */
168                         cur_min = INT16_MAX;
169                         cur_max = INT16_MIN;
170                         cur_square_sum = 0;
171                 }
172         }
174         return NULL;
177 void *print_func(void *data)
179         int i;
180         float frequency;
182         /* Initialize the screen */
183         initscr();
184         /* Set the timeout to 250ms for waiting for user input */
185         timeout(250);
186         curs_set(0);
188         /* Print each channel's min, max, and RMS values to the screen */
189         while (1) {
190                 for(i = 0; i < NUM_CHANNELS/2; i++) {
191                         mvprintw(i, 0, "D%d:C%d Vpp:[%.3f,%.3f] ", i/8+1, i%8, min[i], max[i]);
192                         mvprintw(i, 28, "RMS:%.3f", result[i]);
193                         mvprintw(i, 39, "| D%d:C%d Vpp:[%.3f,%.3f] ", (i+NUM_CHANNELS/2)/8+1, i%8, min[i+NUM_CHANNELS/2], max[i+NUM_CHANNELS/2]);
194                         mvprintw(i, 69, "RMS:%.3f", result[i+NUM_CHANNELS/2]);
195                 }
197                 frequency = (1.0 / ((delay * NUM_CHANNELS / NUM_DEVICES + compensation) * 0.000000005)) / NUM_SAMPLES_PER_CYCLE;
198                 
199                 mvprintw(NUM_CHANNELS/2 + 1, 0, "Delay:%d, Compensation:%d", delay, compensation);
200                 mvprintw(NUM_CHANNELS/2 + 2, 0, "Estimated Frequency:%.3f Hz", frequency);
201                 mvprintw(NUM_CHANNELS/2 + 4, 0, "Press any key to exit");
202                 /* Refresh the screen with the latest data */
203                 refresh();
204                 /* If a character is received then exit the while(1) loop */
205                 if(getch() != -1)
206                         break;
207         }
209         /* Close the window */
210         endwin();
212         return NULL;
215 int main(int argc, char* argv[])
217         struct sched_param param;
218         pthread_attr_t attr;
219         pthread_t capture_thread, print_thread;
220         int ret;
221         uint32_t i;
222         FILE *fp;
224         /* Check for command line arguments requesting to create a CSV file
225          * argv[1] - CSV file name
226          * argv[2] - Channel number to store results from
227          * argv[3] - Number of samples to store (max of 32000)
228          * example given:
229          *      ./ARM_User_Space_App.out chan3_2048samples.csv 3 2048
230          */ 
231         if(argc == 4) {
232                 csv_sample_num = atoi(argv[3]);
233                 if (csv_sample_num > MAX_CSV_SAMPLES)
234                         csv_sample_num = MAX_CSV_SAMPLES;
235                 csv_channel = atoi(argv[2]);
236                 if (csv_channel > NUM_CHANNELS)
237                         csv_channel = 0;
238         }
239         
241         /* Lock memory */
242         if(mlockall(MCL_CURRENT|MCL_FUTURE) == -1) {
243                 printf("mlockall failed: %m\n");
244                 exit(-2);
245         }
246         /* Initialize pthread attributes (default values) */
247         ret = pthread_attr_init(&attr);
248         if (ret) {
249                 printf("init pthread attributes failed\n");
250                 goto out;
251         }
252         /* Set the stack size, need at least 0x1E000 for the samples array */
253         ret = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + 0x20000);
254         if (ret) {
255             printf("pthread setstacksize failed\n");
256             goto out;
257         }
258         /* Set scheduler policy and priority of pthread */
259         ret = pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
260         if (ret) {
261                 printf("pthread setschedpolicy failed\n");
262                 goto out;
263         }
264         param.sched_priority = 99;
265         ret = pthread_attr_setschedparam(&attr, &param);
266         if (ret) {
267                 printf("pthread setschedparam failed\n");
268                 goto out;
269         }
270         /* Use scheduling parameters of attr */
271         ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
272         if (ret) {
273                 printf("pthread setinheritsched failed\n");
274                 goto out;
275         }
276         /* Create a pthread with specified attributes (priority 99) */
277         ret = pthread_create(&capture_thread, &attr, capture_func, NULL);
278         if (ret) {
279                 printf("create capture_thread failed\n");
280                 goto out;
281         }
282         /* Create a pthread with lower priority to print the results */
283         ret = pthread_create(&print_thread, NULL, print_func, NULL);
284         if (ret) {
285                 printf("create capture_thread failed\n");
286                 goto out;
287         }
288         /* Join the print thread and wait until it is done (key press) */
289         ret = pthread_join(print_thread, NULL);
290         if (ret)
291                 printf("join capture_thread failed: %m\n");
293         /* Write the samples to a csv file if requested */
294         if(argc == 4) {
295                 fp = fopen(argv[1], "w+");
296                 for (i = 0; i < csv_sample_num; i++) {
297                         fprintf(fp, "%d\n", csv_samples[i]);
298                 }
299                 fclose(fp);
301                 printf("\n%s file created with %d sample(s) from channel %d\n\n", argv[1], csv_sample_num, csv_channel);
302         }
303         
304 out:
305         return ret;