├── LICENSE ├── README.md ├── alsaPi ├── alsaPi.c ├── alsaPi.h ├── listControls.c ├── listMixers.c ├── setVolControl.c └── setVolMixer.c ├── binaries └── piRotEnc.tcz ├── chipsPi ├── C200 │ └── README.md ├── bcm2835 │ ├── spi │ │ ├── bcm2835spi.c │ │ └── bcm2835spi.h │ └── testDT.c ├── mcp23017 │ ├── README.md │ ├── mcp23017.c │ ├── mcp23017.h │ └── testmcp23017.c └── mcp42x1 │ ├── README.md │ ├── mcp42x1.c │ ├── mcp42x1.h │ └── testmcp42x1.c ├── deprecated ├── piLCD.c └── rotencvol.c ├── displayPi ├── hd44780gpio │ ├── README.md │ ├── hd44780gpio.c │ ├── hd44780gpio.h │ └── testhd44780gpio.c ├── hd44780i2c │ ├── README.md │ ├── hd44780i2c.c │ ├── hd44780i2c.h │ ├── mcp23017.c │ ├── mcp23017.h │ ├── testhd44780i2c.c │ └── testmcp23017.c └── ssd1322-spi │ ├── README.md │ ├── fb │ ├── README.md │ ├── fb-query.c │ └── fb-test2.c │ ├── fbtft │ ├── fb_ssd1322.c │ └── ssd1322-spi-overlay.dts │ ├── old │ ├── graphics.h │ ├── ssd1322-fb.c │ ├── ssd1322-spi.c │ ├── ssd1322-spi.h │ └── test-ssd1322-spi.c │ ├── ssd1322-commands.info │ └── tools │ ├── fontconvert.c │ └── unpacked.txt ├── gpioPi └── testSysPi.c ├── infoPi └── piInfo.c ├── meterPi ├── README.md ├── hd44780i2c.c ├── hd44780i2c.h ├── mcp23017.c ├── mcp23017.h ├── meterPi.c ├── meterPi.h ├── testmeterPi-lcd.c └── testmeterPi-ncurses.c ├── piRotEnc ├── alsaPi.c ├── alsaPi.h ├── piRotEnc.c ├── rotencPi.c └── rotencPi.h ├── popcornPi ├── amg19264Pi.c └── popcornPi.c ├── rotencPi ├── rotencPi.c ├── rotencPi.h └── testrotencPi.c └── streamPi └── thx1138.c /README.md: -------------------------------------------------------------------------------- 1 | ## raspberryPi 2 | 3 | RaspberryPi projects, libraries and utilities. Read the various header files for detailed descriptions. 4 | 5 | ###rotencPi: 6 | 7 | A rotary encoder library providing five different methods of decoding using interrupts. At some point, support for decoder chips may be included with some circuit diagrams. At the moment the decoding routines are interrupt driven but set a global variable that still needs to be polled. It is anticipated that the code will change to avoid this at some point. 8 | 9 | ###displayPi: 10 | 11 | Libraries providing support for various displays. 12 | 13 | * hd44780gpio provides support for HD44780 displays in 4-bit mode via GPIOs. 14 | * hd44780i2c provides the same support but using the I2C bus via a port expander and 8-bit mode. The MCP23017 expander library used includes bitwise set, clear and toggle modes as well as read/write byte and word modes. 15 | 16 | These libraries can initialise the display into different modes and enable up to 8 custom characters for animation, move to any position and display text. They also have a tickertape mode that can display text many times larger than the screen size by rotating the text left or right. Some animation examples using custom characters and threading are included. The libraries include a function to display formattable date and time information with simple animation such as blinking colons between numbers is also provided. 17 | 18 | * amg19264i2c will provide support for the display, and backlight control in the Popcorn C200. 19 | 20 | ###meterPi 21 | 22 | A library to provide metering capability for audio streams, displayed on small LCD or OLED displays, or a console via ncurses. The intent is to be IEC compliant but small displays will need some compromise. A demonstration of a PPM using a dBFS scale has been coded but requires Squeezelite running with the -v switch. This will remain a requirement until I can figure out how to use the memory mapping functions in ALSA or JACK audio. 23 | 24 | ###alsaPi: 25 | 26 | A library to provide some routines to set and change volume. Intended for use with rotencPi. Volume adjustment can be profiled to compensate for, or accentuate the logarithmic response of ALSA. This will allow better control according to the type of use, e.g. headphones need better refinement at low volumes but DACs or line level devices may need better refinement at higher levels. 27 | 28 | A number of utility programs are also inlcuded for setting ALSA volume by using either high level controls or ALSA mixer elements. 29 | 30 | ###infoPi: 31 | 32 | A utility program for providing information on the Raspberry Pi, such as ALSA controls and mixers, GPIO pin layout and board revisions. Uses command line switches to provide specific information. 33 | 34 | * -p Prints out a full pin layout with labels and GPIO numbers. 35 | * -m Lists ALSA mixers for all available cards. 36 | * -c Lists ALSA controls for all available cards. 37 | * -g [pin] Returns corresponding GPIO for header pin number. 38 | * -h [gpio] Returns corresponding header pin number for GPIO. 39 | 40 | ###piRotEnc: 41 | 42 | A program to provide a package of rotary encoder controls for the Raspberry Pi. This incorporates the rotencPi, alsaPi and lcdPi libraries. It is intended that a button be used to select a control mode for a single rotary encoder, i.e. adjust volume, balance, mute, folder navigation and file selection. Tiny Core Linux packages will be uploaded to 'binaries' occasionally. This is still under development as work on the LCD, ALSA and rotary encoder libraries progress. 43 | 44 | Command line parameters allow specifying: 45 | 46 | * The sound card and control element to adjust. 47 | * Soft volume limits. 48 | * Initial settings. 49 | * Volume refinements. 50 | * The shape of the volume response, i.e. logarithmic -> linear -> exponential. 51 | * The GPIO pins to be used. 52 | * Responsiveness. 53 | * Useful informational output. 54 | 55 | The LCD routines and rotary encoder routines are interrupt driven to keep CPU usage low. 56 | 57 | ###binaries: 58 | 59 | Tiny Core Linux packages and binaries for some of the programs and libraries. Packages can be made on request for anyone that is interested. A guide on how to install TCL packages is provided at the end of this file. 60 | 61 | ###deprecated: 62 | 63 | Some older packages that have been deprecated or subsumed into other libraries. 64 | 65 | ##To Do 66 | 67 | ###popcornPi: 68 | 69 | This is intended, once I have learned more about the hardware functions, to repurpose a Popcorn C200 case using a Raspberry Pi as a media server instead of the rather naff motherboard that it came with. 70 | 71 | ###streamPi: 72 | 73 | This will eventually provide a library of functions to manipulate media streams and provide information and control elements. 74 | 75 | ###gpioPi: 76 | 77 | This is intended to provide a library of functions to access and control GPIOs in a similar manner to wiringPi. It is not an attempt to replace wiringPi, which is a well supported library. It is an attempt to shortcut some of the more basic functions to provide more direct but fully interrupt driven libraries. 78 | 79 | --- 80 | #### Instructions for installing the package manually in Tiny Core Linux and it's derivatives. 81 | 82 | Download the tcz package with the following command: 83 | 84 | wget https://github.com/alidaf/raspberryP....tcz 85 | 86 | and type the following command in a terminal: 87 | 88 | cp .tcz /mnt/mmcblk0p2/tce/optional/ 89 | 90 | This copies the package to the optional packages area. 91 | 92 | Now edit /mnt/mmcblk0p2/tce/onboot.lst and add .tcz to the bottom to make it persistent after 93 | a reboot. 94 | 95 | I use nano so the command would be: 96 | 97 | sudo nano /mnt/mmcblk0p2/tce/onboot.lst 98 | 99 | Add the line, then press ctrl-x, press y and then return to save the file. 100 | 101 | Now load the package: 102 | 103 | tce-load -i /mnt/mmcblk0p2/tce/optional/.tcz 104 | 105 | To run, until I can sort out a startup script run: 106 | 107 | sudo /bin/ 108 | 109 | For piRotEnc, -? will print out a list of all of the command line parameters. 110 | 111 | Pay special attention to the card name and control name switches. You will need to run piInfo or alsamixer (part of the main ALSA package) to get these. If you are just running the Pi with no other hardware then the default names should be fine. If you are using anything else, such as a DAC, then you can determine these using piInfo or alsamixer. 112 | 113 | Also check which GPIO pins you are using and set these with the -A switch if they are not the defaults, 114 | which are 23 and 24. 115 | 116 | Try running with output on by using the -P switch and messing around with some of the other parameters such 117 | as -f . Some switches that produce informational output will terminate the program. The switch -f num 118 | shapes the volume profile to overcome the logarithmic output of alsa. Try a value of around 0.1 - 0.05 to get a 119 | more linear response. The default value of one will increment volume up from 0 very slowly at first and then in 120 | increasingly large steps. Values > 1 will exacerbate this but values < 1 will make the volume increase more 121 | quickly at the bottom end. Soft limits can also be set if you have a noisy card and want to ignore some of the 122 | lower volumes where there is hiss or deafeningly loud high volumes. The starting volume can also be set. The default starting volume is 0 since I use headphones but a starting 123 | volume of 100 (%) may be better for DACs, but the choice is there. 124 | 125 | ctrl-c will stop the program if it is running interactively. 126 | 127 | Once you are happy run the command with the '&' character at the end of the line. This will force it to the 128 | background and free up your prompt. E.g. 129 | 130 | sudo /bin/piRotEnc -i 20 -P -A 2,3 & 131 | 132 | Press return to get your prompt back. 133 | 134 | You should see the process running with the following command: 135 | 136 | ps aux | grep 137 | 138 | You will get a list of command that are running that contain the word ‘’. One of them should be the 139 | command you just typed with the process id at the start of the line. To stop the program running you have to kill 140 | it with the command: 141 | 142 | sudo kill 143 | -------------------------------------------------------------------------------- /alsaPi/alsaPi.c: -------------------------------------------------------------------------------- 1 | // **************************************************************************** 2 | /* 3 | alsaPi: 4 | 5 | ALSA based sound driver for the Raspberry Pi. 6 | 7 | Copyright 2015 Darren Faulke 8 | ALSA routines based on amixer, 2000 Jaroslev Kysela. 9 | - see http://www.alsa-project.org. 10 | 11 | This program is free software; you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 2 of the License, or 14 | (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with this program. If not, see . 23 | */ 24 | // **************************************************************************** 25 | 26 | // Compilation: 27 | // 28 | // Compile with gcc -c -fpic alsaPi.c -lasound -lm 29 | // Also use the following flags for Raspberry Pi optimisation: 30 | // -march=armv6 -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp 31 | // -ffast-math -pipe -O3 32 | 33 | #define alsaPiVersion "Version 0.1" 34 | 35 | // Authors: D.Faulke 10/12/2015 36 | // 37 | // Contributors: 38 | // 39 | // Changelog: 40 | // 41 | // v0.1 Original version. 42 | // 43 | 44 | // To Do: 45 | // Add proper muting rather than set volume to 0, and set mute when 0. 46 | // - look at playback switch mechanism. 47 | // Add balance control. 48 | // Add soft limits. 49 | // 50 | 51 | // Installed libraries ------------------------------------------------------- 52 | 53 | #include 54 | #include 55 | #include 56 | 57 | // Local libraries ----------------------------------------------------------- 58 | 59 | #include "alsaPi.h" 60 | 61 | 62 | // Local variables. ---------------------------------------------------------- 63 | 64 | static bool header = false; // Flag to print header on 1st set volume. 65 | 66 | 67 | // Functions. ---------------------------------------------------------------- 68 | 69 | // ---------------------------------------------------------------------------- 70 | // Initialises hardware and returns info in sound struct. 71 | // ---------------------------------------------------------------------------- 72 | int soundOpen( void ) 73 | { 74 | int err; 75 | 76 | // Set up ALSA mixer. 77 | err = snd_mixer_open( &mixerHandle, 0 ); 78 | if ( err < 0 ) 79 | { 80 | printf( "%s.\n", snd_strerror( err )); 81 | return err; 82 | } 83 | err = snd_mixer_attach( mixerHandle, sound.card ); 84 | if ( err < 0 ) 85 | { 86 | printf( "%s.\n", snd_strerror( err )); 87 | return err; 88 | } 89 | err = snd_mixer_load( mixerHandle ); 90 | if ( err < 0 ) 91 | { 92 | printf( "%s.\n", snd_strerror( err )); 93 | return err; 94 | } 95 | err = snd_mixer_selem_register( mixerHandle, NULL, NULL ); 96 | if ( err < 0 ) 97 | { 98 | printf( "%s.\n", snd_strerror( err )); 99 | return err; 100 | } 101 | 102 | snd_mixer_selem_id_alloca( &mixerId ); 103 | snd_mixer_selem_id_set_name( mixerId, sound.mixer ); 104 | 105 | mixerElem = snd_mixer_find_selem( mixerHandle, mixerId ); 106 | if ( mixerElem == NULL ) 107 | { 108 | printf( "Couldn't find mixer" ); 109 | return -1; 110 | } 111 | snd_mixer_selem_get_id( mixerElem, mixerId ); 112 | 113 | // Get hardware volume limits. 114 | long minHard, maxHard; 115 | err = snd_mixer_selem_get_playback_volume_range( mixerElem, 116 | &minHard, &maxHard ); 117 | if ( err < 0 ) 118 | { 119 | printf( "%s.\n", snd_strerror( err )); 120 | return err; 121 | } 122 | 123 | // Calculate soft limits. 124 | long minSoft, maxSoft; 125 | minSoft = sound.min / 100 * ( maxHard - minHard ) + minHard; 126 | maxSoft = sound.max / 100 * ( maxHard - minHard ) + minHard; 127 | 128 | // Set soft limits. 129 | sound.min = minSoft; 130 | sound.max = maxSoft; 131 | sound.range = sound.max - sound.min; 132 | 133 | // Set starting index and volume. 134 | sound.index = lroundf( (float)sound.volume / 100 * sound.incs ); 135 | 136 | return 0; 137 | } 138 | 139 | // ---------------------------------------------------------------------------- 140 | // Calculates volume based on index. Returns value in sound struct. 141 | // ---------------------------------------------------------------------------- 142 | long calcVol( float index, float incs, float range, float min, float factor ) 143 | { 144 | long volume; 145 | 146 | if ( factor == 1 ) // Divide by 0 if used in function. 147 | volume = lroundf(( index / incs * range ) + min ); 148 | else volume = lroundf((( pow( factor, index / incs ) - 1 ) / 149 | ( factor - 1 ) * range + min )); 150 | return volume; 151 | }; 152 | 153 | // ---------------------------------------------------------------------------- 154 | // Set volume using ALSA mixers. 155 | // ---------------------------------------------------------------------------- 156 | int setVol( void ) 157 | { 158 | long linearVol; // Linear volume. Used for debugging. 159 | int err; 160 | 161 | // Calculate volume value from index. 162 | sound.volume = calcVol( sound.index, sound.incs, sound.range, 163 | sound.min, sound.factor ); 164 | 165 | // If control is mono then FRONT_LEFT will set volume. 166 | err=snd_mixer_selem_set_playback_volume( mixerElem, 167 | SND_MIXER_SCHN_FRONT_LEFT, sound.volume ); 168 | if ( err < 0 ) return err; 169 | err=snd_mixer_selem_set_playback_volume( mixerElem, 170 | SND_MIXER_SCHN_FRONT_RIGHT, sound.volume ); 171 | if ( err < 0 ) return err; 172 | 173 | if ( sound.print ) // Print output if requested. For debugging. 174 | { 175 | linearVol = calcVol( sound.index, sound.incs, sound.range, 176 | sound.min, 1 ); 177 | 178 | if ( header == false ) // Print out header block. 179 | { 180 | printf( "\n" ); 181 | printf( "\t+-----------+-----------------+-----------------+\n" ); 182 | printf( "\t| indices | Linear Volume | Mapped Volume |\n" ); 183 | printf( "\t+-----+-----+--------+--------+--------+--------+\n" ); 184 | printf( "\t| L | R | L | R | L | R |\n" ); 185 | printf( "\t+-----+-----+--------+--------+--------+--------+\n" ); 186 | 187 | header = true; 188 | } 189 | if ( err < 0 ) 190 | printf( "\t| %-45s |\n", snd_strerror( err )); 191 | else 192 | printf( "\t| %3i | %3i | %6ld | %6ld | %6d | %6d |\n", 193 | sound.index, sound.index, 194 | linearVol, linearVol, 195 | sound.volume, sound.volume ); 196 | } 197 | 198 | return 0; 199 | }; 200 | 201 | // ---------------------------------------------------------------------------- 202 | // Increases volume. 203 | // ---------------------------------------------------------------------------- 204 | void incVol( void ) 205 | { 206 | // Ensure not at limit. 207 | if ( sound.index >= sound.incs ) sound.index = sound.incs; 208 | // Increment index. 209 | else sound.index++; 210 | 211 | // Set volume. 212 | setVol(); 213 | 214 | return; 215 | }; 216 | 217 | // ---------------------------------------------------------------------------- 218 | // Increases volume. 219 | // ---------------------------------------------------------------------------- 220 | void decVol( void ) 221 | { 222 | // Ensure not at limit. 223 | if ( sound.index <= 0 ) sound.index = 0; 224 | // Deccrement index. 225 | else sound.index--; 226 | 227 | // Set volume. 228 | setVol(); 229 | 230 | return; 231 | }; 232 | 233 | // ---------------------------------------------------------------------------- 234 | // Detaches and closes ALSA. 235 | // ---------------------------------------------------------------------------- 236 | void soundClose( void ) 237 | { 238 | snd_mixer_detach( mixerHandle, sound.card ); 239 | snd_mixer_close( mixerHandle ); 240 | 241 | return; 242 | }; 243 | 244 | -------------------------------------------------------------------------------- /alsaPi/alsaPi.h: -------------------------------------------------------------------------------- 1 | // **************************************************************************** 2 | /* 3 | alsaPi: 4 | 5 | ALSA based sound driver for the Raspberry Pi. 6 | 7 | Copyright 2015 Darren Faulke 8 | ALSA routines based on amixer, 2000 Jaroslev Kysela. 9 | - see http://www.alsa-project.org. 10 | 11 | This program is free software; you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 2 of the License, or 14 | (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with this program. If not, see . 23 | */ 24 | // **************************************************************************** 25 | 26 | // Authors: D.Faulke 10/12/2015 27 | // 28 | // Contributors: 29 | // 30 | // Changelog: 31 | // 32 | // v0.1 Original version. 33 | // 34 | 35 | // To Do: 36 | // Add proper muting rather than set volume to 0, and set mute when 0. 37 | // - look at playback switch mechanism. 38 | // Add balance control. 39 | // Add soft limits. 40 | // 41 | 42 | #ifndef ALSAPI_H 43 | #define ALSAPI_H 44 | 45 | //#include 46 | //#include 47 | //#include 48 | //#include 49 | //#include 50 | //#include 51 | //#include 52 | //#include 53 | 54 | 55 | // Data structures. ---------------------------------------------------------- 56 | 57 | struct soundStruct 58 | { 59 | char *card; // ALSA card ID. 60 | char *mixer; // ALSA mixer ID. 61 | float factor; // Volume mapping factor. 62 | unsigned char index; // Relative index for volume level. 63 | unsigned char incs; // Number of increments over volume range. 64 | int min; // Minimum volume (hardware dependent). 65 | int max; // Maximum volume (hardware dependent). 66 | int range; // Volume range (hardware dependent). 67 | int volume; // Volume level. 68 | char balance; // Relative balance -100(%) to +100(%). 69 | bool mute; // Mute switch. 70 | bool print; // Print output switch. 71 | } sound; 72 | 73 | 74 | // ALSA control types. ------------------------------------------------------- 75 | 76 | snd_ctl_t *ctlHandle; // Simple control handle. 77 | snd_ctl_elem_id_t *ctlId; // Simple control element id. 78 | snd_ctl_elem_value_t *ctlControl; // Simple control element value. 79 | snd_ctl_elem_type_t ctlType; // Simple control element type. 80 | snd_ctl_elem_info_t *ctlInfo; // Simple control element info container. 81 | snd_ctl_card_info_t *ctlCard; // Simple control card info container. 82 | 83 | 84 | // ALSA mixer types. ---------------------------------------------------------- 85 | 86 | snd_mixer_t *mixerHandle; // Mixer handle. 87 | snd_mixer_selem_id_t *mixerId; // Mixer simple element identifier. 88 | snd_mixer_elem_t *mixerElem; // Mixer element handle. 89 | 90 | 91 | // Functions. ---------------------------------------------------------------- 92 | 93 | // ---------------------------------------------------------------------------- 94 | // Initialises hardware and returns info in sound struct. 95 | // ---------------------------------------------------------------------------- 96 | int soundOpen( void ); 97 | 98 | // ---------------------------------------------------------------------------- 99 | // Calculates volume based on index. Returns value in soundStruct. 100 | // ---------------------------------------------------------------------------- 101 | /* 102 | linear volume = ratio * range + min. 103 | mapped volume = ( factor^ratio - 1 ) / ( factor - 1 ) * range + min. 104 | ratio = index / incs. 105 | 106 | factor < 1, logarithmic. 107 | factor = 1, linear. 108 | factor > 1, exponential. 109 | */ 110 | long calcVol( float index, float incs, float range, float min, float factor ); 111 | 112 | // ---------------------------------------------------------------------------- 113 | // Set volume using ALSA mixers. 114 | // ---------------------------------------------------------------------------- 115 | int setVol( void ); 116 | 117 | // ---------------------------------------------------------------------------- 118 | // Increases volume. 119 | // ---------------------------------------------------------------------------- 120 | void incVol( void ); 121 | 122 | // ---------------------------------------------------------------------------- 123 | // Increases volume. 124 | // ---------------------------------------------------------------------------- 125 | void decVol( void ); 126 | 127 | // ---------------------------------------------------------------------------- 128 | // Detaches and closes ALSA. 129 | // ---------------------------------------------------------------------------- 130 | void soundClose( void ); 131 | 132 | #endif 133 | -------------------------------------------------------------------------------- /alsaPi/listControls.c: -------------------------------------------------------------------------------- 1 | // **************************************************************************** 2 | // **************************************************************************** 3 | /* 4 | listControls: 5 | 6 | Lists ALSA control elements for all available cards. 7 | 8 | Copyright 2015 by Darren Faulke 9 | 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program. If not, see . 22 | */ 23 | // **************************************************************************** 24 | // **************************************************************************** 25 | 26 | #define Version "Version 0.1" 27 | 28 | // Compilation: 29 | // 30 | // Compile with gcc listControls.c -Wall -o listControls -lasound 31 | // Also use the following flags for Raspberry Pi optimisation: 32 | // -march=armv6 -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp 33 | // -ffast-math -pipe -O3 34 | 35 | // Authors: D.Faulke 19/10/15 36 | // Contributors: 37 | // 38 | // Changelog: 39 | // 40 | // Initial version. 41 | // 42 | 43 | #include 44 | #include 45 | #include 46 | 47 | // ============================================================================ 48 | // Main routine. 49 | // ============================================================================ 50 | 51 | int main() 52 | { 53 | int cardNumber = -1; 54 | int errNum; 55 | char *controlType; 56 | char deviceID[16]; 57 | 58 | // ------------------------------------------------------------------------ 59 | // ALSA control elements. 60 | // ------------------------------------------------------------------------ 61 | snd_ctl_t *ctl; // Simple control handle. 62 | snd_ctl_elem_id_t *id; // Simple control element id. 63 | snd_ctl_elem_value_t *control; // Simple control element value. 64 | snd_ctl_elem_type_t type; // Simple control element type. 65 | snd_ctl_elem_info_t *info; // Simple control element info container. 66 | snd_ctl_card_info_t *card; // Simple control card info container. 67 | 68 | snd_hctl_t *hctl; // High level control handle; 69 | snd_hctl_elem_t *elem; // High level control element handle. 70 | 71 | // ------------------------------------------------------------------------ 72 | // Initialise ALSA card and device types. 73 | // ------------------------------------------------------------------------ 74 | snd_ctl_card_info_alloca( &card ); 75 | snd_ctl_elem_value_alloca( &control ); 76 | snd_ctl_elem_id_alloca( &id ); 77 | snd_ctl_elem_info_alloca( &info ); 78 | 79 | // ------------------------------------------------------------------------ 80 | // Start card section. 81 | // ------------------------------------------------------------------------ 82 | // For each card. 83 | while (1) 84 | { 85 | // Find next card number. If < 0 then returns 1st card. 86 | errNum = snd_card_next( &cardNumber ); 87 | if (( errNum < 0 ) || ( cardNumber < 0 )) break; 88 | 89 | // Concatenate strings to get card's control interface. 90 | sprintf( deviceID, "hw:%i", cardNumber ); 91 | 92 | // Try to open card. 93 | if ( snd_ctl_open( &ctl, deviceID, 0 ) < 0 ) 94 | { 95 | printf( "Error opening card.\n" ); 96 | continue; 97 | } 98 | 99 | // Fill control card info element. 100 | if ( snd_ctl_card_info( ctl, card ) < 0 ) 101 | { 102 | printf( "Error getting card info.\n" ); 103 | continue; 104 | } 105 | 106 | // -------------------------------------------------------------------- 107 | // Print header block. 108 | // -------------------------------------------------------------------- 109 | printf( "\t+-----------------------------" ); 110 | printf( "-----------------------------+\n" ); 111 | printf( "\t| Card: %d - %-46s |", 112 | cardNumber, 113 | snd_ctl_card_info_get_name( card )); 114 | printf( "\n" ); 115 | printf( "\t+--------+------------" ); 116 | printf( "+------------------------------------+\n" ); 117 | printf( "\t| Device | Type " ); 118 | printf( "| Name |\n" ); 119 | printf( "\t+--------+------------" ); 120 | printf( "+------------------------------------+\n" ); 121 | 122 | // -------------------------------------------------------------------- 123 | // Start control section. 124 | // -------------------------------------------------------------------- 125 | // Open an empty high level control. 126 | if ( snd_hctl_open( &hctl, deviceID, 0 ) < 0 ) 127 | printf( "Error opening high level control.\n" ); 128 | 129 | // Load high level control element. 130 | if ( snd_hctl_load( hctl ) < 0 ) 131 | printf( "Error loading high level control.\n" ); 132 | 133 | // -------------------------------------------------------------------- 134 | // For each control element. 135 | // -------------------------------------------------------------------- 136 | for ( elem = snd_hctl_first_elem( hctl ); 137 | elem; 138 | elem = snd_hctl_elem_next( elem )) 139 | { 140 | // Get ID of high level control element. 141 | snd_hctl_elem_get_id( elem, id ); 142 | 143 | // ---------------------------------------------------------------- 144 | // Determine control type. 145 | // ---------------------------------------------------------------- 146 | if ( snd_hctl_elem_info( elem, info ) < 0 ) 147 | printf( "Can't get control information.\n" ); 148 | 149 | type = snd_ctl_elem_info_get_type( info ); 150 | 151 | switch ( type ) 152 | { 153 | case SND_CTL_ELEM_TYPE_NONE: 154 | controlType = "None"; 155 | break; 156 | case SND_CTL_ELEM_TYPE_BOOLEAN: 157 | controlType = "Boolean"; 158 | break; 159 | case SND_CTL_ELEM_TYPE_INTEGER: 160 | controlType = "Integer"; 161 | break; 162 | case SND_CTL_ELEM_TYPE_INTEGER64: 163 | controlType = "Integer64"; 164 | break; 165 | case SND_CTL_ELEM_TYPE_ENUMERATED: 166 | controlType = "Enumerated"; 167 | break; 168 | case SND_CTL_ELEM_TYPE_BYTES: 169 | controlType = "Bytes"; 170 | break; 171 | case SND_CTL_ELEM_TYPE_IEC958: 172 | controlType = "IEC958"; 173 | break; 174 | default: 175 | controlType = "Not Found"; 176 | break; 177 | } 178 | printf( "\t| %-6i | %-10s | %-34s |\n", 179 | snd_hctl_elem_get_numid( elem ), 180 | controlType, 181 | snd_hctl_elem_get_name( elem )); 182 | } 183 | printf( "\t+--------+------------" ); 184 | printf( "+------------------------------------+\n\n" ); 185 | 186 | // -------------------------------------------------------------------- 187 | // Tidy up. 188 | // -------------------------------------------------------------------- 189 | snd_hctl_close( hctl ); 190 | snd_ctl_close( ctl ); 191 | } 192 | 193 | return 0; 194 | } 195 | -------------------------------------------------------------------------------- /alsaPi/listMixers.c: -------------------------------------------------------------------------------- 1 | // **************************************************************************** 2 | // **************************************************************************** 3 | /* 4 | listMixers: 5 | 6 | Simple test program to list all ALSA cards and mixers. 7 | 8 | Copyright 2015 by Darren Faulke 9 | 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program. If not, see . 22 | */ 23 | // **************************************************************************** 24 | // **************************************************************************** 25 | 26 | #define Version "Version 0.4" 27 | 28 | // Compilation: 29 | // 30 | // Compile with gcc listMixers.c -Wall -o listMixers -lasound 31 | // Also use the following flags for Raspberry Pi optimisation: 32 | // -march=armv6 -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp 33 | // -ffast-math -pipe -O3 34 | 35 | // Authors: D.Faulke 19/10/15 36 | // Contributors: 37 | // 38 | // Changelog: 39 | // 40 | // v0.1 Initial version. 41 | // v0.2 Modified output and added control type. 42 | // v0.3 Rewrite from scratch. 43 | // v0.4 Added number of channels to output. 44 | // 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | // ============================================================================ 52 | // Main routine. 53 | // ============================================================================ 54 | int main() 55 | { 56 | int cardNumber = -1; 57 | char deviceID[8]; 58 | char channelStr[3]; 59 | unsigned int channels; 60 | long volMin, volMax; 61 | int errNum; 62 | 63 | // ------------------------------------------------------------------------ 64 | // ALSA mixer elements. 65 | // ------------------------------------------------------------------------ 66 | snd_mixer_t *handle; // Mixer handle. 67 | snd_mixer_selem_id_t *sid; // Mixer simple element identifier. 68 | snd_mixer_elem_t *elem; // Mixer element handle. 69 | 70 | // We are cycling through the mixers without knowing the CTL names so 71 | // we need some control elements. 72 | // Using CTL or HCTL elements should be avoided for 'safe' ALSA! 73 | snd_ctl_t *ctl; // Simple control handle. 74 | 75 | // ALSA info elements for retrieving certain information. Should also 76 | // be avoided for 'safe' ALSA. 77 | snd_ctl_card_info_t *card; // Control card info container. 78 | 79 | printf( "\nKey:" ); 80 | printf( "\tVol = Volume Control.\n" ); 81 | printf( "\t0/1 = Playback switch.\n" ); 82 | printf( "\tChn = Number of channels.\n\n" ); 83 | 84 | while (1) 85 | { 86 | // Find next card. Exit loop if none. 87 | errNum = snd_card_next( &cardNumber ); 88 | if (( errNum < 0 ) || ( cardNumber < 0 )) break; 89 | 90 | sprintf( deviceID, "hw:%i", cardNumber ); 91 | 92 | // Open card. 93 | errNum = snd_ctl_open( &ctl, deviceID, 0 ); 94 | if (errNum < 0 ) continue; 95 | 96 | // Allocate memory for card info. 97 | snd_ctl_card_info_alloca( &card ); 98 | errNum = snd_ctl_card_info( ctl, card ); 99 | if (errNum < 0 ) continue; 100 | 101 | // -------------------------------------------------------------------- 102 | // Print header block and some card specific info. 103 | // -------------------------------------------------------------------- 104 | printf( "Card: %s.\n", snd_ctl_card_info_get_name( card )); 105 | printf( "\t+------------------------------------------" ); 106 | printf( "+---+---+---+-------+-------+\n" ); 107 | printf( "\t| Control ID%-30s ", "" ); 108 | printf( "|Vol|0/1|Chn| Min | Max |\n" ); 109 | printf( "\t+------------------------------------------" ); 110 | printf( "+---+---+---+-------+-------+\n" ); 111 | 112 | // -------------------------------------------------------------------- 113 | // Set up control and mixer. 114 | // -------------------------------------------------------------------- 115 | // Open an empty mixer and attach a control. 116 | if ( snd_mixer_open( &handle, 0 ) < 0 ) 117 | { 118 | printf( "Error opening mixer.\n" ); 119 | return -1; 120 | } 121 | if ( snd_mixer_attach( handle, deviceID ) < 0 ) 122 | { 123 | printf( "Error attaching control to mixer.\n" ); 124 | return -2; 125 | } 126 | // Register the mixer simple element class and load mixer. 127 | if ( snd_mixer_selem_register( handle, NULL, NULL ) < 0 ) 128 | { 129 | printf( "Error registering element class.\n" ); 130 | return -3; 131 | } 132 | if ( snd_mixer_load( handle ) < 0 ) 133 | { 134 | printf( "Error loading mixer.\n" ); 135 | return -4; 136 | } 137 | snd_mixer_selem_id_alloca( &sid ); 138 | 139 | // -------------------------------------------------------------------- 140 | // For each mixer element. 141 | // -------------------------------------------------------------------- 142 | for ( elem = snd_mixer_first_elem( handle ); 143 | elem; 144 | elem = snd_mixer_elem_next( elem )) 145 | { 146 | // Get ID of mixer element. 147 | snd_mixer_selem_get_id( elem, sid ); 148 | 149 | // Get range of values for control. 150 | errNum = snd_mixer_selem_get_playback_volume_range( 151 | elem, &volMin, &volMax ); 152 | 153 | // Check whether element has volume control. 154 | char *hasVolume = "-"; 155 | char *hasSwitch = "-"; 156 | if ( snd_mixer_selem_has_playback_volume( elem )) 157 | hasVolume = "*"; 158 | if ( snd_mixer_selem_has_playback_switch( elem )) 159 | hasSwitch = "*"; 160 | 161 | // Check which channels the mixer has. 162 | channels = 0; 163 | if ( snd_mixer_selem_has_playback_channel( elem, 164 | SND_MIXER_SCHN_MONO ) && 165 | snd_mixer_selem_has_playback_channel( elem, 166 | SND_MIXER_SCHN_FRONT_LEFT ) && 167 | !snd_mixer_selem_has_playback_channel( elem, 168 | SND_MIXER_SCHN_FRONT_RIGHT )) 169 | sprintf( channelStr, " 1 " ); 170 | else 171 | { 172 | if ( snd_mixer_selem_has_playback_channel( elem, 173 | SND_MIXER_SCHN_FRONT_LEFT )) 174 | channels++; 175 | if ( snd_mixer_selem_has_playback_channel( elem, 176 | SND_MIXER_SCHN_FRONT_CENTER )) 177 | channels++; 178 | if ( snd_mixer_selem_has_playback_channel( elem, 179 | SND_MIXER_SCHN_FRONT_RIGHT )) 180 | channels++; 181 | if ( snd_mixer_selem_has_playback_channel( elem, 182 | SND_MIXER_SCHN_SIDE_LEFT )) 183 | channels++; 184 | if ( snd_mixer_selem_has_playback_channel( elem, 185 | SND_MIXER_SCHN_SIDE_RIGHT )) 186 | channels++; 187 | if ( snd_mixer_selem_has_playback_channel( elem, 188 | SND_MIXER_SCHN_REAR_LEFT )) 189 | channels++; 190 | if ( snd_mixer_selem_has_playback_channel( elem, 191 | SND_MIXER_SCHN_REAR_CENTER )) 192 | channels++; 193 | if ( snd_mixer_selem_has_playback_channel( elem, 194 | SND_MIXER_SCHN_REAR_RIGHT )) 195 | channels++; 196 | 197 | sprintf( channelStr, "%i.%i", 198 | channels, 199 | snd_mixer_selem_has_playback_channel( elem, 200 | SND_MIXER_SCHN_WOOFER )); 201 | } 202 | 203 | printf( "\t| %-40s | %s | %s |%s|%+7ld|%+7ld|\n", 204 | snd_mixer_selem_id_get_name( sid ), 205 | hasVolume, 206 | hasSwitch, 207 | channelStr, 208 | volMin, volMax ); 209 | } 210 | printf( "\t+------------------------------------------" ); 211 | printf( "+---+---+---+-------+-------+\n\n" ); 212 | } 213 | 214 | snd_mixer_close( handle ); 215 | 216 | return 0; 217 | } 218 | -------------------------------------------------------------------------------- /alsaPi/setVolControl.c: -------------------------------------------------------------------------------- 1 | // **************************************************************************** 2 | // **************************************************************************** 3 | /* 4 | setVolControl: 5 | 6 | Simple app to set volume using ALSA controls. 7 | 8 | Copyright 2015 by Darren Faulke 9 | 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program. If not, see . 22 | */ 23 | // **************************************************************************** 24 | // **************************************************************************** 25 | 26 | #define Version "Version 0.2" 27 | 28 | // Compilation: 29 | // 30 | // Compile with gcc setVolControl.c -Wall -o setVolControl -lasound 31 | // Also use the following flags for Raspberry Pi optimisation: 32 | // -march=armv6 -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp 33 | // -ffast-math -pipe -O3 34 | 35 | // Authors: D.Faulke 19/10/15 36 | // Contributors: 37 | // 38 | // Changelog: 39 | // 40 | // v0.1 Initial version. 41 | // v0.2 Added command line parameters. 42 | // 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | // ---------------------------------------------------------------------------- 50 | // argp documentation. 51 | // ---------------------------------------------------------------------------- 52 | const char *argp_program_version = Version; 53 | const char *argp_program_bug_address = "darren@alidaf.co.uk"; 54 | static char doc[] = "A short test program to set ALSA control values."; 55 | static char args_doc[] = "alsavol "; 56 | 57 | // ---------------------------------------------------------------------------- 58 | // Data definitions. 59 | // ---------------------------------------------------------------------------- 60 | 61 | // Data structure to hold command line arguments. 62 | struct structArgs 63 | { 64 | int card; 65 | int control; 66 | char deviceID[8]; 67 | int value1; 68 | int value2; 69 | }; 70 | 71 | // ---------------------------------------------------------------------------- 72 | // Command line argument definitions. 73 | // ---------------------------------------------------------------------------- 74 | static struct argp_option options[] = 75 | { 76 | { 0, 0, 0, 0, "Card information:" }, 77 | { "card", 'c', "", 0, "Card ID number." }, 78 | { "control", 'd', "", 0, "Control ID number." }, 79 | { 0, 0, 0, 0, "Control parameters:" }, 80 | { "val", 'v', "<%>/<%,%>", 0, "Set control value(s)." }, 81 | { 0 } 82 | }; 83 | 84 | // ---------------------------------------------------------------------------- 85 | // Command line argument parser. 86 | // ---------------------------------------------------------------------------- 87 | static int parse_opt( int param, char *arg, struct argp_state *state ) 88 | { 89 | char *str; 90 | char *token; 91 | const char delimiter[] = ","; 92 | struct structArgs *cmdArgs = state->input; 93 | 94 | switch( param ) 95 | { 96 | case 'c' : 97 | cmdArgs->card = atoi( arg ); 98 | break; 99 | case 'd' : 100 | cmdArgs->control = atoi( arg ); 101 | break; 102 | case 'v' : 103 | str = arg; 104 | token = strtok( str, delimiter ); 105 | cmdArgs->value1 = atoi( token ); 106 | token = strtok( NULL, delimiter ); 107 | if ( token == NULL ) 108 | cmdArgs->value2 = cmdArgs->value1; 109 | else 110 | cmdArgs->value2 = atoi( token ); 111 | break; 112 | } 113 | return 0; 114 | }; 115 | 116 | // ---------------------------------------------------------------------------- 117 | // argp parser parameter structure. 118 | // ---------------------------------------------------------------------------- 119 | static struct argp argp = { options, parse_opt, args_doc, doc }; 120 | 121 | // ============================================================================ 122 | // Main section. 123 | // ============================================================================ 124 | int main( int argc, char *argv[] ) 125 | { 126 | struct structArgs cmdArgs; 127 | 128 | // ------------------------------------------------------------------------ 129 | // ALSA control elements. 130 | // ------------------------------------------------------------------------ 131 | snd_ctl_t *ctl; // Simple control handle. 132 | snd_ctl_elem_id_t *id; // Simple control element id. 133 | snd_ctl_elem_value_t *control; // Simple control element value. 134 | snd_ctl_elem_type_t type; // Simple control element type. 135 | snd_ctl_elem_info_t *info; // Simple control info container. 136 | 137 | // ------------------------------------------------------------------------ 138 | // Get command line parameters. 139 | // ------------------------------------------------------------------------ 140 | argp_parse( &argp, argc, argv, 0, 0, &cmdArgs ); 141 | 142 | printf( "Card = %i\n", cmdArgs.card ); 143 | printf( "Control = %i\n", cmdArgs.control ); 144 | printf( "Value 1 = %i\n", cmdArgs.value1 ); 145 | printf( "Value 2 = %i\n", cmdArgs.value2 ); 146 | 147 | // ------------------------------------------------------------------------ 148 | // Set up ALSA control. 149 | // ------------------------------------------------------------------------ 150 | sprintf( cmdArgs.deviceID, "hw:%i", cmdArgs.card ); 151 | printf( "Device ID = %s.\n", cmdArgs.deviceID ); 152 | 153 | if ( snd_ctl_open( &ctl, cmdArgs.deviceID, 1 ) < 0 ) 154 | { 155 | printf( "Error opening control.\n" ); 156 | return -1; 157 | } 158 | // Initialise a simple control element id structure. 159 | snd_ctl_elem_id_alloca( &id ); 160 | snd_ctl_elem_id_set_numid( id, cmdArgs.control ); 161 | 162 | // Initialise info element. 163 | snd_ctl_elem_info_alloca( &info ); 164 | snd_ctl_elem_info_set_numid( info, cmdArgs.control ); 165 | 166 | // Is the control valid? 167 | if ( snd_ctl_elem_info( ctl, info ) < 0 ) 168 | { 169 | printf( "Error getting control element info.\n" ); 170 | return -2; 171 | } 172 | 173 | // Find type of control. 174 | // either: 175 | // SND_CTL_ELEM_TYPE_INTEGER, 176 | // SND_CTL_ELEM_TYPE_INTEGER64, 177 | // SND_CTL_ELEM_TYPE_ENUMERATED, etc. 178 | // Only interested in INTEGER. 179 | type = snd_ctl_elem_info_get_type( info ); 180 | if ( type != SND_CTL_ELEM_TYPE_INTEGER ) 181 | { 182 | printf( "Control type is not integer.\n" ); 183 | printf( "Type = %u\n", type ); 184 | return -3; 185 | } 186 | 187 | // ------------------------------------------------------------------------ 188 | // Get some information for selected control. 189 | // ------------------------------------------------------------------------ 190 | printf( "Min value for control = %ld\n", snd_ctl_elem_info_get_min( info )); 191 | printf( "Max value for control = %ld\n", snd_ctl_elem_info_get_max( info )); 192 | printf( "Step value for control = %ld\n", snd_ctl_elem_info_get_step( info )); 193 | 194 | // Initialise the control element value container. 195 | snd_ctl_elem_value_alloca( &control ); 196 | snd_ctl_elem_value_set_id( control, id ); 197 | 198 | // ------------------------------------------------------------------------ 199 | // Set values for selected control. 200 | // ------------------------------------------------------------------------ 201 | snd_ctl_elem_value_set_integer( control, 0, cmdArgs.value1 ); 202 | if ( snd_ctl_elem_write( ctl, control ) < 0 ) 203 | printf( "Error setting L volume" ); 204 | else 205 | printf( "Set L volume to %d.\n", cmdArgs.value1 ); 206 | snd_ctl_elem_value_set_integer( control, 1, cmdArgs.value2 ); 207 | if ( snd_ctl_elem_write( ctl, control ) < 0 ) 208 | printf( "Error setting R volume" ); 209 | else 210 | printf( "Set R volume to %d.\n", cmdArgs.value2 ); 211 | 212 | // ------------------------------------------------------------------------ 213 | // Clean up. 214 | // ------------------------------------------------------------------------ 215 | snd_ctl_close( ctl ); 216 | 217 | return 0; 218 | } 219 | -------------------------------------------------------------------------------- /alsaPi/setVolMixer.c: -------------------------------------------------------------------------------- 1 | // **************************************************************************** 2 | // **************************************************************************** 3 | /* 4 | setVolMixer: 5 | 6 | Simple app to set volume using ALSA mixer controls. 7 | 8 | Copyright 2015 by Darren Faulke 9 | 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program. If not, see . 22 | */ 23 | // **************************************************************************** 24 | // **************************************************************************** 25 | 26 | #define Version "Version 0.3" 27 | 28 | // Compilation: 29 | // 30 | // Compile with gcc setVolMixer.c -Wall -o setVolMixer -lasound -lm 31 | // Also use the following flags for Raspberry Pi optimisation: 32 | // -march=armv6 -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp 33 | // -ffast-math -pipe -O3 34 | 35 | // Authors: D.Faulke 19/10/15 36 | // Contributors: 37 | // 38 | // Changelog: 39 | // 40 | // v0.1 Initial version. 41 | // v0.2 Added command line parameters. 42 | // v0.3 Added volume shaping. 43 | // 44 | 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | // ---------------------------------------------------------------------------- 53 | // argp documentation. 54 | // ---------------------------------------------------------------------------- 55 | const char *argp_program_version = Version; 56 | const char *argp_program_bug_address = "darren@alidaf.co.uk"; 57 | static char doc[] = "A short test program to set ALSA mixer values."; 58 | static char args_doc[] = "alsavolmixer "; 59 | 60 | // ---------------------------------------------------------------------------- 61 | // Data definitions. 62 | // ---------------------------------------------------------------------------- 63 | // Data structure to hold command line arguments. 64 | struct volumeStruct 65 | { 66 | char *card; 67 | char *mixer; 68 | float factor; 69 | unsigned int left; 70 | unsigned int right; 71 | }; 72 | 73 | // ---------------------------------------------------------------------------- 74 | // Command line argument definitions. 75 | // ---------------------------------------------------------------------------- 76 | static struct argp_option options[] = 77 | { 78 | { 0, 0, 0, 0, "Card information:" }, 79 | { "card", 'c', "", 0, "Card name or hw:." }, 80 | { "mixer", 'm', "", 0, "Mixer name." }, 81 | { 0, 0, 0, 0, "Mixer parameters:" }, 82 | { "val", 'v', "<%>/<%,%>", 0, "Set mixer value(s)." }, 83 | { "fac", 'f', "", 0, "Volume shaping factor" }, 84 | { 0 } 85 | }; 86 | 87 | // ---------------------------------------------------------------------------- 88 | // Command line argument parser. 89 | // ---------------------------------------------------------------------------- 90 | static int parse_opt( int param, char *arg, struct argp_state *state ) 91 | { 92 | char *str; 93 | char *token; 94 | const char delimiter[] = ","; 95 | struct volumeStruct *volume = state->input; 96 | 97 | switch( param ) 98 | { 99 | case 'c' : 100 | volume->card = arg; 101 | break; 102 | case 'm' : 103 | volume->mixer = arg; 104 | break; 105 | case 'f' : 106 | volume->factor = atof( arg ); 107 | break; 108 | case 'v' : 109 | str = arg; 110 | token = strtok( str, delimiter ); 111 | volume->left = atoi( token ); 112 | token = strtok( NULL, delimiter ); 113 | if ( token == NULL ) 114 | volume->right = volume->left; 115 | else 116 | volume->right = atoi( token ); 117 | break; 118 | } 119 | return 0; 120 | }; 121 | 122 | // ---------------------------------------------------------------------------- 123 | // argp parser parameter structure. 124 | // ---------------------------------------------------------------------------- 125 | static struct argp argp = { options, parse_opt, args_doc, doc }; 126 | 127 | // ---------------------------------------------------------------------------- 128 | // Returns mapped volume based on shaping factor. 129 | // ---------------------------------------------------------------------------- 130 | /* 131 | mappedVolume = ( factor^fraction - 1 ) / ( base - 1 ) 132 | fraction = linear volume / volume range. 133 | 134 | factor << 1, logarithmic. 135 | factor == 1, linear. 136 | factor >> 1, exponential. 137 | */ 138 | static long getVolume( float volume, float factor, 139 | float minimum, float maximum ) 140 | { 141 | long mappedVolume; 142 | float range = maximum - minimum; 143 | 144 | if ( factor == 1 ) 145 | mappedVolume = lroundf(( volume / 100 * range ) + minimum ); 146 | else mappedVolume = lroundf((( pow( factor, volume / 100 ) - 1 ) / 147 | ( factor - 1 ) * range + minimum )); 148 | return mappedVolume; 149 | }; 150 | 151 | // ---------------------------------------------------------------------------- 152 | // Set volume using ALSA mixers. 153 | // ---------------------------------------------------------------------------- 154 | static void setVolume( struct volumeStruct volume ) 155 | { 156 | // snd_ctl_t *ctlHandle; // Simple control handle. 157 | // snd_ctl_elem_id_t *ctlId; // Simple control element id. 158 | // snd_ctl_elem_value_t *ctlControl; // Simple control element value. 159 | // snd_ctl_elem_type_t ctlType; // Simple control element type. 160 | // snd_ctl_elem_info_t *ctlInfo; // Simple control element info container. 161 | // snd_ctl_card_info_t *ctlCard; // Simple control card info container. 162 | 163 | snd_mixer_t *mixerHandle; // Mixer handle. 164 | snd_mixer_selem_id_t *mixerId; // Mixer simple element identifier. 165 | snd_mixer_elem_t *mixerElem; // Mixer element handle. 166 | 167 | // ------------------------------------------------------------------------ 168 | // Set up ALSA mixer. 169 | // ------------------------------------------------------------------------ 170 | snd_mixer_open( &mixerHandle, 0 ); 171 | snd_mixer_attach( mixerHandle, volume.card ); 172 | snd_mixer_load( mixerHandle ); 173 | snd_mixer_selem_register( mixerHandle, NULL, NULL ); 174 | 175 | snd_mixer_selem_id_alloca( &mixerId ); 176 | snd_mixer_selem_id_set_name( mixerId, volume.mixer ); 177 | mixerElem = snd_mixer_find_selem( mixerHandle, mixerId ); 178 | snd_mixer_selem_get_id( mixerElem, mixerId ); 179 | 180 | // ------------------------------------------------------------------------ 181 | // Get some information for selected mixer. 182 | // ------------------------------------------------------------------------ 183 | // Hardware volume limits. 184 | long minimum, maximum; 185 | snd_mixer_selem_get_playback_volume_range( mixerElem, &minimum, &maximum ); 186 | 187 | // ------------------------------------------------------------------------ 188 | // Calculate volume and check bounds. 189 | // ------------------------------------------------------------------------ 190 | // Calculate mapped volumes. 191 | long mappedLeft; 192 | long mappedRight; 193 | mappedLeft = getVolume( volume.left, volume.factor, minimum, maximum ); 194 | mappedRight = getVolume( volume.right, volume.factor, minimum, maximum ); 195 | 196 | // ------------------------------------------------------------------------ 197 | // Set volume. 198 | // ------------------------------------------------------------------------ 199 | // If control is mono then FL will set volume. 200 | snd_mixer_selem_set_playback_volume( mixerElem, 201 | SND_MIXER_SCHN_FRONT_LEFT, mappedLeft ); 202 | snd_mixer_selem_set_playback_volume( mixerElem, 203 | SND_MIXER_SCHN_FRONT_RIGHT, mappedRight ); 204 | 205 | // ------------------------------------------------------------------------ 206 | // Clean up. 207 | // ------------------------------------------------------------------------ 208 | snd_mixer_detach( mixerHandle, volume.card ); 209 | snd_mixer_close( mixerHandle ); 210 | 211 | return; 212 | } 213 | 214 | // ============================================================================ 215 | // Main routine. 216 | // ============================================================================ 217 | int main( int argc, char *argv[] ) 218 | { 219 | struct volumeStruct volume = 220 | { 221 | .card = "hw:0", 222 | .mixer = "PCM", 223 | .factor = 0.01, 224 | .left = 0, 225 | .right = 0 226 | }; 227 | 228 | // ------------------------------------------------------------------------ 229 | // Get command line parameters. 230 | // ------------------------------------------------------------------------ 231 | argp_parse( &argp, argc, argv, 0, 0, &volume ); 232 | 233 | setVolume( volume ); 234 | 235 | return 0; 236 | } 237 | -------------------------------------------------------------------------------- /binaries/piRotEnc.tcz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alidaf/raspberryPi/167aee27bb670890d71a110995fb20344c10726c/binaries/piRotEnc.tcz -------------------------------------------------------------------------------- /chipsPi/bcm2835/testDT.c: -------------------------------------------------------------------------------- 1 | // =========================================================================== 2 | /* 3 | testDT: 4 | 5 | Tests parsing the device tree for the BCM2835 peripherals. 6 | 7 | Copyright 2015 Darren Faulke 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . 21 | */ 22 | // =========================================================================== 23 | /* 24 | Compile with: 25 | 26 | gcc testDT.c mcp42x1.c -Wall -o testDT 27 | 28 | Also use the following flags for Raspberry Pi optimisation: 29 | -march=armv6 -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp 30 | -ffast-math -pipe -O3 31 | */ 32 | // =========================================================================== 33 | /* 34 | Authors: D.Faulke 04/01/2016 35 | 36 | Contributors: 37 | */ 38 | // =========================================================================== 39 | 40 | #define VERSION 10000 // v1.0 41 | 42 | // =========================================================================== 43 | /* 44 | Changelog: 45 | 46 | v0.1 Original version. 47 | */ 48 | // =========================================================================== 49 | 50 | 51 | // Information. -------------------------------------------------------------- 52 | /* 53 | Sources: 54 | 55 | https://www.raspberrypi.org/documentation/configuration/device-tree.md 56 | https://en.wikipedia.org/wiki/Device_tree 57 | http://elinux.org/Device_Tree 58 | http://devicetree.org/Linux 59 | 60 | Description: 61 | 62 | A device tree is a data structure for describing hardware, implemented as a 63 | tree of nodes, child nodes and properties. 64 | 65 | It is intended as a means to allow compilation of kernels that are fairly 66 | hardware agnostic within an architecture family, i.e. between different 67 | hardware revisions with slightly different peripherals. A significant part 68 | of the hardware description may be moved out of the kernel binary and into 69 | a compiled device tree blob, which is passed to the kernel by the boot 70 | loader. 71 | 72 | This is especially important for ARM-based Linux distributions such as the 73 | Raspberry Pi where traditionally, the boot loader has been customised for 74 | specific boards, creating many variants of kernel for the different boards. 75 | 76 | Intent: 77 | 78 | The Raspberry Pi has a Broadcom BCM2835 or BCM2836 chip (depending on 79 | version) that provides peripheral support. The latest Raspbian kernel now 80 | has device tree support. This program experiments with the BCM2835 device 81 | tree to test parsing and information retrieval to avoid typically using 82 | lots of unwieldly macro definitions. 83 | 84 | Device trees are written as .dts files in textual form and compiled into 85 | a flattened device tree or device tree blob (.dtb) file. Additional trees 86 | with the .dtsi extension may be referenceded via the /include/ card and are 87 | analogous to .h header files in C. 88 | 89 | Usage: 90 | 91 | RPi device tree blobs should be located in /boot/overlays/ 92 | e.g. /boot/overlays/spi-bcm2835-overlay.dtb 93 | 94 | 95 | 96 | */ 97 | // --------------------------------------------------------------------------- 98 | 99 | #include 100 | #include 101 | #include 102 | #include 103 | 104 | struct dt 105 | { 106 | struct device *device; 107 | void __iomem *base; 108 | void __iomem *base_of; 109 | void __iomem *base_node; 110 | 111 | int main() 112 | { 113 | 114 | } 115 | -------------------------------------------------------------------------------- /chipsPi/mcp23017/README.md: -------------------------------------------------------------------------------- 1 | ### MCP23017. 2 | 3 | The MCP23017 is an I2C bus operated 16-bit I/O port expander: 4 | 5 | +-----------( )-----------+ 6 | | Fn | pin | pin | Fn | 7 | |------+-----+-----+------| 8 | { | GPB0 | 01 | 28 | GPA7 | } 9 | { | GPB1 | 02 | 27 | GPA6 | } 10 | { | GPB2 | 03 | 26 | GPA5 | } 11 | BANKA GPIOs { | GPB3 | 04 | 25 | GPA4 | } BANKB GPIOs 12 | { | GPB4 | 05 | 24 | GPA3 | } 13 | { | GPB5 | 06 | 23 | GPA2 | } 14 | { | GPB6 | 07 | 22 | GPA1 | } 15 | { | GPB7 | 08 | 21 | GPA0 | } 16 | +5V <---| VDD | 09 | 20 | INTA |---> Interrupt A. 17 | GND <---| VSS | 10 | 19 | INTB |---> Interrupt B. 18 | x-| NC | 11 | 18 | RST |---> Reset when low. 19 | I2C CLK <---| SCL | 12 | 17 | A2 |---} 20 | I2C I/O <---| SDA | 13 | 16 | A1 |---} Address. 21 | x-| NC | 14 | 15 | A0 |---} 22 | +-------------------------+ 23 | 24 | The I2C address device is addressed as follows: 25 | 26 | +-----------------------------------------------+ 27 | | 0 | 1 | 0 | 0 | A2 | A1 | A0 | R/W | 28 | +-----------------------------------------------+ 29 | : <----------- slave address -----------> : : 30 | : <--------------- control byte --------------> : 31 | 32 | R/W = 0: write. 33 | R/W = 1: read. 34 | 35 | Possible addresses are therefore 0x20 to 0x27 and set by wiring 36 | pins A0 to A2 low (GND) or high (+5V). If wiring high, the pins 37 | should be connected to +5V via a 10k resistor. 38 | 39 | --- 40 | 41 | Reading/writing to the MCP23017: 42 | 43 | The MCP23017 has two 8-bit ports (PORTA & PORTB) that can operate in 44 | 8-bit or 16-bit modes. Each port has associated registers but share 45 | a configuration register IOCON. 46 | 47 | MCP23017 register addresses: 48 | 49 | +----------------------------------------------------------+ 50 | | BANK1 | BANK0 | Register | Description | 51 | |-------+-------+----------+-------------------------------| 52 | | 0x00 | 0x00 | IODIRA | IO direction (port A). | 53 | | 0x10 | 0x01 | IODIRB | IO direction (port B). | 54 | | 0x01 | 0x02 | IPOLA | Polarity (port A). | 55 | | 0x11 | 0x03 | IPOLB | Polarity (port B). | 56 | | 0x02 | 0x04 | GPINTENA | Interrupt on change (port A). | 57 | | 0x12 | 0x05 | GPINTENB | Interrupt on change (port B). | 58 | | 0x03 | 0x06 | DEFVALA | Default compare (port A). | 59 | | 0x13 | 0x07 | DEFVALB | Default compare (port B). | 60 | | 0x04 | 0x08 | INTCONA | Interrupt control (port A). | 61 | | 0x14 | 0x09 | INTCONB | Interrupt control (port B). | 62 | | 0x05 | 0x0a | IOCON | Configuration. | 63 | | 0x15 | 0x0b | IOCON | Configuration. | 64 | | 0x06 | 0x0c | GPPUA | Pull-up resistors (port A). | 65 | | 0x16 | 0x0d | GPPUB | Pull-up resistors (port B). | 66 | | 0x07 | 0x0e | INTFA | Interrupt flag (port A). | 67 | | 0x17 | 0x0f | INTFB | Interrupt flag (port B). | 68 | | 0x08 | 0x10 | INTCAPA | Interrupt capture (port A). | 69 | | 0x18 | 0x11 | INTCAPB | Interrupt capture (port B). | 70 | | 0x09 | 0x12 | GPIOA | GPIO ports (port A). | 71 | | 0x19 | 0x13 | GPIOB | GPIO ports (port B). | 72 | | 0x0a | 0x14 | OLATA | Output latches (port A). | 73 | | 0x1a | 0x15 | OLATB | Output latches (port B). | 74 | +----------------------------------------------------------+ 75 | 76 | The IOCON register bits set various configurations including the BANK 77 | bit (bit 7): 78 | 79 | +-------------------------------------------------------+ 80 | | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 | 81 | |------+------+------+------+------+------+------+------| 82 | | BANK |MIRROR|SEQOP |DISSLW| HAEN | ODR |INTPOL| ---- | 83 | +-------------------------------------------------------+ 84 | 85 | BANK = 1: PORTS are segregated, i.e. 8-bit mode. 86 | BANK = 0: PORTS are paired into 16-bit mode. 87 | MIRROR = 1: INT pins are connected. 88 | MIRROR = 0: INT pins operate independently. 89 | SEQOP = 1: Sequential operation disabled. 90 | SEQOP = 0: Sequential operation enabled. 91 | DISSLW = 1: Slew rate disabled. 92 | DISSLW = 0: Slew rate enabled. 93 | HAEN = 1: N/A for MCP23017. 94 | HAEN = 0: N/A for MCP23017. 95 | ODR = 1: INT pin configured as open-drain output. 96 | ODR = 0: INT pin configured as active driver output. 97 | INTPOL = 1: Polarity of INT pin, active = low. 98 | INTPOL = 0: Polarity of INT pin, active = high. 99 | 100 | Default is 0 for all bits. 101 | 102 | The internal pull-up resistors are 100kOhm. 103 | -------------------------------------------------------------------------------- /chipsPi/mcp23017/testmcp23017.c: -------------------------------------------------------------------------------- 1 | /* 2 | // =========================================================================== 3 | 4 | testmcp23017: 5 | 6 | Tests MCP23017 driver for the Raspberry Pi. 7 | 8 | Copyright 2015 Darren Faulke 9 | 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program. If not, see . 22 | 23 | // =========================================================================== 24 | */ 25 | 26 | #define Version "Version 0.1" 27 | 28 | /* 29 | // --------------------------------------------------------------------------- 30 | 31 | Compile with: 32 | 33 | gcc testmcp23017.c mcp23017.c -Wall -o testmcp23017 34 | 35 | Also use the following flags for Raspberry Pi optimisation: 36 | -march=armv6 -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp 37 | -ffast-math -pipe -O3 38 | 39 | // --------------------------------------------------------------------------- 40 | 41 | Authors: D.Faulke 17/12/2015 This program. 42 | 43 | Contributors: 44 | 45 | Changelog: 46 | 47 | v0.1 Original version. 48 | 49 | // Information. -------------------------------------------------------------- 50 | 51 | The MCP23017 is an I2C bus operated 16-bit I/O port expander. 52 | 53 | For testing, LEDs were connected via a breadboard as follows: 54 | 55 | +-----------( )-----------+ 56 | | Fn | pin | pin | Fn | 57 | 100R LED |------+-----+-----+------| 58 | .---/\/\/--|<|--| GPB0 | 01 | 28 | GPA7 |---/ ---. 59 | |---/\/\/--|<|--| GPB1 | 02 | 27 | GPA6 |---/ ---| 60 | |---/\/\/--|<|--| GPB2 | 03 | 26 | GPA5 |---/ ---| 61 | |---/\/\/--|<|--| GPB3 | 04 | 25 | GPA4 |---/ ---| 8 port 62 | |---/\/\/--|<|--| GPB4 | 05 | 24 | GPA3 |---/ ---| dip switch 63 | |---/\/\/--|<|--| GPB5 | 06 | 23 | GPA2 |---/ ---| 64 | |---/\/\/--|<|--| GPB6 | 07 | 22 | GPA1 |---/ ---| 65 | |---/\/\/--|<|--| GPB7 | 08 | 21 | GPA0 |---/ ---| 66 | | +3.3V <---| VDD | 09 | 20 | INTA | | 67 | GND <--'---------------| VSS | 10 | 19 | INTB | | 68 | | NC | 11 | 18 | RST |--------'----> +3.3V. 69 | I2C CLK <---| SCL | 12 | 17 | A2 |---> GND } 70 | I2C I/O <---| SDA | 13 | 16 | A1 |---> GND } Address = 0x20. 71 | | NC | 14 | 15 | A0 |---> GND } 72 | +-------------------------+ 73 | 74 | The LEDs have a forward voltage and current of 1.8V and 20mA respectively 75 | so 100Ohm resistors are reasonable although 80Ohms is more ideal. 76 | 77 | R = (3.3 - 1.8) / 20x10-3 = 75Ohm. 78 | 79 | // --------------------------------------------------------------------------- 80 | */ 81 | 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | 90 | #include "mcp23017.h" 91 | 92 | int main() 93 | { 94 | 95 | int8_t err = 0; // Return code. 96 | int8_t num = 1; // Number of MCP23017 devices. 97 | 98 | // Initialise MCP23017. Only using 1 but should work for up to 8. 99 | err = mcp23017Init( 0x20 ); 100 | if ( err < 0 ) 101 | { 102 | printf( "Couldn't init.\n" ); 103 | return -1; 104 | } 105 | 106 | // Print properties for each device. 107 | printf( "Properties.\n" ); 108 | 109 | uint8_t i; // Loop counter. 110 | 111 | for ( i = 0; i < num; i++ ) 112 | { 113 | // Start off with BANK = 0. 114 | mcp23017[i]->bank = 0; 115 | mcp23017WriteByte( mcp23017[i], IOCONA, 0x00 ); 116 | 117 | // Make sure MCP23017s have been initialised OK. 118 | printf( "\tDevice %d:\n", i ); 119 | printf( "\tHandle = %d,\n", mcp23017[i]->id ); 120 | printf( "\tAddress = 0x%02x,\n", mcp23017[i]->addr ); 121 | printf( "\tBank mode = %1d.\n", mcp23017[i]->bank ); 122 | 123 | // Set direction of GPIOs and clear latches. 124 | mcp23017WriteByte( mcp23017[i], IODIRA, 0xff ); // Input. 125 | mcp23017WriteByte( mcp23017[i], IODIRB, 0x00 ); // Output. 126 | 127 | // Writes to latches are the same as writes to GPIOs. 128 | mcp23017WriteByte( mcp23017[i], OLATA, 0x00 ); // Clear pins. 129 | mcp23017WriteByte( mcp23017[i], OLATB, 0x00 ); // Clear pins. 130 | 131 | } 132 | printf( "\n" ); 133 | 134 | // Test setting BANK modes: ---------------------------------------------- 135 | 136 | printf( "Testing writes in both BANK modes.\n" ); 137 | 138 | uint8_t j, k; // Loop counters. 139 | 140 | for ( i = 0; i < num; i++ ) // For each MCP23017. 141 | { 142 | printf( "MCP23017 %d:\n", i ); 143 | 144 | for ( j = 0; j < 2; j++ ) // Toggle BANK bit twice. 145 | { 146 | printf( "\tBANK %d.\n", mcp23017[i]->bank ); 147 | 148 | for ( k = 0; k < 0xff; k++ ) // Write 0x00 to 0xff. 149 | { 150 | mcp23017WriteByte( mcp23017[i], OLATB, k ); 151 | usleep( 50000 ); 152 | } 153 | 154 | // Reset all LEDs. 155 | mcp23017WriteByte( mcp23017[i], OLATB, 0x00 ); 156 | 157 | // Toggle BANK bit. 158 | if ( mcp23017[i]->bank == 0 ) 159 | mcp23017WriteByte( mcp23017[i], IOCONA, 0x80 ); 160 | else 161 | mcp23017WriteByte( mcp23017[i], IOCONA, 0x00 ); 162 | mcp23017[i]->bank = !mcp23017[i]->bank; 163 | } 164 | 165 | // Next MCP23017. 166 | printf( "\n" ); 167 | } 168 | 169 | // Test read & check bits functions. ------------------------------------- 170 | 171 | printf( "Testing read and bit checks.\n" ); 172 | 173 | // Check value of GPIO register set as inputs (PORT A). 174 | uint8_t data; 175 | bool match = false; 176 | for ( i = 0; i < num; i++ ) 177 | { 178 | printf( "MCP23017 %d:\n", i ); 179 | 180 | data = mcp23017ReadByte( mcp23017[i], GPIOA ); 181 | mcp23017WriteByte( mcp23017[i], OLATB, data ); 182 | printf( "\tGPIOA = 0x%02x, checking...", data ); 183 | for ( j = 0; j < 0xff; j++ ) 184 | { 185 | match = mcp23017CheckBitsByte( mcp23017[i], GPIOA, j ); 186 | if ( match ) printf( "matched to 0x%02x.\n", j ); 187 | match = false; 188 | } 189 | // Next MCP23017. 190 | printf( "\n" ); 191 | } 192 | 193 | // Continuously loop through the next tests. ----------------------------- 194 | 195 | while ( 1 ) 196 | { 197 | 198 | // Test toggle bits function. 199 | 200 | printf( "Testing toggle bits.\n" ); 201 | 202 | for ( i = 0; i < num; i++ ) 203 | { 204 | printf( "MCP23017 %d:\n", i ); 205 | 206 | printf( "\tAlternating bits.\n" ); 207 | for ( j = 0; j < 10; j++ ) 208 | { 209 | mcp23017ToggleBitsByte( mcp23017[i], OLATB, 0x55 ); 210 | usleep( 100000 ); 211 | mcp23017ToggleBitsByte( mcp23017[i], OLATB, 0x55 ); 212 | mcp23017ToggleBitsByte( mcp23017[i], OLATB, 0xaa ); 213 | usleep( 100000 ); 214 | mcp23017ToggleBitsByte( mcp23017[i], OLATB, 0xaa ); 215 | } 216 | 217 | printf( "\tAlternating nibbles.\n" ); 218 | for ( j = 0; j < 10; j++ ) 219 | { 220 | mcp23017ToggleBitsByte( mcp23017[i], OLATB, 0x0f ); 221 | usleep( 100000 ); 222 | mcp23017ToggleBitsByte( mcp23017[i], OLATB, 0x0f ); 223 | mcp23017ToggleBitsByte( mcp23017[i], OLATB, 0xf0 ); 224 | usleep( 100000 ); 225 | mcp23017ToggleBitsByte( mcp23017[i], OLATB, 0xf0 ); 226 | } 227 | // Next MCP23017. 228 | printf( "\n" ); 229 | } 230 | 231 | // Test set bits function. ------------------------------------------- 232 | 233 | printf( "Testing set and clear bits.\n" ); 234 | 235 | // Set all LEDs off and light in sequence. 236 | uint8_t setBits; 237 | uint8_t clearBits; 238 | for ( i = 0; i < num; i++ ) 239 | { 240 | printf( "MCP23017 %d:\n", i ); 241 | 242 | printf( "Setting and clearing bits 0 - 7 in sequence.\n" ); 243 | for ( j = 0; j < 10; j++ ) // Sequence through LEDs 10x. 244 | { 245 | mcp23017WriteByte( mcp23017[i], GPIOB, 0x00 ); 246 | usleep( 50000 ); 247 | for ( k = 0; k < 8; k++ ) 248 | { 249 | setBits = 1 << k; 250 | mcp23017SetBitsByte( mcp23017[i], GPIOB, setBits ); 251 | usleep( 50000 ); 252 | } 253 | usleep( 50000 ); 254 | for ( k = 0; k < 8; k++ ) 255 | { 256 | clearBits = 1 << k; 257 | mcp23017ClearBitsByte( mcp23017[i], GPIOB, clearBits ); 258 | usleep( 50000 ); 259 | } 260 | } 261 | 262 | // Next MCP23017. 263 | printf( "\n" ); 264 | } 265 | 266 | } 267 | 268 | // End of tests. --------------------------------------------------------- 269 | 270 | return 0; 271 | } 272 | -------------------------------------------------------------------------------- /chipsPi/mcp42x1/README.md: -------------------------------------------------------------------------------- 1 | ###MCP42x1 digital potentiometer driver. 2 | 3 | The **MCP42x1** is an **SPI** bus operated Dual 7/8-bit digital potentiometer with non-volatile memory. 4 | 5 | +-----------( )-----------+ 6 | | Fn | pin | pin | Fn | 7 | |------+-----+-----+------| 8 | | CS | 01 | 14 | VDD | 1.8V -> 5.5V 9 | | SCK | 02 | 13 | SDO | 10 | | SDI | 03 | 12 | SHDN | 11 | | VSS | 04 | 11 | NC | 12 | ,----- // | P1B | 05 | 10 | P0B | // -----, 13 | R[ ]<--- // | P1W | 06 | 09 | P0W | // --->[ ]R 14 | '----- // | P1A | 07 | 08 | P0A | // -----' 15 | +-------------------------+ 16 | 17 | **R** = 5, 10, 50 or 100 kOhms. Wiper resistance = 75 Ohms. 18 | 19 | +---------------------------------------+ 20 | | Fn | Description | 21 | |------+--------------------------------| 22 | | CS | SPI chip select. | 23 | | SCK | SPI clock input. | 24 | | SDI | SPI serial data in. | 25 | | VSS | GND. | 26 | | PxA | Potentiometer pin A. | 27 | | PxW | Potentiometer wiper. | 28 | | PxB | Potentiometer pin B. | 29 | | NC | Not internally connected. | 30 | | SHDN | Hardware shutdown (reset). | 31 | | SDO | Serial data out. | 32 | | VDD | Supply voltage (1.8V to 5.5V). | 33 | +---------------------------------------+ 34 | 35 | **NC** is not internally connected but should be externally connected to either **VSS** or **VDD** to reduce noise coupling. 36 | 37 | ####Device memory map: 38 | 39 | +--------------------------------+ 40 | | Addr | Function | Mem | 41 | |------+-------------------+-----| 42 | | 00h | Volatile wiper 0. | RAM | 43 | | 01h | Volatile wiper 1. | RAM | 44 | | 02h | Reserved. | --- | 45 | | 03h | Reserved. | --- | 46 | | 04h | Volatile TCON. | RAM | 47 | | 05h | Status. | RAM | 48 | | 06h+ | Reserved. | --- | 49 | +--------------------------------+ 50 | 51 | * All 16 locations are 9 bits wide. 52 | * The status register at 05h has 5 status bits, 4 of which are reserved. 53 | * Bit 1 is the shutdown status; 0 = normal, 1 = Shutdown. 54 | * The **TCON** register (Terminal Control) has 8 control bits, 4 for each wiper: 55 | 56 | +--------------------------------------------------------------+ 57 | | bit8 | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 58 | |------+------+------+------+------+------+------+------+------| 59 | | D8 | R1HW | R1A | R1W | R1B | R0HW | R0A | R0W | R0B | 60 | +--------------------------------------------------------------+ 61 | 62 | * **RxHW**: Forces potentiometer x into shutdown configuration of the **SHDN** pin; 0 = normal, 1 = forced. 63 | * **RxA**: Connects/disconnects potentiometer x pin A to/from the resistor network; 0 = connected, 1 = disconnected. 64 | * **RxW**: Connects/disconnects potentiometer x wiper to/from the resistor network; 0 = connected, 1 = disconnected. 65 | * **RxB**: Connects/disconnects potentiometer x pin B to/from the resistor network; 0 = connected, 1 = disconnected. 66 | 67 | * The **SHDN** pin, when active, overrides the state of these bits. 68 | * The maximum **SCK** (serial clock) frequency is 10 MHz. 69 | * The only **SPI** modes supported are 0,0 and 1,1. 70 | 71 | --- 72 | ####Commands: 73 | 74 | The **MCP42x1** has 4 commands: 75 | 76 | +-----------------------------------------------------+ 77 | | Command | Size | addr |cmd| data | 78 | |------------+--------+-------+---+-------------------| 79 | | Read data | 16-bit |x|x|x|x|1|1|x|x|x|x|x|x|x|x|x|x| 80 | | Write data | 16-bit |x|x|x|x|0|0|x|x|x|x|x|x|x|x|x|x| 81 | | Increment | 8-bit |x|x|x|x|0|1|x|x|-|-|-|-|-|-|-|-| 82 | | Decrement | 8-bit |x|x|x|x|1|0|x|x|-|-|-|-|-|-|-|-| 83 | +---------------------------------+-+-+-+-+-+-+-+-+-+-+ 84 | | Min resistance (x-bit) = 0x000 |0|0|0|0|0|0|0|0|0|0| 85 | | Max resistance (7-bit) = 0x080 |0|0|1|0|0|0|0|0|0|0| 86 | | Max resistance (8-bit) = 0x100 |0|1|0|0|0|0|0|0|0|0| 87 | +-----------------------------------------------------+ 88 | 89 | --- 90 | ####Testing: 91 | 92 | For testing, LEDs were connected via a breadboard as follows: 93 | 94 | +-----------( )-----------+ 95 | | Fn | pin | pin | Fn | 96 | |------+-----+-----+------| 97 | CE0 <----| CS | 01 | 14 | VDD |-----------> +5V 98 | SCKL1 <----| SCK | 02 | 13 | SDO |----> MISO 99 | MOSI <----| SDI | 03 | 12 | SHDN | 100 | GND <-,--------------| VSS | 04 | 11 | NC |--------------,-> GND 101 | | R | P1B | 05 | 10 | P0B | R | 102 | '--|<|--/\/\/--| P1W | 06 | 09 | P0W |--/\/\/--|>|--' 103 | // ,-| P1A | 07 | 08 | P0A |-, \\ 104 | LED | +-------------------------+ | LED 105 | | | 106 | '-----------------------------'---------> +5V 107 | 108 | The LEDs have a forward voltage of 1.8 V and a maximum operating current of 20 mA, therefore a 160 Ohm resistance is ideal (for 5V **VDD**) for placing in series with it. However, the wiper resistance is 75 Ohms so only an 85 Ohms resistor is needed. The closest I have is 75 Ohms, which seems fine. 109 | 110 | R = V / I. 111 | R = (5 - 1.8) / 20x10-3 = 160 Ohms. 112 | 113 | The brightness does not change very much over the lower and higher resistance ranges but is very linear of a small range in the middle. 114 | -------------------------------------------------------------------------------- /chipsPi/mcp42x1/mcp42x1.h: -------------------------------------------------------------------------------- 1 | // =========================================================================== 2 | /* 3 | mcp42x1: 4 | 5 | Driver for the MCP42x1 SPI digital potentiometer. 6 | 7 | Copyright 2015 Darren Faulke 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . 21 | */ 22 | // =========================================================================== 23 | 24 | #define MCP42X1_VERSION 01.01 25 | 26 | // =========================================================================== 27 | /* 28 | Authors: D.Faulke 15/01/2016 29 | 30 | Contributors: 31 | 32 | Changelog: 33 | 34 | v01.00 Original version. 35 | v01.01 Rewrote init routine. 36 | */ 37 | // =========================================================================== 38 | 39 | #ifndef MCP42X1_H 40 | #define MCP42X1_H 41 | 42 | 43 | // MCP42x1 information. ------------------------------------------------------ 44 | /* 45 | The MCP42x1 is an SPI bus operated Dual 7/8-bit digital potentiometer with 46 | non-volatile memory. 47 | 48 | +-----------( )-----------+ 49 | | Fn | pin | pin | Fn | 50 | |------+-----+-----+------| 51 | | CS | 01 | 14 | VDD | 1.8V -> 5.5V 52 | | SCK | 02 | 13 | SDO | 53 | | SDI | 03 | 12 | SHDN | 54 | | VSS | 04 | 11 | NC | 55 | ,----- // | P1B | 05 | 10 | P0B | // -----, 56 | R [ ]<--- // | P1W | 06 | 09 | P0W | // --->[ ] R 57 | '----- // | P1A | 07 | 08 | P0A | // -----' 58 | +-------------------------+ 59 | R = 5, 10, 50 or 100 kOhms. Wiper resistance = 75 Ohms. 60 | 61 | Key: 62 | +---------------------------------------+ 63 | | Fn | Description | 64 | |------+--------------------------------| 65 | | CS | SPI chip select. | 66 | | SCK | SPI clock input. | 67 | | SDI | SPI serial data in. | 68 | | VSS | GND. | 69 | | PxA | Potentiometer pin A. | 70 | | PxW | Potentiometer wiper. | 71 | | PxB | Potentiometer pin B. | 72 | | NC | Not internally connected. | 73 | | SHDN | Hardware shutdown (reset). | 74 | | SDO | Serial data out. | 75 | | VDD | Supply voltage (1.8V to 5.5V). | 76 | +---------------------------------------+ 77 | Notes: 78 | 79 | NC is not internally connected but should be externally connected 80 | to either VSS or VDD to reduce noise coupling. 81 | 82 | Device memory map: 83 | 84 | +--------------------------------+ 85 | | Addr | Function | Mem | 86 | |------+-------------------+-----| 87 | | 00h | Volatile wiper 0. | RAM | 88 | | 01h | Volatile wiper 1. | RAM | 89 | | 02h | Reserved. | --- | 90 | | 03h | Reserved. | --- | 91 | | 04h | Volatile TCON. | RAM | 92 | | 05h | Status. | RAM | 93 | | 06h+ | Reserved. | --- | 94 | +--------------------------------+ 95 | Notes: 96 | 97 | All 16 locations are 9 bits wide. 98 | The status register at 05h has 5 status bits, 4 of which are 99 | reserved. Bit 1 is the shutdown status; 0 = normal, 1 = Shutdown. 100 | 101 | The TCON register (Terminal CONtrol) has 8 control bits, 4 for 102 | each wiper, as shown: 103 | 104 | +--------------------------------------------------------------+ 105 | | bit8 | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 106 | |------+------+------+------+------+------+------+------+------| 107 | | D8 | R1HW | R1A | R1W | R1B | R0HW | R0A | R0W | R0B | 108 | +--------------------------------------------------------------+ 109 | 110 | RxHW : Forces potentiometer x into shutdown configuration of 111 | the SHDN pin; 0 = normal, 1 = forced. 112 | RxA : Connects/disconnects potentiometer x pin A to/from the 113 | resistor network; 0 = connected, 1 = disconnected. 114 | RxW : Connects/disconnects potentiometer x wiper to/from the 115 | resistor network; 0 = connected, 1 = disconnected. 116 | RxB : Connects/disconnects potentiometer x pin B to/from the 117 | resistor network; 0 = connected, 1 = disconnected. 118 | 119 | The SHDN pin, when active, overrides the state of these bits. 120 | 121 | The maximum SCK (serial clock) frequency is 10MHz. 122 | 123 | The only SPI modes supported are 0,0 and 1,1. 124 | 125 | Commands: 126 | 127 | The MCP42x1 has 4 commands: 128 | 129 | +-----------------------------------------------------+ 130 | | Command | Size | addr |cmd| data | 131 | |------------+--------+-------+---+-------------------| 132 | | Read data | 16-bit |x|x|x|x|1|1|x|x|x|x|x|x|x|x|x|x| 133 | | Write data | 16-bit |x|x|x|x|0|0|x|x|x|x|x|x|x|x|x|x| 134 | | Increment | 8-bit |x|x|x|x|0|1|x|x|-|-|-|-|-|-|-|-| 135 | | Decrement | 8-bit |x|x|x|x|1|0|x|x|-|-|-|-|-|-|-|-| 136 | +---------------------------------+-+-+-+-+-+-+-+-+-+-+ 137 | | Min resistance (x-bit) = 0x000 |0|0|0|0|0|0|0|0|0|0| 138 | | Max resistance (7-bit) = 0x080 |0|0|1|0|0|0|0|0|0|0| 139 | | Max resistance (8-bit) = 0x100 |0|1|0|0|0|0|0|0|0|0| 140 | +-----------------------------------------------------+ 141 | */ 142 | 143 | // MCP42x1 data. ------------------------------------------------------------- 144 | 145 | // Max number of MCP42X1 chips, determined by No of chip selects. 146 | #define MCP42X1_DEVICES 2 // SPI0 has 2 chip selects but AUX has 3. 147 | #define MCP42X1_WIPERS 2 // Number of wipers on MCP42x1. 148 | #define MCP42X1_RMIN 0x0000 // Minimum wiper value. 149 | #define MCP42X1_RMAX 0x0101 // Maximum wiper value. 150 | 151 | // Maximum SCK frequency = 10MHz. 152 | #define MCP42X1_SPI_BAUD 10000000 153 | 154 | // Commands. 155 | #define MCP42X1_CMD_WRITE 0x0 156 | #define MCP42X1_CMD_INC 0x1 157 | #define MCP42X1_CMD_DEC 0x2 158 | #define MCP42X1_CMD_READ 0x3 159 | 160 | // MCP42x1 register addresses. 161 | enum mcp42x1_registers 162 | { 163 | MCP42X1_REG_WIPER0 = 0x0, // Wiper for resistor network 0. 164 | MCP42X1_REG_WIPER1 = 0x1, // Wiper for resistor network 1. 165 | MCP42X1_REG_TCON = 0x4, // Terminal control. 166 | MCP42X1_REG_STATUS = 0x5 // Status. 167 | }; 168 | 169 | // TCON register masks. 170 | enum mcp42x1_tcon 171 | { 172 | MCP42X1_TCON_R0B = 0x01, // Resistor newtork 0, pin B. 173 | MCP42X1_TCON_R0W = 0x02, // Resistor network 0, wiper. 174 | MCP42X1_TCON_R0A = 0x04, // Resistor network 0, pin A. 175 | MCP42X1_TCON_R0HW = 0x08, // Resistor network 0, hardware configuration. 176 | MCP42X1_TCON_R1B = 0x10, // Resistor network 1, pin B. 177 | MCP42X1_TCON_R1W = 0x20, // Resistor network 1, wiper. 178 | MCP42X1_TCON_R1A = 0x40, // Resistor network 1, pin A. 179 | MCP42X1_TCON_R1HW = 0x80 // Resistor network 1, hardware configuration. 180 | }; 181 | 182 | // Error codes. 183 | enum mcp42x1_error 184 | { 185 | MCP42X1_ERR_NOINIT = -1, // Couldn't initialise MCP42x1. 186 | MCP42X1_ERR_NOWIPER = -2, // Wiper is invalid. 187 | MCP42X1_ERR_NOMEM = -3, // Not enough memory. 188 | MCP42X1_ERR_DUPLIC = -4, // Duplicate properties. 189 | }; 190 | 191 | struct mcp42x1 192 | { 193 | uint8_t spi; // SPI handle. 194 | uint8_t wiper; // Wiper. 195 | }; 196 | 197 | struct mcp42x1 *mcp42x1[MCP42X1_DEVICES * MCP42X1_WIPERS]; 198 | 199 | 200 | // MCP42x1 functions. -------------------------------------------------------- 201 | 202 | // --------------------------------------------------------------------------- 203 | // Returns value of MCP42x1 register. 204 | // --------------------------------------------------------------------------- 205 | int16_t mcp42x1ReadReg( uint8_t spi, uint8_t reg ); 206 | 207 | // --------------------------------------------------------------------------- 208 | // Writes bytes to register of MCP42x1. 209 | // --------------------------------------------------------------------------- 210 | void mcp42x1WriteReg( uint8_t spi, uint8_t reg, uint16_t data ); 211 | 212 | // --------------------------------------------------------------------------- 213 | // Sets wiper resistance. 214 | // --------------------------------------------------------------------------- 215 | void mcp42x1SetResistance( uint8_t spi, uint8_t wiper, uint16_t value ); 216 | 217 | // --------------------------------------------------------------------------- 218 | // Increments wiper resistance. 219 | // --------------------------------------------------------------------------- 220 | void mcp42x1IncResistance( uint8_t spi, uint8_t wiper ); 221 | 222 | // --------------------------------------------------------------------------- 223 | // Decrements wiper resistance. 224 | // --------------------------------------------------------------------------- 225 | void mcp42x1DecResistance( uint8_t spi, uint8_t wiper ); 226 | 227 | // --------------------------------------------------------------------------- 228 | // Initialises MCP42x1. Call for each MCP42x1. 229 | // --------------------------------------------------------------------------- 230 | int8_t mcp42x1Init( uint8_t spi, uint8_t wiper ); 231 | 232 | #endif // #ifndef MCP42X1_H 233 | -------------------------------------------------------------------------------- /chipsPi/mcp42x1/testmcp42x1.c: -------------------------------------------------------------------------------- 1 | /* 2 | // =========================================================================== 3 | 4 | testmcp42x1: 5 | 6 | Tests MCP42x1 driver for the Raspberry Pi. 7 | 8 | Copyright 2015 Darren Faulke 9 | 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program. If not, see . 22 | 23 | // =========================================================================== 24 | */ 25 | 26 | #define TESTMCP42X1_VERSION 01.02 27 | 28 | /* 29 | // --------------------------------------------------------------------------- 30 | 31 | Compile with: 32 | 33 | gcc testmcp42x1.c mcp42x1.c -Wall -o testmcp42x1 -lpigpio lpthread 34 | 35 | Also use the following flags for Raspberry Pi optimisation: 36 | -march=armv6 -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp 37 | -ffast-math -pipe -O3 38 | 39 | // --------------------------------------------------------------------------- 40 | 41 | Authors: D.Faulke 15/01/2016 42 | 43 | Contributors: 44 | 45 | Changelog: 46 | 47 | v01.00 Original version. 48 | v01.01 Modified init routine. 49 | v01.02 Modified test circuit. 50 | 51 | // Information. -------------------------------------------------------------- 52 | 53 | The MCP42x1 is an SPI bus operated Dual 7/8-bit digital potentiometer with 54 | non-volatile memory. 55 | 56 | For testing, LEDs were connected via a breadboard as follows: 57 | 58 | +-----------( )-----------+ 59 | | Fn | pin | pin | Fn | 60 | |------+-----+-----+------| 61 | CE0 <----| CS | 01 | 14 | VDD |-----------> +5V 62 | SCKL1 <----| SCK | 02 | 13 | SDO |----> MISO 63 | MOSI <----| SDI | 03 | 12 | SHDN | 64 | GND <-;--------------| VSS | 04 | 11 | NC |--------------;-> GND 65 | | R | P1B | 05 | 10 | P0B | R | 66 | '--|<|--/\/\/--| P1W | 06 | 09 | P0W |--/\/\/--|>|--' 67 | // ,-| P1A | 07 | 08 | P0A |-, \\ 68 | LED | +-------------------------+ | LED 69 | | | 70 | '-----------------------------'---------> +5V 71 | 72 | The LEDs have a forward voltage of 1.8 V and a max current of 20 mA, 73 | therefore a 160 Ohm resistance is ideal (for 5 V VDD) for placing 74 | in series with it: 75 | 76 | R = V / I. 77 | R = (5 - 1.8) / 20x10-3 = 160 Ohms. 78 | 79 | However, the wiper resistance is already 75 Ohms so only an 85 Ohm 80 | resistor is needed. The closest I have is 75 Ohms, which seems fine. 81 | 82 | NC is not internally connected but can be externally connected to VDD 83 | or VSS to reduce noise coupling. 84 | 85 | // --------------------------------------------------------------------------- 86 | */ 87 | 88 | #include 89 | #include 90 | #include 91 | #include 92 | #include 93 | #include 94 | #include 95 | #include 96 | 97 | #include "mcp42x1.h" 98 | 99 | int main() 100 | { 101 | 102 | uint8_t spi; // SPI handle. 103 | uint8_t device[MCP42X1_DEVICES * MCP42X1_WIPERS]; // MCP42x1 handles. 104 | 105 | /* 106 | Setting the SPI flags: 107 | 108 | +-----------------------------------------------------------------+ 109 | |21|20|19|18|17|16|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| 110 | |-----------------+--+--+-----------+--+--+--+--+--+--+--+--+-----| 111 | | word size | R| T| num bytes | W| A|u2|u1|u0|p2|p1|p0| mode| 112 | +-----------------------------------------------------------------+ 113 | 114 | MCP42x1 can only operate in 0,0 or 1,1 mode; 0,0 is default. 115 | All other values can stay at default = 0. 116 | Therefore SPI flags = 0. 117 | */ 118 | 119 | uint8_t flags = 0; // SPI flags for default operation. 120 | uint16_t i; // Loop counter. 121 | uint16_t data; // Register data. 122 | 123 | printf( "Initialising.\n\n" ); 124 | 125 | gpioInitialise(); // Initialise pigpio. 126 | printf( "GPIO initialised ok!\n" ); 127 | 128 | spi = spiOpen( 0, MCP42X1_SPI_BAUD, flags ); // Initialise SPI for CS = 0. 129 | if ( spi < 0 ) return -1; 130 | printf( "SPI initialised ok!\n" ); 131 | printf( "SPI handle = %d.\n", spi ); 132 | 133 | // Initialise MCP42X1 twice, once for each wiper. 134 | mcp42x1Init( spi, 0 ); // Wiper 0. 135 | mcp42x1Init( spi, 1 ); // Wiper 1. 136 | 137 | // Check that devices have initialised. 138 | for ( i = 0; mcp42x1[i] != NULL; i++ ) 139 | if ( device[i] < 0 ) return -1; 140 | printf( "Devices initialised ok!\n\n" ); 141 | 142 | // Print properties for each device. 143 | printf( "Properties:\n\n" ); 144 | for ( i = 0; (mcp42x1[i] != NULL); i++ ) 145 | { 146 | printf( "Device %d.\n", i ); 147 | printf( "SPI handle = %d,\n", mcp42x1[i]->spi ); 148 | printf( "Wiper = 0d.\n", mcp42x1[i]->wiper ); 149 | printf( "\n" ); 150 | } 151 | 152 | // Test reading status register. ----------------------------------------- 153 | 154 | printf( "Reading Registers:\n\n" ); 155 | data = mcp42x1ReadReg( 0, MCP42X1_REG_TCON ); 156 | printf( "TCON register = 0x%04x,\n", data ); 157 | data = mcp42x1ReadReg( 0, MCP42X1_REG_STATUS ); 158 | printf( "Status register = 0x%04x,\n", data ); 159 | data = mcp42x1ReadReg( 0, MCP42X1_REG_WIPER0 ); 160 | printf( "Wiper0 register = 0x%04x,\n", data ); 161 | data = mcp42x1ReadReg( 0, MCP42X1_REG_WIPER1 ); 162 | printf( "Wiper1 register = 0x%04x.\n", data ); 163 | printf( "\n" ); 164 | 165 | // Test setting wiper values. -------------------------------------------- 166 | 167 | // Set wiper values. 168 | mcp42x1SetResistance ( mcp42x1[0]->spi, mcp42x1[0]->wiper, MCP42X1_RMAX ); 169 | mcp42x1SetResistance ( mcp42x1[1]->spi, mcp42x1[1]->wiper, MCP42X1_RMIN ); 170 | printf( "Set starting values.\n\n" ); 171 | 172 | // Make sure values have stuck. 173 | data = mcp42x1ReadReg( 0, MCP42X1_REG_WIPER0 ); 174 | printf( "Wiper0 register = 0x%04x,\n", data ); 175 | data = mcp42x1ReadReg( 0, MCP42X1_REG_WIPER1 ); 176 | printf( "Wiper1 register = 0x%04x.\n", data ); 177 | printf( "\n" ); 178 | 179 | 180 | // Test increment and decrement. ----------------------------------------- 181 | 182 | printf( "Cycling wiper resistances.\n" ); 183 | for ( ; ; ) // Continual loop. 184 | { 185 | for ( i = MCP42X1_RMIN; i < MCP42X1_RMAX; i++ ) 186 | { 187 | // mcp42x1DecResistance( mcp42x1[0]->spi, mcp42x1[0]->wiper ); 188 | // mcp42x1IncResistance( mcp42x1[1]->spi, mcp42x1[1]->wiper ); 189 | mcp42x1SetResistance ( mcp42x1[0]->spi, 190 | mcp42x1[0]->wiper, i ); 191 | mcp42x1SetResistance ( mcp42x1[1]->spi, 192 | mcp42x1[1]->wiper, MCP42X1_RMAX - i ); 193 | gpioDelay( 10000 ); 194 | } 195 | for ( i = MCP42X1_RMIN; i < MCP42X1_RMAX; i++ ) 196 | { 197 | // mcp42x1IncResistance( mcp42x1[0]->spi, mcp42x1[0]->wiper ); 198 | // mcp42x1DecResistance( mcp42x1[1]->spi, mcp42x1[1]->wiper ); 199 | mcp42x1SetResistance ( mcp42x1[0]->spi, 200 | mcp42x1[0]->wiper, MCP42X1_RMAX - i ); 201 | mcp42x1SetResistance ( mcp42x1[1]->spi, 202 | mcp42x1[1]->wiper, i ); 203 | gpioDelay( 10000 ); 204 | } 205 | } 206 | 207 | printf( "Finished.\n" ); 208 | return 0; 209 | } 210 | -------------------------------------------------------------------------------- /displayPi/hd44780gpio/README.md: -------------------------------------------------------------------------------- 1 | ### HD44780 2 | 3 | Pin layout for Hitachi HD44780 based LCD display. 4 | 5 | +------------------------------------------------------------+ 6 | | Pin | Label | Pi | Description | 7 | |-----+-------+------+---------------------------------------| 8 | | 1 | Vss | GND | Ground (0V) for logic. | 9 | | 2 | Vdd | 5V | 5V supply for logic. | 10 | | 3 | Vo | xV | Variable V for contrast. | 11 | | 4 | RS | GPIO | Register Select. 0: command, 1: data. | 12 | | 5 | RW | GND | R/W. 0: write, 1: read. *Caution* | 13 | | 6 | E | GPIO | Enable bit. | 14 | | 7 | DB0 | n/a | Data bit 0. Not used in 4-bit mode. | 15 | | 8 | DB1 | n/a | Data bit 1. Not used in 4-bit mode. | 16 | | 9 | DB2 | n/a | Data bit 2. Not used in 4-bit mode. | 17 | | 10 | DB3 | n/a | Data bit 3. Not used in 4-bit mode. | 18 | | 11 | DB4 | GPIO | Data bit 4. | 19 | | 12 | DB5 | GPIO | Data bit 5. | 20 | | 13 | DB6 | GPIO | Data bit 6. | 21 | | 14 | DB7 | GPIO | Data bit 7. | 22 | | 15 | A | xV | Voltage for backlight (max 5V). | 23 | | 16 | K | GND | Ground (0V) for backlight. | 24 | +------------------------------------------------------------+ 25 | 26 | LCD register bits: 27 | 28 | +---------------------------------------+ +-------------------+ 29 | |RS |RW |DB7|DB6|DB5|DB4|DB3|DB2|DB1|DB0| |Key|Effect | 30 | |---+---+---+---+---+---+---+---+---+---| |---+---------------| 31 | | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | |I/D|DDRAM inc/dec. | 32 | | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | - | |R/L|Shift R/L. | 33 | | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |I/D| S | |S |Shift on. | 34 | | 0 | 0 | 0 | 0 | 0 | 0 | 1 | D | C | B | |DL |4-bit/8-bit. | 35 | | 0 | 0 | 0 | 0 | 0 | 1 |S/C|R/L| - | - | |D |Display on/off.| 36 | | 0 | 0 | 0 | 0 | 1 |DL | N | F | - | - | |N |1/2 lines. | 37 | | 0 | 0 | 0 | 1 | : CGRAM address : | |C |Cursor on/off. | 38 | | 0 | 0 | 1 | : DDRAM address : | |F |5x8/5x10 font. | 39 | | 0 | 1 |BF | : Address counter : | |B |Blink on/off. | 40 | | 1 | 0 | : : Read Data : : : | |S/C|Display/cursor.| 41 | | 1 | 1 | : : Write Data: : : | |BF |Busy flag. | 42 | +---------------------------------------+ +-------------------+ 43 | 44 | DDRAM: Display Data RAM. 45 | CGRAM: Character Generator RAM. 46 | -------------------------------------------------------------------------------- /displayPi/hd44780gpio/testhd44780gpio.c: -------------------------------------------------------------------------------- 1 | /* 2 | // =========================================================================== 3 | 4 | testHD44780gpio: 5 | 6 | Tests HD44780 LCD display driver for the Raspberry Pi (GPIO version). 7 | 8 | Copyright 2015 Darren Faulke 9 | 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program. If not, see . 22 | 23 | // =========================================================================== 24 | */ 25 | 26 | #define Version "Version 0.2" 27 | 28 | /* 29 | // --------------------------------------------------------------------------- 30 | 31 | Compile with: 32 | 33 | gcc testHD44780gpio.c hd44780.c -Wall -o testhd44780gpio 34 | -lwiringPi -lpthread 35 | 36 | Also use the following flags for Raspberry Pi optimisation: 37 | -march=armv6 -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp 38 | -ffast-math -pipe -O3 39 | 40 | // --------------------------------------------------------------------------- 41 | 42 | Authors: D.Faulke 24/12/2015 43 | 44 | Contributors: 45 | 46 | Changelog: 47 | 48 | v0.1 Original version. 49 | v0.2 Rewrote code into libraries. 50 | 51 | // --------------------------------------------------------------------------- 52 | */ 53 | 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | 63 | #include "hd44780gpioPi.h" 64 | 65 | int main() 66 | { 67 | bool data = 0; // 4-bit mode. 68 | bool lines = 1; // 2 display lines. 69 | bool font = 1; // 5x8 font. 70 | bool display = 1; // Display on. 71 | bool cursor = 0; // Cursor off. 72 | bool blink = 0; // Blink (block cursor) off. 73 | bool counter = 1; // Increment DDRAM counter after data write 74 | bool shift = 0; // Do not shift display after data write. 75 | bool mode = 0; // Shift cursor. 76 | bool direction = 0; // Right. 77 | 78 | // Initialise display. 79 | hd44780Init( data, lines, font, display, cursor, blink, 80 | counter, shift, mode, direction ); 81 | 82 | // Set up structure to display current time. 83 | struct Calendar time = 84 | { 85 | .row = 1, 86 | .col = 4, 87 | .length = 16, 88 | .format[0] = "%H:%M:%S", 89 | .format[1] = "%H %M %S", 90 | .delay = 0.5 91 | }; 92 | 93 | // Set up structure to display current date. 94 | struct Calendar date = 95 | { 96 | .row = 0, 97 | .col = 0, 98 | .length = 16, 99 | .format[0] = "%a %d %b %Y", 100 | .format[1] = "%a %d %b %Y", 101 | .delay = 360 102 | }; 103 | 104 | // Set ticker tape properties. 105 | struct tickerStruct ticker = 106 | { 107 | .text = "This text is really long and used to demonstrate the ticker!", 108 | .length = strlen( ticker.text ), 109 | .padding = 6, 110 | .row = 1, 111 | .increment = 1, 112 | .delay = 300 113 | }; 114 | 115 | // Create threads and mutex for animated display functions. 116 | pthread_mutex_init( &displayBusy, NULL ); 117 | pthread_t threads[2]; 118 | 119 | pthread_create( &threads[0], NULL, displayCalendar, (void *) &date ); 120 | pthread_create( &threads[1], NULL, displayCalendar, (void *) &time ); 121 | // pthread_create( &threads[1], NULL, displayPacMan, (void *) pacManRow ); 122 | // pthread_create( &threads[1], NULL, displayTicker, (void *) &ticker ); 123 | 124 | while (1) 125 | { 126 | }; 127 | 128 | displayClear(); 129 | displayHome(); 130 | 131 | // Clean up threads. 132 | pthread_mutex_destroy( &displayBusy ); 133 | pthread_exit( NULL ); 134 | 135 | } 136 | -------------------------------------------------------------------------------- /displayPi/hd44780i2c/README.md: -------------------------------------------------------------------------------- 1 | ### HD44780 2 | 3 | Pin layout for Hitachi HD44780 based LCD display. 4 | 5 | +------------------------------------------------------------+ 6 | | Pin | Label | Pi | Description | 7 | |-----+-------+------+---------------------------------------| 8 | | 1 | Vss | GND | Ground (0V) for logic. | 9 | | 2 | Vdd | 5V | 5V supply for logic. | 10 | | 3 | Vo | xV | Variable V for contrast. | 11 | | 4 | RS | GPIO | Register Select. 0: command, 1: data. | 12 | | 5 | RW | GND | R/W. 0: write, 1: read. *Caution* | 13 | | 6 | E | GPIO | Enable bit. | 14 | | 7 | DB0 | n/a | Data bit 0. Not used in 4-bit mode. | 15 | | 8 | DB1 | n/a | Data bit 1. Not used in 4-bit mode. | 16 | | 9 | DB2 | n/a | Data bit 2. Not used in 4-bit mode. | 17 | | 10 | DB3 | n/a | Data bit 3. Not used in 4-bit mode. | 18 | | 11 | DB4 | GPIO | Data bit 4. | 19 | | 12 | DB5 | GPIO | Data bit 5. | 20 | | 13 | DB6 | GPIO | Data bit 6. | 21 | | 14 | DB7 | GPIO | Data bit 7. | 22 | | 15 | A | xV | Voltage for backlight (max 5V). | 23 | | 16 | K | GND | Ground (0V) for backlight. | 24 | +------------------------------------------------------------+ 25 | 26 | LCD register bits: 27 | 28 | +---------------------------------------+ +-------------------+ 29 | |RS |RW |DB7|DB6|DB5|DB4|DB3|DB2|DB1|DB0| |Key|Effect | 30 | |---+---+---+---+---+---+---+---+---+---| |---+---------------| 31 | | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | |I/D|DDRAM inc/dec. | 32 | | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | - | |R/L|Shift R/L. | 33 | | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |I/D| S | |S |Shift on. | 34 | | 0 | 0 | 0 | 0 | 0 | 0 | 1 | D | C | B | |DL |4-bit/8-bit. | 35 | | 0 | 0 | 0 | 0 | 0 | 1 |S/C|R/L| - | - | |D |Display on/off.| 36 | | 0 | 0 | 0 | 0 | 1 |DL | N | F | - | - | |N |1/2 lines. | 37 | | 0 | 0 | 0 | 1 | : CGRAM address : | |C |Cursor on/off. | 38 | | 0 | 0 | 1 | : DDRAM address : | |F |5x8/5x10 font. | 39 | | 0 | 1 |BF | : Address counter : | |B |Blink on/off. | 40 | | 1 | 0 | : : Read Data : : : | |S/C|Display/cursor.| 41 | | 1 | 1 | : : Write Data: : : | |BF |Busy flag. | 42 | +---------------------------------------+ +-------------------+ 43 | 44 | DDRAM: Display Data RAM. 45 | CGRAM: Character Generator RAM. 46 | -------------------------------------------------------------------------------- /displayPi/hd44780i2c/testhd44780i2c.c: -------------------------------------------------------------------------------- 1 | /* 2 | // =========================================================================== 3 | 4 | testhd44780i2c: 5 | 6 | Tests HD44780 LCD display driver for the Raspberry Pi (I2C version). 7 | 8 | Copyright 2015 Darren Faulke 9 | 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program. If not, see . 22 | 23 | // =========================================================================== 24 | */ 25 | 26 | #define Version "Version 0.1" 27 | 28 | /* 29 | // --------------------------------------------------------------------------- 30 | 31 | Compile with: 32 | 33 | gcc testhd44780i2c.c hd44780i2c.c mcp23017.c -Wall -o testhd44780i2c 34 | -lpthread 35 | 36 | Also use the following flags for Raspberry Pi optimisation: 37 | -march=armv6 -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp 38 | -ffast-math -pipe -O3 39 | 40 | // --------------------------------------------------------------------------- 41 | 42 | Authors: D.Faulke 24/12/2015 43 | 44 | Contributors: 45 | 46 | Changelog: 47 | 48 | v0.1 Original version. 49 | 50 | // Information. -------------------------------------------------------------- 51 | 52 | The MCP23017 is an I2C bus operated 16-bit I/O port expander. 53 | 54 | For testing, the HD44780 LCD was connected via a breadboard as follows: 55 | 56 | GND 57 | | 10k 58 | +-----------+ +---\/\/\--x 59 | | pin | Fn | | | 60 | |-----+-----| | | ,----------------------------------, 61 | | 1 | VSS |---' | | ,--------------------------------|-, 62 | | 2 | VDD |--> 5V | | | ,------------------------------|-|-, 63 | | 3 | Vo |---------' | | | | | | 64 | | 4 | RS |-------------' | | +-----------( )-----------+ | | | 65 | | 5 | R/W |---------------' | | Fn | pin | pin | Fn | | | | 66 | | 6 | E |-----------------' |------+-----+-----+------| | | | 67 | | 7 | DB0 |------------------>| GPB0 | 01 | 28 | GPA7 |<-' | | 68 | | 8 | DB1 |------------------>| GPB1 | 02 | 27 | GPA6 |<---' | 69 | | 9 | DB2 |------------------>| GPB2 | 03 | 26 | GPA5 |<-----' 70 | | 10 | DB3 |------------------>| GPB3 | 04 | 25 | GPA4 | 71 | | 11 | DB4 |------------------>| GPB4 | 05 | 24 | GPA3 | 72 | | 12 | DB5 |------------------>| GPB5 | 06 | 23 | GPA2 | 73 | | 13 | DB6 |------------------>| GPB6 | 07 | 22 | GPA1 | 74 | | 14 | DB7 |------------------>| GPB7 | 08 | 21 | GPA0 | 75 | | 15 | A |--+----------------| VDD | 09 | 20 | INTA | 76 | | 16 | K |--|----+-----------| VSS | 10 | 19 | INTB | 77 | +-----------+ | | | NC | 11 | 18 | RST |-----> +5V 78 | | | ,----| SCL | 12 | 17 | A2 |---, 79 | | | | ,-| SDA | 13 | 16 | A1 |---+-> GND 80 | | | | | | NC | 14 | 15 | A0 |---' 81 | v v | | +-------------------------+ 82 | +5V GND | | 83 | {-+ +-} 84 | { << } Logic level shifter * 85 | {-+ +-} (bi-directional) 86 | | | 87 | v v 88 | SCL1 SDA1 89 | 90 | Notes: Vo is connected to the wiper of a 10k trim pot to adjust the 91 | contrast. A similar (perhaps 5k) pot could be used to adjust the 92 | backlight but connecting to 3.3V works OK instead. These displays 93 | are commonly sold with a single 10k pot. 94 | 95 | * The HD44780 operates slightly faster at 5V but 3.3V works fine. 96 | The MCP23017 expander can operate at both levels. The Pi's I2C 97 | pins have pull-up resistors that should protect against 5V levels 98 | but use a logic level shifter if there is any doubt. 99 | 100 | // --------------------------------------------------------------------------- 101 | */ 102 | 103 | #include 104 | #include 105 | #include 106 | #include 107 | #include 108 | #include 109 | #include 110 | #include 111 | 112 | #include "hd44780i2c.h" 113 | #include "mcp23017.h" 114 | 115 | int main() 116 | { 117 | bool data = 1; // 8-bit mode. 118 | bool lines = 1; // 2 display lines. 119 | bool font = 1; // 5x8 font. 120 | bool display = 1; // Display on. 121 | bool cursor = 0; // Cursor off. 122 | bool blink = 0; // Blink (block cursor) off. 123 | bool counter = 1; // Increment DDRAM counter after data write 124 | bool shift = 0; // Do not shift display after data write. 125 | bool mode = 0; // Shift cursor. 126 | bool direction = 0; // Right. 127 | 128 | int8_t err; 129 | 130 | // Initialise MCP23017. 131 | err = mcp23017Init( 0x20 ); 132 | if ( err < 0 ) 133 | { 134 | printf( "Couldn't init. Try loading i2c-dev module.\n" ); 135 | return -1; 136 | } 137 | 138 | // Set direction of GPIOs. 139 | mcp23017WriteByte( mcp23017[0], IODIRA, 0x00 ); // Output. 140 | mcp23017WriteByte( mcp23017[0], IODIRB, 0x00 ); // Output. 141 | 142 | // Writes to latches are the same as writes to GPIOs. 143 | mcp23017WriteByte( mcp23017[0], OLATA, 0x00 ); // Clear pins. 144 | mcp23017WriteByte( mcp23017[0], OLATB, 0x00 ); // Clear pins. 145 | 146 | // Set BANK bit for 8-bit mode. 147 | mcp23017WriteByte( mcp23017[0], IOCONA, 0x80 ); 148 | 149 | struct hd44780 *hd44780this; 150 | 151 | hd44780this = malloc( sizeof( struct hd44780 )); 152 | 153 | /* 154 | +---------------------------------------------------------------+ 155 | | GPIOB | GPIOA | 156 | |-------------------------------+-------------------------------| 157 | | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 158 | |---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---| 159 | |DB7|DB6|DB5|DB4|DB3|DB2|DB1|DB0|RS |R/W| E |---|---|---|---|---| 160 | +---------------------------------------------------------------+ 161 | */ 162 | 163 | // Set up hd44780 data. 164 | hd44780this->rs = 0x80; // HD44780 RS pin. 165 | hd44780this->rw = 0x40; // HD44780 R/W pin. 166 | hd44780this->en = 0x20; // HD44780 E pin. 167 | 168 | hd44780[0] = hd44780this; 169 | 170 | // Initialise display. 171 | hd44780Init( mcp23017[0], hd44780[0], 172 | data, lines, font, display, cursor, blink, 173 | counter, shift, mode, direction ); 174 | 175 | hd44780WriteString( mcp23017[0], hd44780[0], "Initialised" ); 176 | 177 | // Set up structure to display current time. 178 | struct calendar time = 179 | { 180 | .mcp23017 = mcp23017[0], // Initialised MCP23017. 181 | .hd44780 = hd44780[0], // Initialised HD44780. 182 | .delay.tv_sec = 0, // 0 full seconds. 183 | .delay.tv_usec = 500000, // 0.5 seconds. 184 | .row = 1, 185 | .col = 4, 186 | .length = 16, 187 | .frames = FRAMES_MAX, 188 | .format[0] = "%H:%M:%S", 189 | .format[1] = "%H %M %S" 190 | }; 191 | 192 | // Set up structure to display current date. 193 | struct calendar date = 194 | { 195 | .mcp23017 = mcp23017[0], // Initialised MCP23017. 196 | .hd44780 = hd44780[0], // Initialised HD44780. 197 | .delay.tv_sec = 60, // 1 minute. 198 | .delay.tv_usec = 0, // 0 microseconds. 199 | .row = 0, 200 | .col = 0, 201 | .length = 16, 202 | .frames = 1, 203 | .format[0] = "%a %d %b %Y" 204 | }; 205 | 206 | // Set ticker tape properties. 207 | struct ticker ticker = 208 | { 209 | .mcp23017 = mcp23017[0], // Initialised MCP23017. 210 | .hd44780 = hd44780[0], // Initialised HD44780. 211 | .delay.tv_sec = 0, // Seconds. } 212 | .delay.tv_usec = 100000, // Microseconds. } Adjust for flicker. 213 | .text = "This text is really long and used to demonstrate the ticker!", 214 | .length = strlen( ticker.text ), 215 | .padding = 6, 216 | .row = 1, 217 | .increment = 1 218 | }; 219 | 220 | // Create threads and mutex for animated display functions. 221 | pthread_mutex_init( &displayBusy, NULL ); 222 | pthread_t threads[2]; 223 | 224 | /* 225 | The HD44780 has a slow response so animation times should be as 226 | large as possible and not mixed with other routines that have high 227 | animation duty, e.g. ticker and time display with animation. 228 | */ 229 | pthread_create( &threads[0], NULL, displayCalendar, (void *) &date ); 230 | pthread_create( &threads[1], NULL, displayCalendar, (void *) &time ); 231 | // pthread_create( &threads[1], NULL, displayPacMan, (void *) pacManRow ); 232 | // pthread_create( &threads[1], NULL, displayTicker, (void *) &ticker ); 233 | 234 | while (1) 235 | { 236 | }; 237 | 238 | hd44780Clear( mcp23017[0], hd44780[0] ); 239 | hd44780Home( mcp23017[0], hd44780[0] ); 240 | 241 | // Clean up threads. 242 | pthread_mutex_destroy( &displayBusy ); 243 | pthread_exit( NULL ); 244 | 245 | } 246 | -------------------------------------------------------------------------------- /displayPi/hd44780i2c/testmcp23017.c: -------------------------------------------------------------------------------- 1 | /* 2 | // =========================================================================== 3 | 4 | testmcp23017: 5 | 6 | Tests MCP23017 driver for the Raspberry Pi. 7 | 8 | Copyright 2015 Darren Faulke 9 | 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program. If not, see . 22 | 23 | // =========================================================================== 24 | */ 25 | 26 | #define Version "Version 0.1" 27 | 28 | /* 29 | // --------------------------------------------------------------------------- 30 | 31 | Compile with: 32 | 33 | gcc testmcp23017.c mcp23017.c -Wall -o testmcp23017 34 | 35 | Also use the following flags for Raspberry Pi optimisation: 36 | -march=armv6 -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp 37 | -ffast-math -pipe -O3 38 | 39 | // --------------------------------------------------------------------------- 40 | 41 | Authors: D.Faulke 17/12/2015 This program. 42 | 43 | Contributors: 44 | 45 | Changelog: 46 | 47 | v0.1 Original version. 48 | 49 | // Information. -------------------------------------------------------------- 50 | 51 | The MCP23017 is an I2C bus operated 16-bit I/O port expander. 52 | 53 | For testing, LEDs were connected via a breadboard as follows: 54 | 55 | +-----------( )-----------+ 56 | | Fn | pin | pin | Fn | 57 | 100R LED |------+-----+-----+------| 58 | .---/\/\/--|<|--| GPB0 | 01 | 28 | GPA7 |---/ ---. 59 | |---/\/\/--|<|--| GPB1 | 02 | 27 | GPA6 |---/ ---| 60 | |---/\/\/--|<|--| GPB2 | 03 | 26 | GPA5 |---/ ---| 61 | |---/\/\/--|<|--| GPB3 | 04 | 25 | GPA4 |---/ ---| 8 port 62 | |---/\/\/--|<|--| GPB4 | 05 | 24 | GPA3 |---/ ---| dip switch 63 | |---/\/\/--|<|--| GPB5 | 06 | 23 | GPA2 |---/ ---| 64 | |---/\/\/--|<|--| GPB6 | 07 | 22 | GPA1 |---/ ---| 65 | |---/\/\/--|<|--| GPB7 | 08 | 21 | GPA0 |---/ ---| 66 | | +3.3V <---| VDD | 09 | 20 | INTA | | 67 | GND <--'---------------| VSS | 10 | 19 | INTB | | 68 | | NC | 11 | 18 | RST |--------'----> +3.3V. 69 | I2C CLK <---| SCL | 12 | 17 | A2 |---> GND } 70 | I2C I/O <---| SDA | 13 | 16 | A1 |---> GND } Address = 0x20. 71 | | NC | 14 | 15 | A0 |---> GND } 72 | +-------------------------+ 73 | 74 | The LEDs have a forward voltage and current of 1.8V and 20mA respectively 75 | so 100Ohm resistors are reasonable although 80Ohms is more ideal. 76 | 77 | R = (3.3 - 1.8) / 20x10-3 = 75Ohm. 78 | 79 | // --------------------------------------------------------------------------- 80 | */ 81 | 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | 90 | #include "mcp23017.h" 91 | 92 | int main() 93 | { 94 | 95 | int8_t err = 0; // Return code. 96 | int8_t num = 1; // Number of MCP23017 devices. 97 | 98 | // Initialise MCP23017. Only using 1 but should work for up to 8. 99 | err = mcp23017Init( 0x20 ); 100 | if ( err < 0 ) 101 | { 102 | printf( "Couldn't init.\n" ); 103 | return -1; 104 | } 105 | 106 | // Print properties for each device. 107 | printf( "Properties.\n" ); 108 | 109 | uint8_t i; // Loop counter. 110 | 111 | for ( i = 0; i < num; i++ ) 112 | { 113 | // Start off with BANK = 0. 114 | mcp23017[i]->bank = 0; 115 | mcp23017WriteByte( mcp23017[i], IOCONA, 0x00 ); 116 | 117 | // Make sure MCP23017s have been initialised OK. 118 | printf( "\tDevice %d:\n", i ); 119 | printf( "\tHandle = %d,\n", mcp23017[i]->id ); 120 | printf( "\tAddress = 0x%02x,\n", mcp23017[i]->addr ); 121 | printf( "\tBank mode = %1d.\n", mcp23017[i]->bank ); 122 | 123 | // Set direction of GPIOs and clear latches. 124 | mcp23017WriteByte( mcp23017[i], IODIRA, 0xff ); // Input. 125 | mcp23017WriteByte( mcp23017[i], IODIRB, 0x00 ); // Output. 126 | 127 | // Writes to latches are the same as writes to GPIOs. 128 | mcp23017WriteByte( mcp23017[i], OLATA, 0x00 ); // Clear pins. 129 | mcp23017WriteByte( mcp23017[i], OLATB, 0x00 ); // Clear pins. 130 | 131 | } 132 | printf( "\n" ); 133 | 134 | // Test setting BANK modes: ---------------------------------------------- 135 | 136 | printf( "Testing writes in both BANK modes.\n" ); 137 | 138 | uint8_t j, k; // Loop counters. 139 | 140 | for ( i = 0; i < num; i++ ) // For each MCP23017. 141 | { 142 | printf( "MCP23017 %d:\n", i ); 143 | 144 | for ( j = 0; j < 2; j++ ) // Toggle BANK bit twice. 145 | { 146 | printf( "\tBANK %d.\n", mcp23017[i]->bank ); 147 | 148 | for ( k = 0; k < 0xff; k++ ) // Write 0x00 to 0xff. 149 | { 150 | mcp23017WriteByte( mcp23017[i], OLATB, k ); 151 | usleep( 50000 ); 152 | } 153 | 154 | // Reset all LEDs. 155 | mcp23017WriteByte( mcp23017[i], OLATB, 0x00 ); 156 | 157 | // Toggle BANK bit. 158 | if ( mcp23017[i]->bank == 0 ) 159 | mcp23017WriteByte( mcp23017[i], IOCONA, 0x80 ); 160 | else 161 | mcp23017WriteByte( mcp23017[i], IOCONA, 0x00 ); 162 | mcp23017[i]->bank = !mcp23017[i]->bank; 163 | } 164 | 165 | // Next MCP23017. 166 | printf( "\n" ); 167 | } 168 | 169 | // Test read & check bits functions. ------------------------------------- 170 | 171 | printf( "Testing read and bit checks.\n" ); 172 | 173 | // Check value of GPIO register set as inputs (PORT A). 174 | uint8_t data; 175 | bool match = false; 176 | for ( i = 0; i < num; i++ ) 177 | { 178 | printf( "MCP23017 %d:\n", i ); 179 | 180 | data = mcp23017ReadByte( mcp23017[i], GPIOA ); 181 | mcp23017WriteByte( mcp23017[i], OLATB, data ); 182 | printf( "\tGPIOA = 0x%02x, checking...", data ); 183 | for ( j = 0; j < 0xff; j++ ) 184 | { 185 | match = mcp23017CheckBitsByte( mcp23017[i], GPIOA, j ); 186 | if ( match ) printf( "matched to 0x%02x.\n", j ); 187 | match = false; 188 | } 189 | // Next MCP23017. 190 | printf( "\n" ); 191 | } 192 | 193 | // Continuously loop through the next tests. ----------------------------- 194 | 195 | while ( 1 ) 196 | { 197 | 198 | // Test toggle bits function. 199 | 200 | printf( "Testing toggle bits.\n" ); 201 | 202 | for ( i = 0; i < num; i++ ) 203 | { 204 | printf( "MCP23017 %d:\n", i ); 205 | 206 | printf( "\tAlternating bits.\n" ); 207 | for ( j = 0; j < 10; j++ ) 208 | { 209 | mcp23017ToggleBitsByte( mcp23017[i], OLATB, 0x55 ); 210 | usleep( 100000 ); 211 | mcp23017ToggleBitsByte( mcp23017[i], OLATB, 0x55 ); 212 | mcp23017ToggleBitsByte( mcp23017[i], OLATB, 0xaa ); 213 | usleep( 100000 ); 214 | mcp23017ToggleBitsByte( mcp23017[i], OLATB, 0xaa ); 215 | } 216 | 217 | printf( "\tAlternating nibbles.\n" ); 218 | for ( j = 0; j < 10; j++ ) 219 | { 220 | mcp23017ToggleBitsByte( mcp23017[i], OLATB, 0x0f ); 221 | usleep( 100000 ); 222 | mcp23017ToggleBitsByte( mcp23017[i], OLATB, 0x0f ); 223 | mcp23017ToggleBitsByte( mcp23017[i], OLATB, 0xf0 ); 224 | usleep( 100000 ); 225 | mcp23017ToggleBitsByte( mcp23017[i], OLATB, 0xf0 ); 226 | } 227 | // Next MCP23017. 228 | printf( "\n" ); 229 | } 230 | 231 | // Test set bits function. ------------------------------------------- 232 | 233 | printf( "Testing set and clear bits.\n" ); 234 | 235 | // Set all LEDs off and light in sequence. 236 | uint8_t setBits; 237 | uint8_t clearBits; 238 | for ( i = 0; i < num; i++ ) 239 | { 240 | printf( "MCP23017 %d:\n", i ); 241 | 242 | printf( "Setting and clearing bits 0 - 7 in sequence.\n" ); 243 | for ( j = 0; j < 10; j++ ) // Sequence through LEDs 10x. 244 | { 245 | mcp23017WriteByte( mcp23017[i], GPIOB, 0x00 ); 246 | usleep( 50000 ); 247 | for ( k = 0; k < 8; k++ ) 248 | { 249 | setBits = 1 << k; 250 | mcp23017SetBitsByte( mcp23017[i], GPIOB, setBits ); 251 | usleep( 50000 ); 252 | } 253 | usleep( 50000 ); 254 | for ( k = 0; k < 8; k++ ) 255 | { 256 | clearBits = 1 << k; 257 | mcp23017ClearBitsByte( mcp23017[i], GPIOB, clearBits ); 258 | usleep( 50000 ); 259 | } 260 | } 261 | 262 | // Next MCP23017. 263 | printf( "\n" ); 264 | } 265 | 266 | } 267 | 268 | // End of tests. --------------------------------------------------------- 269 | 270 | return 0; 271 | } 272 | -------------------------------------------------------------------------------- /displayPi/ssd1322-spi/README.md: -------------------------------------------------------------------------------- 1 | ###SSD1322-SPI 2 | 3 | A library for using a SSD1322 based OLED display via the SPI bus. 4 | 5 | Compilation: 6 | 7 | gcc -c -fpic -Wall ssd1322-spi.c -lpigpio 8 | 9 | Also use the following flags for Raspberry Pi optimisation: 10 | 11 | -march=armv6 -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp -ffast-math -pipe -O3 12 | 13 | Based on the following guides and codes: 14 | * SSD1322 datasheet from Solomon Systech (www.solomon-systech.com). 15 | 16 | An example of such a display is the East Rising ER-OLEDM032-1 series: 17 | 18 | ** Caveat Emptor: ** 19 | 20 | It appears that the operating mode is configured by a couple of zero Ohm resistors soldered onto the back of the board rather than jumpers. It isn't at all clear that the buyer should specify a preference or be prepared to desolder and move them. Not an easy task given how small they are. 21 | 22 | The configurations according to where the resistors should be placed are: 23 | 24 | ,---------------------------, 25 | | Mode | BS1 | BS0 | 26 | |---------------+-----+-----| 27 | | 6800 parallel | R18 | R20 | 28 | | 8080 parallel | R18 | R21 | 29 | | 4-wire SPI | R19 | R21 | 30 | | 3-wire SPI | R19 | R20 | 31 | '---------------------------' 32 | 33 | The pin configuration is: 34 | 35 | ,-------------, 36 | | 2 [o o] 1 | 37 | | 4 [o o] 3 | 38 | | 6 [o o] 5 | 39 | | 8 [o o] 7 | 40 | | 10 [o o] 9 | 41 | | 12 [o o] 11 | 42 | | 14 [o o] 13 | 43 | | 16 [o o] 15 | 44 | '-------------' 45 | 46 | For SPI mode, the pin designations and relevant RPi pins are: 47 | 48 | ,---------------------------------------------------------, 49 | | Pin | Fn | Notes | RPi connect | 50 | |-----+--------+----------------------------+-------------+ 51 | | 1 | VSS | Ground. | GND | 52 | | 2 | VBAT | Power (3.3-5V). | +5V | 53 | | 3 | NC | Leave floating. | - | 54 | | 4 | DB0 | SPI SCLK | SPI0_SCLK | 55 | | 5 | DB1 | SPI SDIN | SPI0_MOSI | 56 | | 6 | DB2 | Leave floating. | - | 57 | | 7 | DB3 | - | GND | 58 | | 8 | DB4 | - | GND | 59 | | 9 | DB5 | - | GND | 60 | | 10 | DB6 | - | GND | 61 | | 11 | DB7 | - | GND | 62 | | 12 | /RD | - | GND | 63 | | 13 | /WR | - | GND | 64 | | 14 | /DC | Data/Command for 4-wire. | GPIOxx | 65 | | 15 | /RESET | Power Reset. | GPIOxx | 66 | | 16 | /CS | SPI Chip Select. | SPI0_CEx_N | 67 | '---------------------------------------------------------' 68 | 69 | SPI mode does not allow reads so MISO is not used. 70 | 71 | Command/Data mode is set by the /DC flag (low for command, high for data). SDIN is shifted into an 8-bit register on every rising edge of SCLK (DB0) with the MSB first, i.e. D7, D6, D5, D4, D3, D2, D1, D0. 72 | 73 | ####Operation: 74 | 75 | The display I have is 256x64 but the SSD1322 controller supports up to 480x128. This means that there is additional ram that can be used and shifted or scrolled. 76 | 77 | Rows correspond to the number of pixels top to bottom but the columns group 4 pixels in each, hence there are 120 columns of 4 pixels. Each pixel has a 4-bit address in the display RAM. 78 | 79 | Drawing an arbitrary pixel therefore requires setting the row and column and writing 2 bytes of data that contain the pixel to set. 80 | 81 | ####Framebuffer: 82 | 83 | In order to remove the complexity of drawing individual pixels and accounting for any already underlying image, I have implemented a very basic framebuffer as a thread. The framebuffer thread simply writes the entire content of the buffer to the display in a constant loop. Graphics are simply drawn to the buffer instead, which has a 1:1 pixel mapping with the display. The test incorporates an animation of a 64x64 image (from Fallout 4) and an other 256x64 image. 84 | 85 | ###To-Do: 86 | 87 | Drawing text with predefined fonts. I have designed a font that I want to use with the display but haven't yet implemented it while I'm busy working on the graphics and graphic primitives. Testing with an Arduino library shows up some kerning issues that I want to have a look at. 88 | -------------------------------------------------------------------------------- /displayPi/ssd1322-spi/fb/README.md: -------------------------------------------------------------------------------- 1 | ###Framebuffer 2 | 3 | This is a collection of programs taken from the blog at http://raspberrycompote.blogspot.co.uk, used to test and develop code for the SSD1322 display via the fbtft framebuffer driver. 4 | -------------------------------------------------------------------------------- /displayPi/ssd1322-spi/fb/fb-query.c: -------------------------------------------------------------------------------- 1 | // =========================================================================== 2 | /* 3 | fb-query: 4 | 5 | This is a framebuffer query program taken from the blog at ... 6 | 7 | http://raspberrycompote.blogspot.co.uk. 8 | 9 | It displays the size and colour depth in bpp (bits per pixel). 10 | 11 | The only change to the code is the explicit reference to the fbtft 12 | framebuffer device /dev/fb1 rather than the default /dev/fb0. 13 | */ 14 | // =========================================================================== 15 | /* 16 | Compile with: 17 | 18 | make fbquery 19 | 20 | */ 21 | 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | // application entry point 32 | int main(int argc, char* argv[]) 33 | { 34 | int fbfd = 0; // framebuffer filedescriptor 35 | struct fb_var_screeninfo var_info; 36 | 37 | // Open the framebuffer device file for reading and writing 38 | fbfd = open("/dev/fb1", O_RDWR); 39 | if (fbfd == -1) 40 | { 41 | printf("Error: cannot open framebuffer device.\n"); 42 | return(1); 43 | } 44 | printf("The framebuffer device opened.\n"); 45 | 46 | // Get variable screen information 47 | if (ioctl(fbfd, FBIOGET_VSCREENINFO, &var_info)) 48 | { 49 | printf("Error reading variable screen info.\n"); 50 | } 51 | printf("Display info %dx%d, %d bpp\n", 52 | var_info.xres, var_info.yres, 53 | var_info.bits_per_pixel ); 54 | 55 | // close file 56 | close(fbfd); 57 | 58 | return 0; 59 | 60 | } 61 | -------------------------------------------------------------------------------- /displayPi/ssd1322-spi/fb/fb-test2.c: -------------------------------------------------------------------------------- 1 | // =========================================================================== 2 | /* 3 | fb-test2: 4 | 5 | This is a framebuffer test program taken from the blog at ... 6 | 7 | http://raspberrycompote.blogspot.co.uk. 8 | 9 | It displays the size and colour depth in bpp (bits per pixel) and fills 10 | half of the display with colour. 11 | 12 | The only change to the code is the explicit reference to the fbtft 13 | framebuffer device /dev/fb1 rather than the default /dev/fb0. 14 | */ 15 | // =========================================================================== 16 | /* 17 | Compile with: 18 | 19 | make fb-test2 20 | 21 | */ 22 | 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | // application entry point 33 | int main(int argc, char* argv[]) 34 | { 35 | int fbfd = 0; 36 | struct fb_var_screeninfo vinfo; 37 | struct fb_fix_screeninfo finfo; 38 | long int screensize = 0; 39 | char *fbp = 0; 40 | uint i; 41 | 42 | // Open the file for reading and writing 43 | fbfd = open("/dev/fb1", O_RDWR); 44 | if (!fbfd) 45 | { 46 | printf("Error: cannot open framebuffer device.\n"); 47 | return(1); 48 | } 49 | printf("The framebuffer device was opened successfully.\n"); 50 | 51 | // Get fixed screen information 52 | if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) 53 | { 54 | printf("Error reading fixed information.\n"); 55 | } 56 | 57 | // Get variable screen information 58 | if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) 59 | { 60 | printf("Error reading variable information.\n"); 61 | } 62 | printf("%dx%d, %d bpp\n", vinfo.xres, vinfo.yres, 63 | vinfo.bits_per_pixel ); 64 | 65 | // map framebuffer to user memory 66 | screensize = finfo.smem_len; 67 | 68 | fbp = (char*)mmap(0, 69 | screensize, 70 | PROT_READ | PROT_WRITE, 71 | MAP_SHARED, 72 | fbfd, 0); 73 | 74 | if ((int)fbp == -1) 75 | { 76 | printf("Failed to mmap.\n"); 77 | } 78 | else 79 | { 80 | // draw... 81 | // just fill upper half of the screen with something 82 | for ( i = 0; i < 0xff; i++ ) 83 | { 84 | memset(fbp, i, screensize/2); 85 | // and lower half with something else 86 | memset(fbp + screensize/2, 0xff - i, screensize/2); 87 | } 88 | } 89 | 90 | // cleanup 91 | munmap(fbp, screensize); 92 | close(fbfd); 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /displayPi/ssd1322-spi/fbtft/fb_ssd1322.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "fbtft.h" 10 | 11 | #define DRVNAME "fb_ssd1322" 12 | #define WIDTH 256 13 | #define HEIGHT 64 14 | #define GAMMA_NUM 1 15 | #define GAMMA_LEN 15 16 | #define DEFAULT_GAMMA "7 1 1 1 1 2 2 3 3 4 4 5 5 6 6" 17 | 18 | int init[] = { /* Initialization for LM560G-256064 5.6" OLED display */ 19 | -1, 0xFD, 0x12, /* Unlock OLED driver IC */ 20 | -1, 0xAE, /* Display OFF (blank) */ 21 | -1, 0xB3, 0xF3, /* Display divide clockratio/frequency */ 22 | -1, 0xCA, 0x3F, /* Multiplex ratio, 1/64, 64 COMS enabled */ 23 | -1, 0xA2, 0x00, /* Set offset, the display map starting line is COM0 */ 24 | -1, 0xA1, 0x00, /* Set start line position */ 25 | -1, 0xA0, 0x14, 0x11, /* Set remap, horiz address increment, disable colum address remap, */ 26 | /* enable nibble remap, scan from com[N-1] to COM0, disable COM split odd even */ 27 | -1, 0xAB, 0x01, /* Select external VDD */ 28 | -1, 0xB4, 0xA0, 0xFD, /* Display enhancement A, external VSL, enhanced low GS display quality */ 29 | -1, 0xC1, 0xFF, /* Contrast current, 256 steps, default is 0x7F */ 30 | -1, 0xC7, 0x0F, /* Master contrast current, 16 steps, default is 0x0F */ 31 | -1, 0xB1, 0xF0, /* Phase Length */ 32 | -1, 0xD1, 0x82, 0x20 /* Display enhancement B */ 33 | -1, 0xBB, 0x0D, /* Pre-charge voltage */ 34 | -1, 0xBE, 0x00, /* Set VCOMH */ 35 | -1, 0xA6, /* Normal display */ 36 | -1, 0xAF, /* Display ON */ 37 | -3 }; 38 | 39 | 40 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 41 | { 42 | int width = par->info->var.xres; 43 | int offset = (480 - width) / 8; 44 | 45 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 46 | 47 | write_reg(par, 0x15, offset, offset + (width / 4) - 1); 48 | write_reg(par, 0x75, ys, ye); 49 | write_reg(par, 0x5c); 50 | } 51 | 52 | /* 53 | Grayscale Lookup Table 54 | GS1 - GS15 55 | The "Gamma curve" contains the relative values between the entries in the Lookup table. 56 | 57 | 0 = Setting of GS1 < Setting of GS2 < Setting of GS3..... < Setting of GS14 < Setting of GS15 58 | 59 | */ 60 | static int set_gamma(struct fbtft_par *par, unsigned long *curves) 61 | { 62 | unsigned long tmp[GAMMA_LEN * GAMMA_NUM]; 63 | int i, acc = 0; 64 | 65 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 66 | 67 | for (i = 0; i < GAMMA_LEN; i++) { 68 | if (i > 0 && curves[i] < 1) { 69 | dev_err(par->info->device, 70 | "Illegal value in Grayscale Lookup Table at index %d. " \ 71 | "Must be greater than 0\n", i); 72 | return -EINVAL; 73 | } 74 | acc += curves[i]; 75 | tmp[i] = acc; 76 | if (acc > 180) { 77 | dev_err(par->info->device, 78 | "Illegal value(s) in Grayscale Lookup Table. " \ 79 | "At index=%d, the accumulated value has exceeded 180\n", i); 80 | return -EINVAL; 81 | } 82 | } 83 | 84 | write_reg(par, 0xB8, 85 | tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], 86 | tmp[8], tmp[9], tmp[10], tmp[11], tmp[12], tmp[13], tmp[14]); 87 | 88 | return 0; 89 | } 90 | 91 | static int blank(struct fbtft_par *par, bool on) 92 | { 93 | fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n", __func__, on ? "true" : "false"); 94 | if (on) 95 | write_reg(par, 0xAE); 96 | else 97 | write_reg(par, 0xAF); 98 | return 0; 99 | } 100 | 101 | 102 | #define CYR 613 /* 2.392 */ 103 | #define CYG 601 /* 2.348 */ 104 | #define CYB 233 /* 0.912 */ 105 | 106 | static unsigned int rgb565_to_y(unsigned int rgb) 107 | { 108 | rgb = cpu_to_le16(rgb); 109 | return CYR * (rgb >> 11) + CYG * (rgb >> 5 & 0x3F) + CYB * (rgb & 0x1F); 110 | } 111 | 112 | static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) 113 | { 114 | u16 *vmem16 = (u16 *)(par->info->screen_base); 115 | u8 *buf = par->txbuf.buf; 116 | int y, x, bl_height, bl_width; 117 | int ret = 0; 118 | 119 | /* Set data line beforehand */ 120 | gpio_set_value(par->gpio.dc, 1); 121 | 122 | /* convert offset to word index from byte index */ 123 | offset /= 2; 124 | bl_width = par->info->var.xres; 125 | bl_height = len / par->info->fix.line_length; 126 | 127 | fbtft_par_dbg(DEBUG_WRITE_VMEM, par, 128 | "%s(offset=0x%x bl_width=%d bl_height=%d)\n", __func__, offset, bl_width, bl_height); 129 | 130 | for (y = 0; y < bl_height; y++) { 131 | for (x = 0; x < bl_width / 2; x++) { 132 | *buf = cpu_to_le16(rgb565_to_y(vmem16[offset++])) >> 8 & 0xF0; 133 | *buf++ |= cpu_to_le16(rgb565_to_y(vmem16[offset++])) >> 12; 134 | } 135 | } 136 | 137 | /* Write data */ 138 | ret = par->fbtftops.write(par, par->txbuf.buf, bl_width/2*bl_height); 139 | if (ret < 0) 140 | dev_err(par->info->device, "%s: write failed and returned: %d\n", __func__, ret); 141 | 142 | return ret; 143 | } 144 | 145 | static struct fbtft_display display = { 146 | .regwidth = 8, 147 | .width = WIDTH, 148 | .height = HEIGHT, 149 | .txbuflen = WIDTH*HEIGHT/2, 150 | .gamma_num = GAMMA_NUM, 151 | .gamma_len = GAMMA_LEN, 152 | .gamma = DEFAULT_GAMMA, 153 | .init_sequence = init, 154 | .fbtftops = { 155 | .write_vmem = write_vmem, 156 | .set_addr_win = set_addr_win, 157 | .blank = blank, 158 | .set_gamma = set_gamma, 159 | }, 160 | }; 161 | 162 | FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1322", &display); 163 | 164 | MODULE_ALIAS("spi:" DRVNAME); 165 | MODULE_ALIAS("platform:" DRVNAME); 166 | MODULE_ALIAS("spi:ssd1322"); 167 | MODULE_ALIAS("platform:ssd1322"); 168 | 169 | MODULE_DESCRIPTION("SSD1322 OLED Driver"); 170 | MODULE_AUTHOR("Ryan Press"); 171 | MODULE_LICENSE("GPL"); 172 | -------------------------------------------------------------------------------- /displayPi/ssd1322-spi/fbtft/ssd1322-spi-overlay.dts: -------------------------------------------------------------------------------- 1 | /* 2 | Device Tree overlay for SSD1322 SPI controller. 3 | 4 | Based on overlay for Sainsmart 3.2" display by Alexander Lehmann 5 | https://github.com/Flugtiger 6 | 7 | Default pins: 8 | DC# = GPIO23 9 | RESET# = GPIO24 10 | 11 | */ 12 | 13 | /dts-v1/; 14 | /plugin/; 15 | 16 | / { 17 | compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; 18 | 19 | fragment@0 20 | { 21 | target = <&spi0>; 22 | __overlay__ 23 | { 24 | status = "okay"; 25 | 26 | spidev@0 27 | { 28 | status = "disabled"; 29 | }; 30 | 31 | spidev@1 32 | { 33 | status = "disabled"; 34 | }; 35 | }; 36 | }; 37 | 38 | fragment@1 39 | { 40 | target = <&gpio>; 41 | __overlay__ 42 | { 43 | ssd1322_pins: ssd1322_pins 44 | { 45 | brcm,pins = <23 24>; 46 | brcm,function = <1 1>; 47 | }; 48 | }; 49 | }; 50 | 51 | fragment@2 52 | { 53 | target = <&spi0>; 54 | __overlay__ 55 | { 56 | #address-cells = <1>; 57 | #size-cells = <0>; 58 | 59 | ssd1322: ssd1322@0 60 | { 61 | compatible = "solomon,ssd1322"; 62 | reg = <0>; 63 | 64 | pinctrl-names = "default"; 65 | pinctrl-0 = <&ssd1322_pins>; 66 | 67 | spi-max-frequency = <16000000>; 68 | buswidth = <8>; 69 | rotate = <0>; 70 | bgr = <0>; 71 | fps = <20>; 72 | 73 | reset-gpios = <&gpio 24 0>; 74 | dc-gpios = <&gpio 23 1>; 75 | debug = <3>; 76 | }; 77 | 78 | }; 79 | }; 80 | 81 | __overrides__ 82 | { 83 | speed = <&ssd1322>,"spi-max-frequency:0"; 84 | rotate = <&ssd1322>,"rotate:0"; 85 | bgr = <&ssd1322>,"bgr:0"; 86 | fps = <&ssd1322>,"fps:0"; 87 | resetgpio = <&ssd1322>,"reset-gpios:4", 88 | <&ssd1322_pins>, "brcm,pins:1"; 89 | dcgpio = <&ssd1322>,"dc-gpios:4", 90 | <&ssd1322_pins>, "brcm,pins:2"; 91 | debug = <&ssd1322>,"debug:0"; 92 | }; 93 | }; 94 | 95 | -------------------------------------------------------------------------------- /gpioPi/testSysPi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define IN 0 10 | #define OUT 1 11 | 12 | #define LOW 0 13 | #define HIGH 1 14 | 15 | #define POUT 4 /* P1-07 */ 16 | #define BUFFER_MAX 3 17 | #define DIRECTION_MAX 48 18 | 19 | static int GPIOExport( int pin ) 20 | { 21 | char buffer[ BUFFER_MAX ]; 22 | int len; 23 | int fd; 24 | 25 | fd = open( "/sys/class/gpio/export", O_WRONLY ); 26 | if ( fd < 0 ) 27 | { 28 | fprintf( stderr, "Failed to open export for writing!\n" ); 29 | return( -1 ); 30 | } 31 | 32 | len = snprintf( buffer, BUFFER_MAX, "%d", pin ); 33 | write( fd, buffer, len ); 34 | 35 | close( fd ); 36 | return( 0 ); 37 | } 38 | 39 | static int GPIOUnexport( int pin ) 40 | { 41 | char buffer[ BUFFER_MAX ]; 42 | int len; 43 | int fd; 44 | 45 | fd = open( "/sys/class/gpio/unexport", O_WRONLY ); 46 | if ( fd < 0 ) 47 | { 48 | fprintf( stderr, "Failed to open unexport for writing!\n" ); 49 | return( -1 ); 50 | } 51 | 52 | len = snprintf( buffer, BUFFER_MAX, "%d", pin ); 53 | write( fd, buffer, len ); 54 | 55 | close( fd ); 56 | return( 0 ); 57 | } 58 | 59 | static int GPIODirection( int pin, int dir ) 60 | { 61 | static const char dir_str[] = "in\0out"; 62 | char path[ DIRECTION_MAX ]; 63 | int fd; 64 | 65 | snprintf( path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/direction", pin ); 66 | fd = open( path, O_WRONLY ); 67 | if ( fd < 0 ) 68 | { 69 | fprintf( stderr, "failed to open gpio direction for writing!\n" ); 70 | return( -1 ); 71 | } 72 | 73 | if ( write( fd, &dir_str[ dir == IN ? 0 : 3 ], dir == IN ? 2 : 3 ) < 0 ) 74 | { 75 | fprintf( stderr, "failed to set direction!\n" ); 76 | return( -1 ); 77 | } 78 | 79 | close( fd ); 80 | return( 0 ); 81 | } 82 | 83 | static int GPIORead( int pin ) 84 | { 85 | char path[ DIRECTION_MAX ]; 86 | char value_str[ 3 ]; 87 | int fd; 88 | 89 | snprintf( path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/value", pin ); 90 | fd = open( path, O_RDONLY ); 91 | if ( fd < 0 ) 92 | { 93 | fprintf( stderr, "failed to open gpio value for reading!\n" ); 94 | return( -1 ); 95 | } 96 | 97 | if ( read( fd, value_str, 3 ) < 0 ) 98 | { 99 | fprintf( stderr, "failed to read value!\n" ); 100 | return( -1 ); 101 | } 102 | 103 | close( fd ); 104 | return( atoi( value_str )); 105 | } 106 | 107 | static int GPIOWrite( int pin, int value ) 108 | { 109 | static const char s_values_str[] = "01"; 110 | char path[ DIRECTION_MAX ]; 111 | int fd; 112 | 113 | snprintf( path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/value", pin ); 114 | fd = open( path, O_WRONLY ); 115 | if ( fd < 0 ) 116 | { 117 | fprintf( stderr, "failed to open gpio value for writing!\n" ); 118 | return( -1 ); 119 | } 120 | 121 | if ( write( fd, &s_values_str[ value == LOW ? 0 : 1 ], 1 ) < 0 ) 122 | { 123 | fprintf( stderr, "failed to write value!\n" ); 124 | return( -1 ); 125 | } 126 | 127 | close( fd ); 128 | return( 0 ); 129 | } 130 | -------------------------------------------------------------------------------- /meterPi/README.md: -------------------------------------------------------------------------------- 1 | ###MeterPi 2 | 3 | This library is intended to provide some metering functions for audio streams, displayed on small LCD or OLED displays, or a termina with ncurses. It is intended to be IEC compliant but there may have to be compromises for small displays. The functions currently use the Squeezelite shared memory map, enabled with the -v switch, but it is intended that this reliance is removed at some point and depend only on any audio player via ALSA or JACK audio. 4 | -------------------------------------------------------------------------------- /meterPi/meterPi.h: -------------------------------------------------------------------------------- 1 | // =========================================================================== 2 | /* 3 | meterPi: 4 | 5 | Library to provide audio metering. Intended for use with LMS streams 6 | via squeezelite to feed small LCD displays. 7 | 8 | Copyright 2016 Darren Faulke 9 | 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program. If not, see . 22 | */ 23 | // =========================================================================== 24 | /* 25 | Authors: D.Faulke 13/02/2016 26 | 27 | Contributors: 28 | 29 | Changelog: 30 | 31 | v01.00 Original version. 32 | v01.01 Renamed and converted to library. 33 | v01.02 Added hold and fall timing. 34 | v01.03 Added overload detection. 35 | */ 36 | // =========================================================================== 37 | 38 | #ifndef METERPI_H 39 | #define METERPI_H 40 | 41 | // Info. --------------------------------------------------------------------- 42 | /* 43 | I have searched high and low for details on how to capture ALSA PCM data to 44 | be able to code some audio meters but the API is difficult to understand 45 | and most examples rely on creating a recording ring buffer, creating or 46 | modifying a .asoundrc file and opening a local audio file rather than a 47 | stream. 48 | The primary aim is to use Squeezelite as a player on the Tiny Core Linux 49 | platform, streaming from a Logitech Media Server. Squeezelite has a 50 | companion control and visualisation app (Jivelite) that requires a 51 | graphical desktop but taps into a shared memory buffer. There is little in 52 | the way of an API so this code represents an effort to figure out the 53 | shared buffer and use it allow visualisations to be coded for small LCD or 54 | OLED displays. 55 | */ 56 | 57 | /* 58 | Peak Level Meter: 59 | 60 | According to IEC 60268-18 (1995), peak level meters should have the 61 | following characteristics: 62 | 63 | Delay time < 150ms. 64 | Integration time < 5ms. 65 | Return time < 1.7s +/- 0.3s. 66 | Hold time = 1.0s +/- 0.5s. 67 | 68 | The IEC60268-18 (1995) specification defines minimum scale markings per dB. 69 | 70 | +-------------------------------------------------+ 71 | | Range | Numbers | Ticks | 72 | |----------------+----------------+---------------| 73 | | 0dB -> -20dB | 5dB intervals | 1dB intervals | 74 | | -20dB -> -40dB | 10dB intervals | none | 75 | | -40dB -> -60dB | 10dB intervals | at 45dB | 76 | +-------------------------------------------------+ 77 | 78 | A typical LED panel display can extend down to -96dB for 16-bit audio or 79 | -144dB for 24-bit audio. However, there are limitations due to The intended 80 | use here for an LCD with 16 columns 81 | 82 | A hardware peak meter with level hold using LEDs can be made with two 83 | multiplexed circuits; a bar graph mode circuit for the integrated signal 84 | and a dot mode circuit for the peak hold. These are multiplexed together 85 | to form the PPM display. 86 | 87 | Typical panel LCD 16x2 example (transposed) 88 | 89 | dBfs L R 90 | 0 [ ] [ ] 91 | -2 [ ] [ ] col dBfs cell 92 | -4 [ ] [ ] 16 0 [ ] [ ] 93 | -6 [ ] [ ] 15 -2 [ ] [ ] 94 | -8 [ ] [ ] 14 -4 [ ] [ ] 95 | -10 [ ] [ ] 13 -6 [ ] [ ] 96 | -12 [ ] [ ] 12 -8 [ ] [ ] 97 | -14 [ ] [ ] 11 -10 [ ] [ ] 98 | -16 [ ] [ ] 10 -12 [ ] [ ] 99 | -18 [ ] [ ] 9 -14 [ ] [ ] 100 | -20 [ ] [ ] 8 -16 [ ] [ ] 101 | -30 [ ] [ ] 7 -18 [ ] [ ] 102 | -40 [ ] [ ] 6 -20 [ ] [ ] 103 | -50 [ ] [ ] 5 -30 [ ] [ ] 104 | [ ] [ ] 4 -40 [ ] [ ] 105 | -70 [ ] [ ] 3 -50 [ ] [ ] 106 | [ ] [ ] 2 -60 [ ] [ ] 107 | -96 [ ] [ ] 1 -80 [L] [R] 108 | [ ] [ ] 109 | -inf [ ] [ ] 110 | 111 | Even though 0dBfs is full scale, it is still possible to get an overload 112 | with DAC overshoot. There are no specifications for detecting this in the 113 | IEC spec but Sony (?) apply a rule that an overload is defined by three 114 | consecutive 0dBFS readings. There are other variations but this one is 115 | fairly straightforward to understand... 116 | 117 | e.g. 118 | 119 | DAC overshoot -------> . ' } Overload 120 | . ' } 121 | dbFS -------------- [ ] [ ] ['] -------------------------------------- 122 | [ ] [ ] [ ]. 123 | '[ ] [ ] [ ] ['] 124 | ['] [ ] [ ] [ ] [ ]' 125 | .[ ] [ ] [ ] [ ] [ ] ['] 126 | ['] [ ] [ ] [ ] [ ] [ ] [ ]'[.] 127 | [.]'[ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ]. 128 | . [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [.] 129 | Mean + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - 130 | [ ] [ ] [ ] [ ] [ ] 131 | ['].[ ] [ ] [ ] [ ] 132 | [.] [ ] [ ] [ ] 133 | '[.] [ ] [ ] 134 | .[ ] [ ] 135 | [ ] [ ] 136 | [.] [ ] 137 | dBFS ---------------------------------------------------------- '[.] ---- 138 | 139 | */ 140 | 141 | #define VIS_BUF_SIZE 16384 // Predefined in Squeezelite. 142 | #define PEAK_METER_LEVELS_MAX 48 // Number of peak meter intervals / LEDs. 143 | #define METER_CHANNELS 2 // Number of metered channels. 144 | #define OVERLOAD_PEAKS 3 // Number of consecutive 0dBFS peaks for overload. 145 | 146 | // Types. -------------------------------------------------------------------- 147 | 148 | struct peak_meter_t 149 | { 150 | uint16_t int_time; // Integration time (ms). 151 | uint16_t samples; // Samples for integration time. 152 | uint16_t hold_time; // Peak hold time (ms). 153 | uint16_t hold_incs; // Hold time counter. 154 | uint16_t fall_time; // Fall time (ms). 155 | uint16_t fall_incs; // Fall time counter. 156 | uint8_t over_peaks; // Number of consecutive 0dBFS samples for overload. 157 | uint16_t over_time; // Overload indicator time (ms). 158 | uint16_t over_incs; // Overload indicator count. 159 | uint8_t num_levels; // Number of display levels 160 | int8_t floor; // Noise floor for meter (dB). 161 | uint16_t reference; // Reference level. 162 | bool overload [METER_CHANNELS]; // Overload flags. 163 | int8_t dBfs [METER_CHANNELS]; // dBfs values. 164 | uint8_t bar_index [METER_CHANNELS]; // Index for bar display. 165 | uint8_t dot_index [METER_CHANNELS]; // Index for dot display (peak hold). 166 | uint32_t elapsed [METER_CHANNELS]; // Elapsed time (us). 167 | int16_t scale [PEAK_METER_LEVELS_MAX]; // Scale intervals. 168 | }; 169 | 170 | 171 | // Functions. ---------------------------------------------------------------- 172 | 173 | // --------------------------------------------------------------------------- 174 | // Checks status of mmap and attempt to open/reopen if not updated recently. 175 | // --------------------------------------------------------------------------- 176 | void vis_check( void ); 177 | 178 | // --------------------------------------------------------------------------- 179 | // Returns the stream bit rate. 180 | // --------------------------------------------------------------------------- 181 | uint32_t vis_get_rate( void ); 182 | 183 | // --------------------------------------------------------------------------- 184 | // Calculates peak dBfs values (L & R) of a number of stream samples. 185 | // --------------------------------------------------------------------------- 186 | void get_dBfs( struct peak_meter_t *peak_meter ); 187 | 188 | // --------------------------------------------------------------------------- 189 | // Calculates the indices for string representations of the peak levels. 190 | // --------------------------------------------------------------------------- 191 | void get_dB_indices( struct peak_meter_t *peak_meter ); 192 | 193 | #endif // #ifndef METERPI_H 194 | -------------------------------------------------------------------------------- /piRotEnc/alsaPi.c: -------------------------------------------------------------------------------- 1 | // **************************************************************************** 2 | /* 3 | alsaPi: 4 | 5 | ALSA based sound driver for the Raspberry Pi. 6 | 7 | Copyright 2015 Darren Faulke 8 | ALSA routines based on amixer, 2000 Jaroslev Kysela. 9 | - see http://www.alsa-project.org. 10 | 11 | This program is free software; you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 2 of the License, or 14 | (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with this program. If not, see . 23 | */ 24 | // **************************************************************************** 25 | 26 | // Compilation: 27 | // 28 | // Compile with gcc -c -fpic alsaPi.c -lasound -lm 29 | // Also use the following flags for Raspberry Pi optimisation: 30 | // -march=armv6 -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp 31 | // -ffast-math -pipe -O3 32 | 33 | #define alsaPiVersion "Version 0.1" 34 | 35 | // Authors: D.Faulke 10/12/2015 36 | // 37 | // Contributors: 38 | // 39 | // Changelog: 40 | // 41 | // v0.1 Original version. 42 | // 43 | 44 | // To Do: 45 | // Add proper muting rather than set volume to 0, and set mute when 0. 46 | // - look at playback switch mechanism. 47 | // Add balance control. 48 | // Add soft limits. 49 | // 50 | 51 | // Installed libraries ------------------------------------------------------- 52 | 53 | #include 54 | #include 55 | #include 56 | 57 | // Local libraries ----------------------------------------------------------- 58 | 59 | #include "alsaPi.h" 60 | 61 | 62 | // Local variables. ---------------------------------------------------------- 63 | 64 | static bool header = false; // Flag to print header on 1st set volume. 65 | 66 | 67 | // Functions. ---------------------------------------------------------------- 68 | 69 | // ---------------------------------------------------------------------------- 70 | // Initialises hardware and returns info in sound struct. 71 | // ---------------------------------------------------------------------------- 72 | int soundOpen( void ) 73 | { 74 | int err; 75 | 76 | // Set up ALSA mixer. 77 | err = snd_mixer_open( &mixerHandle, 0 ); 78 | if ( err < 0 ) 79 | { 80 | printf( "%s.\n", snd_strerror( err )); 81 | return err; 82 | } 83 | err = snd_mixer_attach( mixerHandle, sound.card ); 84 | if ( err < 0 ) 85 | { 86 | printf( "%s.\n", snd_strerror( err )); 87 | return err; 88 | } 89 | err = snd_mixer_load( mixerHandle ); 90 | if ( err < 0 ) 91 | { 92 | printf( "%s.\n", snd_strerror( err )); 93 | return err; 94 | } 95 | err = snd_mixer_selem_register( mixerHandle, NULL, NULL ); 96 | if ( err < 0 ) 97 | { 98 | printf( "%s.\n", snd_strerror( err )); 99 | return err; 100 | } 101 | 102 | snd_mixer_selem_id_alloca( &mixerId ); 103 | snd_mixer_selem_id_set_name( mixerId, sound.mixer ); 104 | 105 | mixerElem = snd_mixer_find_selem( mixerHandle, mixerId ); 106 | if ( mixerElem == NULL ) 107 | { 108 | printf( "Couldn't find mixer" ); 109 | return -1; 110 | } 111 | snd_mixer_selem_get_id( mixerElem, mixerId ); 112 | 113 | // Get hardware volume limits. 114 | long minHard, maxHard; 115 | err = snd_mixer_selem_get_playback_volume_range( mixerElem, 116 | &minHard, &maxHard ); 117 | if ( err < 0 ) 118 | { 119 | printf( "%s.\n", snd_strerror( err )); 120 | return err; 121 | } 122 | 123 | // Calculate soft limits. 124 | long minSoft, maxSoft; 125 | minSoft = sound.min / 100 * ( maxHard - minHard ) + minHard; 126 | maxSoft = sound.max / 100 * ( maxHard - minHard ) + minHard; 127 | 128 | // Set soft limits. 129 | sound.min = minSoft; 130 | sound.max = maxSoft; 131 | sound.range = sound.max - sound.min; 132 | 133 | // Set starting index and volume. 134 | sound.index = lroundf( (float)sound.volume / 100 * sound.incs ); 135 | 136 | return 0; 137 | } 138 | 139 | // ---------------------------------------------------------------------------- 140 | // Calculates volume based on index. Returns value in sound struct. 141 | // ---------------------------------------------------------------------------- 142 | long calcVol( float index, float incs, float range, float min, float factor ) 143 | { 144 | long volume; 145 | 146 | if ( factor == 1 ) // Divide by 0 if used in function. 147 | volume = lroundf(( index / incs * range ) + min ); 148 | else volume = lroundf((( pow( factor, index / incs ) - 1 ) / 149 | ( factor - 1 ) * range + min )); 150 | return volume; 151 | }; 152 | 153 | // ---------------------------------------------------------------------------- 154 | // Set volume using ALSA mixers. 155 | // ---------------------------------------------------------------------------- 156 | int setVol( void ) 157 | { 158 | long linearVol; // Linear volume. Used for debugging. 159 | int err; 160 | 161 | // Calculate volume value from index. 162 | sound.volume = calcVol( sound.index, sound.incs, sound.range, 163 | sound.min, sound.factor ); 164 | 165 | // If control is mono then FRONT_LEFT will set volume. 166 | err=snd_mixer_selem_set_playback_volume( mixerElem, 167 | SND_MIXER_SCHN_FRONT_LEFT, sound.volume ); 168 | if ( err < 0 ) return err; 169 | err=snd_mixer_selem_set_playback_volume( mixerElem, 170 | SND_MIXER_SCHN_FRONT_RIGHT, sound.volume ); 171 | if ( err < 0 ) return err; 172 | 173 | if ( sound.print ) // Print output if requested. For debugging. 174 | { 175 | linearVol = calcVol( sound.index, sound.incs, sound.range, 176 | sound.min, 1 ); 177 | 178 | if ( header == false ) // Print out header block. 179 | { 180 | printf( "\n" ); 181 | printf( "\t+-----------+-----------------+-----------------+\n" ); 182 | printf( "\t| indices | Linear Volume | Mapped Volume |\n" ); 183 | printf( "\t+-----+-----+--------+--------+--------+--------+\n" ); 184 | printf( "\t| L | R | L | R | L | R |\n" ); 185 | printf( "\t+-----+-----+--------+--------+--------+--------+\n" ); 186 | 187 | header = true; 188 | } 189 | if ( err < 0 ) 190 | printf( "\t| %-45s |\n", snd_strerror( err )); 191 | else 192 | printf( "\t| %3i | %3i | %6ld | %6ld | %6d | %6d |\n", 193 | sound.index, sound.index, 194 | linearVol, linearVol, 195 | sound.volume, sound.volume ); 196 | } 197 | 198 | return 0; 199 | }; 200 | 201 | // ---------------------------------------------------------------------------- 202 | // Increases volume. 203 | // ---------------------------------------------------------------------------- 204 | void incVol( void ) 205 | { 206 | // Ensure not at limit. 207 | if ( sound.index >= sound.incs ) sound.index = sound.incs; 208 | // Increment index. 209 | else sound.index++; 210 | 211 | // Set volume. 212 | setVol(); 213 | 214 | return; 215 | }; 216 | 217 | // ---------------------------------------------------------------------------- 218 | // Increases volume. 219 | // ---------------------------------------------------------------------------- 220 | void decVol( void ) 221 | { 222 | // Ensure not at limit. 223 | if ( sound.index <= 0 ) sound.index = 0; 224 | // Deccrement index. 225 | else sound.index--; 226 | 227 | // Set volume. 228 | setVol(); 229 | 230 | return; 231 | }; 232 | 233 | // ---------------------------------------------------------------------------- 234 | // Detaches and closes ALSA. 235 | // ---------------------------------------------------------------------------- 236 | void soundClose( void ) 237 | { 238 | snd_mixer_detach( mixerHandle, sound.card ); 239 | snd_mixer_close( mixerHandle ); 240 | 241 | return; 242 | }; 243 | 244 | -------------------------------------------------------------------------------- /piRotEnc/alsaPi.h: -------------------------------------------------------------------------------- 1 | // **************************************************************************** 2 | /* 3 | alsaPi: 4 | 5 | ALSA based sound driver for the Raspberry Pi. 6 | 7 | Copyright 2015 Darren Faulke 8 | ALSA routines based on amixer, 2000 Jaroslev Kysela. 9 | - see http://www.alsa-project.org. 10 | 11 | This program is free software; you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 2 of the License, or 14 | (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with this program. If not, see . 23 | */ 24 | // **************************************************************************** 25 | 26 | // Authors: D.Faulke 10/12/2015 27 | // 28 | // Contributors: 29 | // 30 | // Changelog: 31 | // 32 | // v0.1 Original version. 33 | // 34 | 35 | // To Do: 36 | // Add proper muting rather than set volume to 0, and set mute when 0. 37 | // - look at playback switch mechanism. 38 | // Add balance control. 39 | // Add soft limits. 40 | // 41 | 42 | #ifndef ALSAPI_H 43 | #define ALSAPI_H 44 | 45 | //#include 46 | //#include 47 | //#include 48 | //#include 49 | //#include 50 | //#include 51 | //#include 52 | //#include 53 | 54 | 55 | // Data structures. ---------------------------------------------------------- 56 | 57 | struct soundStruct 58 | { 59 | char *card; // ALSA card ID. 60 | char *mixer; // ALSA mixer ID. 61 | float factor; // Volume mapping factor. 62 | unsigned char index; // Relative index for volume level. 63 | unsigned char incs; // Number of increments over volume range. 64 | int min; // Minimum volume (hardware dependent). 65 | int max; // Maximum volume (hardware dependent). 66 | int range; // Volume range (hardware dependent). 67 | int volume; // Volume level. 68 | char balance; // Relative balance -100(%) to +100(%). 69 | bool mute; // Mute switch. 70 | bool print; // Print output switch. 71 | } sound; 72 | 73 | 74 | // ALSA control types. ------------------------------------------------------- 75 | 76 | snd_ctl_t *ctlHandle; // Simple control handle. 77 | snd_ctl_elem_id_t *ctlId; // Simple control element id. 78 | snd_ctl_elem_value_t *ctlControl; // Simple control element value. 79 | snd_ctl_elem_type_t ctlType; // Simple control element type. 80 | snd_ctl_elem_info_t *ctlInfo; // Simple control element info container. 81 | snd_ctl_card_info_t *ctlCard; // Simple control card info container. 82 | 83 | 84 | // ALSA mixer types. ---------------------------------------------------------- 85 | 86 | snd_mixer_t *mixerHandle; // Mixer handle. 87 | snd_mixer_selem_id_t *mixerId; // Mixer simple element identifier. 88 | snd_mixer_elem_t *mixerElem; // Mixer element handle. 89 | 90 | 91 | // Functions. ---------------------------------------------------------------- 92 | 93 | // ---------------------------------------------------------------------------- 94 | // Initialises hardware and returns info in sound struct. 95 | // ---------------------------------------------------------------------------- 96 | int soundOpen( void ); 97 | 98 | // ---------------------------------------------------------------------------- 99 | // Calculates volume based on index. Returns value in soundStruct. 100 | // ---------------------------------------------------------------------------- 101 | /* 102 | linear volume = ratio * range + min. 103 | mapped volume = ( factor^ratio - 1 ) / ( factor - 1 ) * range + min. 104 | ratio = index / incs. 105 | 106 | factor < 1, logarithmic. 107 | factor = 1, linear. 108 | factor > 1, exponential. 109 | */ 110 | long calcVol( float index, float incs, float range, float min, float factor ); 111 | 112 | // ---------------------------------------------------------------------------- 113 | // Set volume using ALSA mixers. 114 | // ---------------------------------------------------------------------------- 115 | int setVol( void ); 116 | 117 | // ---------------------------------------------------------------------------- 118 | // Increases volume. 119 | // ---------------------------------------------------------------------------- 120 | void incVol( void ); 121 | 122 | // ---------------------------------------------------------------------------- 123 | // Increases volume. 124 | // ---------------------------------------------------------------------------- 125 | void decVol( void ); 126 | 127 | // ---------------------------------------------------------------------------- 128 | // Detaches and closes ALSA. 129 | // ---------------------------------------------------------------------------- 130 | void soundClose( void ); 131 | 132 | #endif 133 | -------------------------------------------------------------------------------- /piRotEnc/rotencPi.h: -------------------------------------------------------------------------------- 1 | /* 2 | // =========================================================================== 3 | 4 | rotencPi: 5 | 6 | Rotary encoder driver for the Raspberry Pi. 7 | 8 | Copyright 2015 Darren Faulke 9 | 10 | Based on state machine algorithm by Michael Kellet. 11 | -see www.mkesc.co.uk/ise.pdf 12 | 13 | This program is free software; you can redistribute it and/or modify 14 | it under the terms of the GNU General Public License as published by 15 | the Free Software Foundation, either version 2 of the License, or 16 | (at your option) any later version. 17 | 18 | This program is distributed in the hope that it will be useful, 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | GNU General Public License for more details. 22 | 23 | You should have received a copy of the GNU General Public License 24 | along with this program. If not, see . 25 | 26 | // =========================================================================== 27 | 28 | Authors: D.Faulke 12/12/2015 29 | 30 | Contributors: 31 | 32 | Testers: D.Stivens 33 | 34 | Changelog: 35 | 36 | v0.1 Original version. 37 | v0.2 Converted to libraries. 38 | 39 | To Do: 40 | 41 | Write GPIO and interrupt routines to replace wiringPi. 42 | Improve response by splitting interrupts. 43 | 44 | 45 | // Description of rotary encoder function. ----------------------------------- 46 | 47 | Quadrature encoding: 48 | +---------------------------+ 49 | : : : : : : : : : | | old | new | | 50 | : +-------+ : +-------+ : | dir |-------+-------| hex | 51 | : | : | : | : | : | | a | b | A | B | | 52 | a,A : | : | : | : | : |-----+---+---+---+---+-----| 53 | --------+ : +-------+ : +------- | +ve | 0 | 0 | 1 | 0 | 0x2 | 54 | : : : : : : : : : | | 1 | 0 | 1 | 1 | 0xb | 55 | : : : : : : : : : | | 1 | 1 | 0 | 1 | 0xd | 56 | +-------+ : +-------+ : +--- | | 0 | 1 | 0 | 0 | 0x4 | 57 | | : | : | : | : | |-----+---+---+---+---+-----| 58 | b,B | : | : | : | : | | -ve | 1 | 1 | 1 | 0 | 0xe | 59 | ----+ : +-------+ : +-------+ | | 1 | 0 | 0 | 0 | 0x8 | 60 | : : : : : : : : : | | 0 | 0 | 0 | 1 | 0x1 | 61 | 1 : 2 : 3 : 4 : 1 : 2 : 3 : 4 : 1 : 2 | | 0 | 1 | 1 | 1 | 0x7 | 62 | : : : : : : : : : +---------------------------+ 63 | 64 | A & B are current readings and a & b are the previous readings. 65 | dec is the decimal equivalent of nibble abAB. 66 | 67 | // --------------------------------------------------------------------------- 68 | 69 | The most direct method is to set an interrupt on the rising edfe of pin A 70 | and measure B. If B is high then the direction is +ve, otherwise -ve. 71 | 72 | SIMPLE_1 - Interrupt on leading edge of A. Sample B (1x resolution). 73 | 74 | Works surprisingly well with mechanical encoders with a small delay after 75 | reading the encoder direction. 76 | 77 | // --------------------------------------------------------------------------- 78 | 79 | There are a variety of other ways to decode the information but a simple 80 | state machine method by Michael Kellet, http://www.mkesc.co.uk/ise.pdf, 81 | is efficient and provides 2 modes. 82 | 83 | SIMPLE_2 - Interrupt on both edges of A. Read A & B (2x resolution). 84 | SIMPLE_4 - Interrupt on both edges of A and B. Read A & B, (4x). 85 | 86 | The state table contains directions for all possible combinations of abAB. 87 | 88 | +-----------------------------------------------------------+ 89 | | abAB(hex) | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9| a| b| c| d| e| f| 90 | |-----------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| 91 | | direction | 0|-1|+1| 0|+1| 0| 0|-1|-1| 0| 0|+1| 0|+1|-1| 0| 92 | +-----------------------------------------------------------+ 93 | 94 | Can be a bit jumpy with mechanical encoders due to contact bounce. 95 | 96 | // --------------------------------------------------------------------------- 97 | 98 | An alternative method using a state transition table that helps with 99 | noisy encoders by ignoring invalid transitions between states has been 100 | offered by Ben Buxton, http://ww.buxtronix.net, and offers 2 modes with 101 | different resolutions. Both require reads of A & B. 102 | 103 | HALF - Outputs direction after half and full steps (2x resolution). 104 | FULL - Outputs direction after full step only (1x resolution). 105 | 106 | Each row is a state. Each cell in that row contains the new state to set 107 | based on the encoder output, AB. The direction is determined when the 108 | state reaches 0x10 (+ve) or 0x20 (-ve). 109 | 110 | Half mode transition table - outputs direction after half and full steps. 111 | 112 | +---------------------------------+ 113 | | | Encoder output AB | 114 | | Transitions |-------------------| 115 | | | 00 | 01 | 10 | 11 | 116 | |-------------+----+----+----+----| 117 | ->| Start | 03 | 02 | 01 | 00 | 118 | | -ve begin | 23 | 00 | 01 | 00 | 119 | | +ve begin | 13 | 02 | 00 | 00 | 120 | | Halfway | 03 | 05 | 04 | 00 | 121 | | +ve begin | 03 | 03 | 04 | 10 |-> +ve 122 | | -ve begin | 03 | 05 | 03 | 20 |-> -ve 123 | +---------------------------------+ 124 | 125 | Full mode transition table - outputs direction after full step only. 126 | 127 | +---------------------------------+ 128 | | | Encoder output AB | 129 | | Transitions |-------------------| 130 | | | 00 | 01 | 10 | 11 | 131 | |-------------+----+----+----+----| 132 | ->| Start | 00 | 02 | 04 | 00 | 133 | | +ve end | 03 | 00 | 01 | 10 |-> +ve 134 | | +ve begin | 03 | 02 | 00 | 00 | 135 | | +ve next | 03 | 02 | 01 | 00 | 136 | | -ve begin | 06 | 00 | 04 | 00 | 137 | | -ve end | 06 | 05 | 00 | 20 |-> -ve 138 | | -ve next | 06 | 05 | 04 | 00 | 139 | +---------------------------------+ 140 | 141 | */ 142 | 143 | // Macros -------------------------------------------------------------------- 144 | 145 | #ifndef ROTENCPI_H 146 | #define ROTENCPI_H 147 | 148 | // Simple state table. 149 | #define SIMPLE_TABLE_COLS 16 150 | #define SIMPLE_TABLE { 0,-1, 1, 0, 1, 0, 0,-1,-1, 0, 0, 1, 0, 1,-1, 0 } 151 | 152 | // Half step transition table. 153 | #define HALF_TABLE_ROWS 6 154 | #define HALF_TABLE_COLS 4 155 | #define HALF_TABLE {{ 0x03, 0x02, 0x01, 0x00 },\ 156 | { 0x23, 0x00, 0x01, 0x00 },\ 157 | { 0x13, 0x02, 0x00, 0x00 },\ 158 | { 0x03, 0x05, 0x04, 0x00 },\ 159 | { 0x03, 0x03, 0x04, 0x10 },\ 160 | { 0x03, 0x05, 0x03, 0x20 }} 161 | 162 | // Full step transition table. 163 | #define FULL_TABLE_ROWS 7 164 | #define FULL_TABLE_COLS 4 165 | #define FULL_TABLE {{ 0x00, 0x02, 0x04, 0x00 },\ 166 | { 0x03, 0x00, 0x01, 0x10 },\ 167 | { 0x03, 0x02, 0x00, 0x00 },\ 168 | { 0x03, 0x02, 0x01, 0x00 },\ 169 | { 0x06, 0x00, 0x04, 0x00 },\ 170 | { 0x06, 0x05, 0x00, 0x20 },\ 171 | { 0x06, 0x05, 0x04, 0x00 }} 172 | 173 | 174 | // Data structures ----------------------------------------------------------- 175 | 176 | volatile int8_t encoderDirection; // Encoder direction. 177 | //volatile int8_t encoderState; // Encoder state, abAB. 178 | volatile int8_t buttonState; // Button state, on or off. 179 | 180 | // Decoder methods. See description of encoder functions below. 181 | enum decode_t { SIMPLE_1, SIMPLE_2, SIMPLE_4, HALF, FULL }; 182 | 183 | struct encoderStruct 184 | { 185 | uint8_t gpioA; // GPIO for encoder pin A. 186 | uint8_t gpioB; // GPIO for encoder pin B. 187 | uint16_t delay; // Sensitivity delay (uS). 188 | enum decode_t mode; // Simple, half or full quadrature. 189 | } encoder; 190 | 191 | struct buttonStruct 192 | { 193 | uint8_t gpio; // GPIO for button pin. 194 | } button; 195 | 196 | /* 197 | Functions to set direction in encoderDirection variable: 198 | encoderDirection = +1: +ve direction. 199 | = 0: no change determined. 200 | = -1: -ve direction. 201 | */ 202 | // --------------------------------------------------------------------------- 203 | // Sets direction in encoderDirection according to state of pin B. 204 | // --------------------------------------------------------------------------- 205 | void setDirectionSimple( void ); 206 | 207 | // --------------------------------------------------------------------------- 208 | // Sets direction in encoderDirection using SIMPLE_TABLE. 209 | // --------------------------------------------------------------------------- 210 | void setDirectionTable( void ); 211 | 212 | // --------------------------------------------------------------------------- 213 | // Sets direction in encoderDirection using HALF_TABLE. 214 | // --------------------------------------------------------------------------- 215 | void setDirectionHalf( void ); 216 | 217 | // --------------------------------------------------------------------------- 218 | // Sets direction in encoderDirection using FULL_TABLE. 219 | // --------------------------------------------------------------------------- 220 | void setDirectionFull( void ); 221 | 222 | // --------------------------------------------------------------------------- 223 | // Returns button state in buttonState. Call by interrupt on GPIO. 224 | // --------------------------------------------------------------------------- 225 | void setButtonState( void ); 226 | 227 | // --------------------------------------------------------------------------- 228 | // Initialises encoder and button GPIOs. 229 | // --------------------------------------------------------------------------- 230 | /* 231 | Send 0xFF for button if no GPIO present. 232 | */ 233 | void encoderInit( uint8_t encoderA, uint8_t encoderB, uint8_t button ); 234 | 235 | #endif 236 | -------------------------------------------------------------------------------- /popcornPi/popcornPi.c: -------------------------------------------------------------------------------- 1 | // **************************************************************************** 2 | // **************************************************************************** 3 | /* 4 | piCorn: 5 | 6 | A driver for the Popcorn C200 display, which is an Orient Display AMG19264 7 | LCD connected via a MAX7325 port expander and incorporating a TI LM27966 8 | backlight control. I2C slave address is either 0x50 or 0x60 according to 9 | the MAX7325 data sheet but i2cdetect gives 0x5d and 0x6d. 10 | Slave address of the LM27966 is 0x36 but this is not detected by i2cdetect. 11 | 12 | Copyright 2015 Darren Faulke 13 | Based on the following guides and codes: 14 | AMG19264C data sheet, 15 | LM27966 data sheet. 16 | 17 | This program is free software; you can redistribute it and/or modify 18 | it under the terms of the GNU General Public License as published by 19 | the Free Software Foundation, either version 2 of the License, or 20 | (at your option) any later version. 21 | 22 | This program is distributed in the hope that it will be useful, 23 | but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | GNU General Public License for more details. 26 | 27 | You should have received a copy of the GNU General Public License 28 | along with this program. If not, see . 29 | */ 30 | // **************************************************************************** 31 | // **************************************************************************** 32 | 33 | #define Version "Version 0.1" 34 | 35 | // Compilation: 36 | // 37 | // Compile with gcc piCorn.c -o piCorn -lwiringPi 38 | // Also use the following flags for Raspberry Pi optimisation: 39 | // -march=armv6 -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp 40 | // -ffast-math -pipe -O3 41 | 42 | // Authors: D.Faulke 02/12/2015 This program. 43 | // 44 | // Contributors: 45 | // 46 | // Changelog: 47 | // 48 | // v0.1 Original version. 49 | // 50 | 51 | // To Do: 52 | // Get it to work with the MAX7325 I2C expander. 53 | // 54 | 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | 65 | // ============================================================================ 66 | // Information. 67 | // ============================================================================ 68 | /* 69 | Pin layout for Orient Display AMG19264 based 192x64 LCD. 70 | 71 | +-----+-------+------+---------------------------------------+ 72 | | Pin | Label | Pi | Description | 73 | +-----+-------+------+---------------------------------------+ 74 | | 1 | Vss | GND | Ground (0V) for logic. | 75 | | 2 | Vdd | 5V | 5V supply for logic. | 76 | | 3 | Vo | +V | Variable V for contrast. | 77 | | 4 | Vee | -V | Voltage output. | 78 | | 5 | RS | GPIO | Register Select. 0: command, 1: data. | 79 | | 6 | RW | GND | R/W. 0: write, 1: read. *Caution* | 80 | | 7 | E | GPIO | Enable bit. | 81 | | 8 | DB0 | GPIO | Data bit 0. | 82 | | 9 | DB1 | GPIO | Data bit 1. | 83 | | 10 | DB2 | GPIO | Data bit 2. | 84 | | 11 | DB3 | GPIO | Data bit 3. | 85 | | 12 | DB4 | GPIO | Data bit 4. | 86 | | 13 | DB5 | GPIO | Data bit 5. | 87 | | 14 | DB6 | GPIO | Data bit 6. | 88 | | 15 | DB7 | GPIO | Data bit 7. | 89 | | 16 | CS3 | GPIO | Chip select (left). | 90 | | 17 | CS2 | GPIO | Chip select (middle). | 91 | | 18 | CS1 | GPIO | Chip select (right). | 92 | | 19 | RST | | Reset signal. | 93 | | 20 | BLA | +V | Voltage for backlight (max 5V). | 94 | | 21 | BLK | GND | Ground (0V) for backlight. | 95 | +-----+-------+------+---------------------------------------+ 96 | 97 | Note: Most displays are combinations of up to 3 64x64 modules, each 98 | controlled via the CSx (chip select) registers. 99 | Pages may refer to virtual screens. 100 | Note: Setting pin 6 (R/W) to 1 (read) while connected to a GPIO 101 | will likely damage the Pi unless V is reduced or grounded. 102 | 103 | LCD register bits: 104 | +---+---+---+---+---+---+---+---+---+---+ +---+---------------+ 105 | |RS |RW |DB7|DB6|DB5|DB4|DB3|DB2|DB1|DB0| |Key|Effect | 106 | +---+---+---+---+---+---+---+---+---+---+ +---+---------------+ 107 | | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | D | | D |Display on/off.| 108 | | 0 | 0 | 0 | 1 | : Y address (0-63) | | B |Busy status. | 109 | | 0 | 0 | 1 | 0 | 1 | 1 | 1 |Page (0-7) | | D |Display status.| 110 | | 0 | 0 | 1 | 1 | X address (0-63) | | R |Reset status. | 111 | | 0 | 1 | B | 1 | D | R | 0 | 0 | 0 | 0 | +---+---------------+ 112 | | 1 | 0 | : : Write Data: : : | 113 | | 1 | 1 | : : Read Data : : : | 114 | +---+---+---+---+---+---+---+---+---+---+ 115 | 116 | --------------------------------------------------------------------------- 117 | 118 | LM27966 information: 119 | 120 | Chip address = 0x36. 121 | 122 | +------+------+------+------+------+------+------+------+ 123 | | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 124 | +------+------+------+------+------+------+------+------+ 125 | | ADR6 | ADR5 | ADR4 | ADR3 | ADR2 | ADR1 | ADR0 | R/W | 126 | +------+------+------+------+------+------+------+------+ 127 | 128 | Internal registers: 129 | 130 | General purpose register address = 0x10. 131 | 132 | +--------+--------+--------+--------+--------+--------+--------+--------+ 133 | | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 134 | +--------+--------+--------+--------+--------+--------+--------+--------+ 135 | | 0 | 0 | 1 | T1 | EN-D5 | EN-AUX | T0 |EN-MAIN | 136 | +--------+--------+--------+--------+--------+--------+--------+--------+ 137 | 138 | EN-MAIN : Enables Dx LED drivers (main display). 139 | T0 : Must be set to 0. 140 | EN-AUX : Enables Daux LED driver (indicator lighting). 141 | EN-D5 : Enables D5 LED voltage sense. 142 | T1 : Must be set to 0. 143 | 144 | Main display brightness control register address = 0xa0. 145 | 146 | +------+------+------+------+------+------+------+------+ 147 | | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 148 | +------+------+------+------+------+------+------+------+ 149 | | 1 | 1 | 1 | Dx4 | Dx3 | Dx2 | Dx1 | Dx0 | 150 | +------+------+------+------+------+------+------+------+ 151 | 152 | Aux LED brightness control register address = 0xc0. 153 | 154 | +------+------+------+------+------+------+------+------+ 155 | | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 156 | +------+------+------+------+------+------+------+------+ 157 | | 1 | 1 | 1 | 1 | 1 | 1 |DAUX1 |DAUX0 | 158 | +------+------+------+------+------+------+------+------+ 159 | 160 | Dx4 - Dx0 : Sets brightness for Dx pins (main display). 161 | DAUX1-DAUX0 : Sets brightness for Daux pin. 162 | 163 | Brightness code = 0x00 - 0x1f (1.25% - 100% brightness) for main display. 164 | Brightness code = 0x0 - 0x3 (20%, 40%, 70%, 100% brightness). 165 | 166 | --------------------------------------------------------------------------- 167 | 168 | 169 | 170 | */ 171 | // ============================================================================ 172 | // Command and constant macros. 173 | // ============================================================================ 174 | 175 | // I2C addresses. 176 | #define MAX7325_ADDR1 0x5d // I2C address for port expander. 177 | #define MAX7325_ADDR2 0x6d // I2C address for port expander. 178 | #define LM27966_ADDR 0x36 // I2C address for backlight control. 179 | 180 | // These should be replaced by command line options. 181 | #define DISPLAY_PMAX 8 // Max No of LCD pages. 182 | #define DISPLAY_XMAX 64 // Max No of LCD display rows. 183 | #define DISPLAY_YMAX 64 // Max No of LCD display columns. 184 | #define DISPLAY_NUM 1 // Number of displays. 185 | 186 | // Display commands. 187 | #define DISPLAY_ON 0x3f // Turn display on. 188 | #define DISPLAY_OFF 0x3e // Turn display off. 189 | 190 | // LCD addresses. 191 | #define BASE_PADDR 0xb8 // Base address for pages 0-7. 192 | #define BASE_XADDR 0x40 // Base address for X position. 193 | #define BASE_YADDR 0xc0 // Base address for Y position. 194 | 195 | // Constants for GPIO states. 196 | #define GPIO_UNSET 0 // Set GPIO to low. 197 | #define GPIO_SET 1 // Set GPIO to high. 198 | 199 | // Define a mutex to allow concurrent display routines. 200 | /* 201 | Mutex needs to lock before any cursor positioning or write functions. 202 | */ 203 | pthread_mutex_t displayBusy; 204 | 205 | // ============================================================================ 206 | // Data structures. 207 | // ============================================================================ 208 | 209 | 210 | // ============================================================================ 211 | // Main section. 212 | // ============================================================================ 213 | void main( void ) 214 | { 215 | 216 | // ------------------------------------------------------------------------ 217 | // Initialise I2C. 218 | // ------------------------------------------------------------------------ 219 | int displayHandle1 = wiringPiI2CSetup( MAX7325_ADDR1 ); 220 | int displayHandle2 = wiringPiI2CSetup( MAX7325_ADDR2 ); 221 | int backlightHandle = wiringPiI2CSetup( LM27966_ADDR ); 222 | 223 | printf( "Display handles are %d & %d.\n", displayHandle1, displayHandle2 ); 224 | printf( "Backlight handle is %d.\n", backlightHandle ); 225 | 226 | } 227 | -------------------------------------------------------------------------------- /rotencPi/rotencPi.h: -------------------------------------------------------------------------------- 1 | /* 2 | // =========================================================================== 3 | 4 | rotencPi: 5 | 6 | Rotary encoder driver for the Raspberry Pi. 7 | 8 | Copyright 2015 Darren Faulke 9 | 10 | Based on state machine algorithm by Michael Kellet. 11 | -see www.mkesc.co.uk/ise.pdf 12 | 13 | This program is free software; you can redistribute it and/or modify 14 | it under the terms of the GNU General Public License as published by 15 | the Free Software Foundation, either version 2 of the License, or 16 | (at your option) any later version. 17 | 18 | This program is distributed in the hope that it will be useful, 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | GNU General Public License for more details. 22 | 23 | You should have received a copy of the GNU General Public License 24 | along with this program. If not, see . 25 | 26 | // =========================================================================== 27 | 28 | Authors: D.Faulke 12/12/2015 29 | 30 | Contributors: 31 | 32 | Testers: D.Stivens 33 | 34 | Changelog: 35 | 36 | v0.1 Original version. 37 | v0.2 Converted to libraries. 38 | 39 | To Do: 40 | 41 | Write GPIO and interrupt routines to replace wiringPi. 42 | Improve response by splitting interrupts. 43 | 44 | 45 | // Description of rotary encoder function. ----------------------------------- 46 | 47 | Quadrature encoding: 48 | +---------------------------+ 49 | : : : : : : : : : | | old | new | | 50 | : +-------+ : +-------+ : | dir |-------+-------| hex | 51 | : | : | : | : | : | | a | b | A | B | | 52 | a,A : | : | : | : | : |-----+---+---+---+---+-----| 53 | --------+ : +-------+ : +------- | +ve | 0 | 0 | 1 | 0 | 0x2 | 54 | : : : : : : : : : | | 1 | 0 | 1 | 1 | 0xb | 55 | : : : : : : : : : | | 1 | 1 | 0 | 1 | 0xd | 56 | +-------+ : +-------+ : +--- | | 0 | 1 | 0 | 0 | 0x4 | 57 | | : | : | : | : | |-----+---+---+---+---+-----| 58 | b,B | : | : | : | : | | -ve | 1 | 1 | 1 | 0 | 0xe | 59 | ----+ : +-------+ : +-------+ | | 1 | 0 | 0 | 0 | 0x8 | 60 | : : : : : : : : : | | 0 | 0 | 0 | 1 | 0x1 | 61 | 1 : 2 : 3 : 4 : 1 : 2 : 3 : 4 : 1 : 2 | | 0 | 1 | 1 | 1 | 0x7 | 62 | : : : : : : : : : +---------------------------+ 63 | 64 | A & B are current readings and a & b are the previous readings. 65 | dec is the decimal equivalent of nibble abAB. 66 | 67 | // --------------------------------------------------------------------------- 68 | 69 | The most direct method is to set an interrupt on the rising edfe of pin A 70 | and measure B. If B is high then the direction is +ve, otherwise -ve. 71 | 72 | SIMPLE_1 - Interrupt on leading edge of A. Sample B (1x resolution). 73 | 74 | Works surprisingly well with mechanical encoders with a small delay after 75 | reading the encoder direction. 76 | 77 | // --------------------------------------------------------------------------- 78 | 79 | There are a variety of other ways to decode the information but a simple 80 | state machine method by Michael Kellet, http://www.mkesc.co.uk/ise.pdf, 81 | is efficient and provides 2 modes. 82 | 83 | SIMPLE_2 - Interrupt on both edges of A. Read A & B (2x resolution). 84 | SIMPLE_4 - Interrupt on both edges of A and B. Read A & B, (4x). 85 | 86 | The state table contains directions for all possible combinations of abAB. 87 | 88 | +-----------------------------------------------------------+ 89 | | abAB(hex) | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9| a| b| c| d| e| f| 90 | |-----------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| 91 | | direction | 0|-1|+1| 0|+1| 0| 0|-1|-1| 0| 0|+1| 0|+1|-1| 0| 92 | +-----------------------------------------------------------+ 93 | 94 | Can be a bit jumpy with mechanical encoders due to contact bounce. 95 | 96 | // --------------------------------------------------------------------------- 97 | 98 | An alternative method using a state transition table that helps with 99 | noisy encoders by ignoring invalid transitions between states has been 100 | offered by Ben Buxton, http://ww.buxtronix.net, and offers 2 modes with 101 | different resolutions. Both require reads of A & B. 102 | 103 | HALF - Outputs direction after half and full steps (2x resolution). 104 | FULL - Outputs direction after full step only (1x resolution). 105 | 106 | Each row is a state. Each cell in that row contains the new state to set 107 | based on the encoder output, AB. The direction is determined when the 108 | state reaches 0x10 (+ve) or 0x20 (-ve). 109 | 110 | Half mode transition table - outputs direction after half and full steps. 111 | 112 | +---------------------------------+ 113 | | | Encoder output AB | 114 | | Transitions |-------------------| 115 | | | 00 | 01 | 10 | 11 | 116 | |-------------+----+----+----+----| 117 | ->| Start | 03 | 02 | 01 | 00 | 118 | | -ve begin | 23 | 00 | 01 | 00 | 119 | | +ve begin | 13 | 02 | 00 | 00 | 120 | | Halfway | 03 | 05 | 04 | 00 | 121 | | +ve begin | 03 | 03 | 04 | 10 |-> +ve 122 | | -ve begin | 03 | 05 | 03 | 20 |-> -ve 123 | +---------------------------------+ 124 | 125 | Full mode transition table - outputs direction after full step only. 126 | 127 | +---------------------------------+ 128 | | | Encoder output AB | 129 | | Transitions |-------------------| 130 | | | 00 | 01 | 10 | 11 | 131 | |-------------+----+----+----+----| 132 | ->| Start | 00 | 02 | 04 | 00 | 133 | | +ve end | 03 | 00 | 01 | 10 |-> +ve 134 | | +ve begin | 03 | 02 | 00 | 00 | 135 | | +ve next | 03 | 02 | 01 | 00 | 136 | | -ve begin | 06 | 00 | 04 | 00 | 137 | | -ve end | 06 | 05 | 00 | 20 |-> -ve 138 | | -ve next | 06 | 05 | 04 | 00 | 139 | +---------------------------------+ 140 | 141 | */ 142 | 143 | // Macros -------------------------------------------------------------------- 144 | 145 | #ifndef ROTENCPI_H 146 | #define ROTENCPI_H 147 | 148 | // Simple state table. 149 | #define SIMPLE_TABLE_COLS 16 150 | #define SIMPLE_TABLE { 0,-1, 1, 0, 1, 0, 0,-1,-1, 0, 0, 1, 0, 1,-1, 0 } 151 | 152 | // Half step transition table. 153 | #define HALF_TABLE_ROWS 6 154 | #define HALF_TABLE_COLS 4 155 | #define HALF_TABLE {{ 0x03, 0x02, 0x01, 0x00 },\ 156 | { 0x23, 0x00, 0x01, 0x00 },\ 157 | { 0x13, 0x02, 0x00, 0x00 },\ 158 | { 0x03, 0x05, 0x04, 0x00 },\ 159 | { 0x03, 0x03, 0x04, 0x10 },\ 160 | { 0x03, 0x05, 0x03, 0x20 }} 161 | 162 | // Full step transition table. 163 | #define FULL_TABLE_ROWS 7 164 | #define FULL_TABLE_COLS 4 165 | #define FULL_TABLE {{ 0x00, 0x02, 0x04, 0x00 },\ 166 | { 0x03, 0x00, 0x01, 0x10 },\ 167 | { 0x03, 0x02, 0x00, 0x00 },\ 168 | { 0x03, 0x02, 0x01, 0x00 },\ 169 | { 0x06, 0x00, 0x04, 0x00 },\ 170 | { 0x06, 0x05, 0x00, 0x20 },\ 171 | { 0x06, 0x05, 0x04, 0x00 }} 172 | 173 | 174 | // Data structures ----------------------------------------------------------- 175 | 176 | volatile int8_t encoderDirection; // Encoder direction. 177 | //volatile int8_t encoderState; // Encoder state, abAB. 178 | volatile int8_t buttonState; // Button state, on or off. 179 | 180 | // Decoder methods. See description of encoder functions below. 181 | enum decode_t { SIMPLE_1, SIMPLE_2, SIMPLE_4, HALF, FULL }; 182 | 183 | struct encoderStruct 184 | { 185 | uint8_t gpioA; // GPIO for encoder pin A. 186 | uint8_t gpioB; // GPIO for encoder pin B. 187 | uint16_t delay; // Sensitivity delay (uS). 188 | enum decode_t mode; // Simple, half or full quadrature. 189 | } encoder; 190 | 191 | struct buttonStruct 192 | { 193 | uint8_t gpio; // GPIO for button pin. 194 | } button; 195 | 196 | /* 197 | Functions to set direction in encoderDirection variable: 198 | encoderDirection = +1: +ve direction. 199 | = 0: no change determined. 200 | = -1: -ve direction. 201 | */ 202 | // --------------------------------------------------------------------------- 203 | // Sets direction in encoderDirection according to state of pin B. 204 | // --------------------------------------------------------------------------- 205 | void setDirectionSimple( void ); 206 | 207 | // --------------------------------------------------------------------------- 208 | // Sets direction in encoderDirection using SIMPLE_TABLE. 209 | // --------------------------------------------------------------------------- 210 | void setDirectionTable( void ); 211 | 212 | // --------------------------------------------------------------------------- 213 | // Sets direction in encoderDirection using HALF_TABLE. 214 | // --------------------------------------------------------------------------- 215 | void setDirectionHalf( void ); 216 | 217 | // --------------------------------------------------------------------------- 218 | // Sets direction in encoderDirection using FULL_TABLE. 219 | // --------------------------------------------------------------------------- 220 | void setDirectionFull( void ); 221 | 222 | // --------------------------------------------------------------------------- 223 | // Returns button state in buttonState. Call by interrupt on GPIO. 224 | // --------------------------------------------------------------------------- 225 | void setButtonState( void ); 226 | 227 | // --------------------------------------------------------------------------- 228 | // Initialises encoder and button GPIOs. 229 | // --------------------------------------------------------------------------- 230 | /* 231 | Send 0xFF for button if no GPIO present. 232 | */ 233 | void encoderInit( uint8_t encoderA, uint8_t encoderB, uint8_t button ); 234 | 235 | #endif 236 | -------------------------------------------------------------------------------- /rotencPi/testrotencPi.c: -------------------------------------------------------------------------------- 1 | /* 2 | // =========================================================================== 3 | 4 | testrotencPi: 5 | 6 | Test app for rotary encoder driver for the Raspberry Pi. 7 | 8 | Copyright 2015 Darren Faulke 9 | 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program. If not, see . 22 | 23 | // =========================================================================== 24 | 25 | Compilation: 26 | 27 | gcc testrotencPi.c rotencPi.c -Wall -o testrotencPi 28 | -lwiringPi -lpthread 29 | 30 | Also use the following flags for Raspberry Pi optimisation: 31 | 32 | -march=armv6 -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp 33 | -ffast-math -pipe -O3 34 | 35 | // --------------------------------------------------------------------------- 36 | 37 | Authors: D.Faulke 11/12/2015 38 | 39 | // --------------------------------------------------------------------------- 40 | */ 41 | 42 | 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #include "rotencPi.h" 50 | 51 | // Main section. ------------------------------------------------------------- 52 | 53 | int main( void ) 54 | { 55 | // Initialise encoder and function button. 56 | encoder.mode = SIMPLE_1; 57 | encoderInit( 23, 24, 0xFF ); 58 | encoder.delay = 100; 59 | 60 | // Check for attributes changed by interrupts. 61 | while ( 1 ) 62 | { 63 | // Volume. 64 | if ( encoderDirection != 0 ) 65 | { 66 | // Volume + 67 | if ( encoderDirection > 0 ) printf( "++++.\n" ); 68 | // Volume - 69 | else printf( "----\n" ); 70 | encoderDirection = 0; 71 | } 72 | // Button. 73 | // if ( button.state ) 74 | // { 75 | // volume.mute = true; 76 | // button.state = false; 77 | // setVolumeMixer( volume ); // May be better to use playback switch. 78 | // } 79 | 80 | // Sensitivity delay. 81 | delay( encoder.delay ); 82 | } 83 | 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /streamPi/thx1138.c: -------------------------------------------------------------------------------- 1 | // **************************************************************************** 2 | // **************************************************************************** 3 | /* 4 | thx1138: 5 | 6 | ALSA experiments to test using PCM streams and the feasibility of creating 7 | a spectrum analyser and digital VU meters. 8 | 9 | Copyright 2015 by Darren Faulke 10 | 11 | This program is free software; you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 2 of the License, or 14 | (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with this program. If not, see . 23 | */ 24 | // **************************************************************************** 25 | // **************************************************************************** 26 | 27 | #define Version "Version 0.1" 28 | 29 | // Compilation: 30 | // 31 | // Compile with gcc thx1138.c -o thx1138 -lasound 32 | // Also use the following flags for Raspberry Pi optimisation: 33 | // -march=armv6 -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp 34 | // -ffast-math -pipe -O3 35 | 36 | // Authors: D.Faulke 19/10/15 37 | // Contributors: 38 | // 39 | // Changelog: 40 | // 41 | // v0.1 Initial version. 42 | 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | // **************************************************************************** 49 | // Data definitions. 50 | // **************************************************************************** 51 | 52 | // Data structure for PCM stream. 53 | struct pcmStruct 54 | { 55 | int channels; 56 | float sampleFreq; 57 | int sampleRate; 58 | }; 59 | 60 | // **************************************************************************** 61 | // argp documentation. 62 | // **************************************************************************** 63 | 64 | const char *argp_program_version = Version; 65 | const char *argp_program_bug_address = "darren@alidaf.co.uk"; 66 | static char doc[] = "A short program to test using ALSA PCM streams"; 67 | static char args_doc[] = "thx1138 "; 68 | 69 | // **************************************************************************** 70 | // Data definitions. 71 | // **************************************************************************** 72 | 73 | // Data structure to hold command line arguments. 74 | struct structArgs 75 | { 76 | int card; 77 | int control; 78 | char deviceID[8]; 79 | }; 80 | 81 | // **************************************************************************** 82 | // Command line argument definitions. 83 | // **************************************************************************** 84 | 85 | static struct argp_option options[] = 86 | { 87 | { 0, 0, 0, 0, "Card information:" }, 88 | { "card", 'c', "", 0, "Card ID number." }, 89 | { "control", 'd', "", 0, "Control ID number." }, 90 | { 0 } 91 | }; 92 | 93 | // **************************************************************************** 94 | // Command line argument parser. 95 | // **************************************************************************** 96 | 97 | static int parse_opt( int param, char *arg, struct argp_state *state ) 98 | { 99 | char *str; 100 | char *token; 101 | const char delimiter[] = ","; 102 | struct structArgs *cmdArgs = state->input; 103 | 104 | switch( param ) 105 | { 106 | case 'c' : 107 | cmdArgs->card = atoi( arg ); 108 | break; 109 | case 'd' : 110 | cmdArgs->control = atoi( arg ); 111 | break; 112 | } 113 | return 0; 114 | }; 115 | 116 | // **************************************************************************** 117 | // argp parser parameter structure. 118 | // **************************************************************************** 119 | 120 | static struct argp argp = { options, parse_opt, args_doc, doc }; 121 | 122 | 123 | // **************************************************************************** 124 | // Main section. 125 | // **************************************************************************** 126 | 127 | int main( int argc, char *argv[] ) 128 | { 129 | struct structArgs cmdArgs; 130 | unsigned int val, val2; 131 | int dir; 132 | int errNum; 133 | cmdArgs.card = 0; // Default card. 134 | cmdArgs.control = 1; // Default control. 135 | 136 | 137 | // ************************************************************************ 138 | // ALSA control elements. 139 | // ************************************************************************ 140 | snd_pcm_t *pcmp; 141 | snd_pcm_hw_params_t *params; 142 | // snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK; 143 | snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE; 144 | snd_pcm_uframes_t frames; 145 | 146 | 147 | // ************************************************************************ 148 | // Get command line parameters. 149 | // ************************************************************************ 150 | argp_parse( &argp, argc, argv, 0, 0, &cmdArgs ); 151 | 152 | printf( "Card = %i\n", cmdArgs.card ); 153 | printf( "Control = %i\n", cmdArgs.control ); 154 | sprintf( cmdArgs.deviceID, "hw:%i,%i", cmdArgs.card, cmdArgs.control ); 155 | printf( "Using device %s :", cmdArgs.deviceID ); 156 | 157 | /* Allocate a hardware parameters object. */ 158 | if ( snd_pcm_hw_params_alloca( ¶ms ) < 0 ) 159 | { 160 | fprintf( stderr, "Unable to allocate.\n" ); 161 | return -1; 162 | } 163 | /* Open PCM device for playback. */ 164 | // if ( snd_pcm_open( &pcmp, cmdArgs.deviceID, stream, 0 ) < 0 ) 165 | // { 166 | // fprintf( stderr, "Unable to open pcm device.\n" ); 167 | // return -1; 168 | // } 169 | /* Fill it in with default values. */ 170 | // if ( snd_pcm_hw_params_any( pcmp, params ) < 0 171 | // { 172 | // fprintf( stderr, "Unable to set default values.\n" ); 173 | // return -1; 174 | // } 175 | /* Interleaved mode */ 176 | // snd_pcm_hw_params_set_access( pcmp, params, 177 | // SND_PCM_ACCESS_RW_INTERLEAVED ); 178 | 179 | /* Signed 16-bit little-endian format */ 180 | snd_pcm_hw_params_set_format( pcmp, params, 181 | SND_PCM_FORMAT_S16_LE ); 182 | 183 | /* Two channels (stereo) */ 184 | snd_pcm_hw_params_set_channels( pcmp, params, 2 ); 185 | 186 | /* 44100 bits/second sampling rate (CD quality) */ 187 | val = 44100; 188 | snd_pcm_hw_params_set_rate_near( pcmp, params, &val, &dir ); 189 | 190 | /* Write the parameters to the driver */ 191 | errNum = snd_pcm_hw_params( pcmp, params ); 192 | if ( errNum < 0 ) 193 | { 194 | fprintf(stderr, "unable to set hw parameters: %s\n", 195 | snd_strerror( errNum )); 196 | exit( 1 ); 197 | } 198 | 199 | /* Display information about the PCM interface */ 200 | 201 | printf( "PCM handle name = '%s'\n", snd_pcm_name( pcmp )); 202 | 203 | printf("PCM state = %s\n", snd_pcm_state_name( snd_pcm_state( pcmp ))); 204 | 205 | snd_pcm_hw_params_get_access( params, ( snd_pcm_access_t * ) &val ); 206 | printf( "access type = %s\n", 207 | snd_pcm_access_name(( snd_pcm_access_t ) val )); 208 | 209 | snd_pcm_hw_params_get_format( params, ( snd_pcm_format_t * ) &val ); 210 | printf( "format = '%s' (%s)\n", 211 | snd_pcm_format_name(( snd_pcm_format_t ) val ), 212 | snd_pcm_format_description(( snd_pcm_format_t ) val )); 213 | 214 | snd_pcm_hw_params_get_subformat( params, 215 | ( snd_pcm_subformat_t * ) &val ); 216 | printf( "subformat = '%s' (%s)\n", 217 | snd_pcm_subformat_name(( snd_pcm_subformat_t ) val ), 218 | snd_pcm_subformat_description(( 219 | snd_pcm_subformat_t ) val )); 220 | 221 | snd_pcm_hw_params_get_channels( params, &val ); 222 | printf( "channels = %d\n", val ); 223 | 224 | snd_pcm_hw_params_get_rate( params, &val, &dir ); 225 | printf( "rate = %d bps\n", val ); 226 | 227 | snd_pcm_hw_params_get_period_time( params, &val, &dir ); 228 | printf( "period time = %d us\n", val ); 229 | 230 | snd_pcm_hw_params_get_period_size( params, &frames, &dir ); 231 | printf( "period size = %d frames\n", ( int ) frames ); 232 | 233 | snd_pcm_hw_params_get_buffer_time( params, &val, &dir ); 234 | printf( "buffer time = %d us\n", val ); 235 | 236 | snd_pcm_hw_params_get_buffer_size( params, 237 | ( snd_pcm_uframes_t * ) &val ); 238 | printf( "buffer size = %d frames\n", val ); 239 | 240 | snd_pcm_hw_params_get_periods( params, &val, &dir ); 241 | printf( "periods per buffer = %d frames\n", val ); 242 | 243 | snd_pcm_hw_params_get_rate_numden( params, &val, &val2 ); 244 | printf( "exact rate = %d/%d bps\n", val, val2 ); 245 | 246 | val = snd_pcm_hw_params_get_sbits( params ); 247 | printf( "significant bits = %d\n", val ); 248 | 249 | // snd_pcm_hw_params_get_tick_time( params, &val, &dir ); 250 | // printf( "tick time = %d us\n", val ); 251 | 252 | val = snd_pcm_hw_params_is_batch( params ); 253 | printf( "is batch = %d\n", val ); 254 | 255 | val = snd_pcm_hw_params_is_block_transfer( params ); 256 | printf( "is block transfer = %d\n", val ); 257 | 258 | val = snd_pcm_hw_params_is_double( params ); 259 | printf( "is double = %d\n", val ); 260 | 261 | val = snd_pcm_hw_params_is_half_duplex( params ); 262 | printf( "is half duplex = %d\n", val ); 263 | 264 | val = snd_pcm_hw_params_is_joint_duplex( params ); 265 | printf( "is joint duplex = %d\n", val ); 266 | 267 | val = snd_pcm_hw_params_can_overrange( params ); 268 | printf( "can overrange = %d\n", val ); 269 | 270 | val = snd_pcm_hw_params_can_mmap_sample_resolution( params ); 271 | printf( "can mmap = %d\n", val ); 272 | 273 | val = snd_pcm_hw_params_can_pause( params ); 274 | printf( "can pause = %d\n", val ); 275 | 276 | val = snd_pcm_hw_params_can_resume( params ); 277 | printf( "can resume = %d\n", val ); 278 | 279 | val = snd_pcm_hw_params_can_sync_start( params ); 280 | printf( "can sync start = %d\n", val ); 281 | snd_pcm_close( pcmp ); 282 | 283 | return 0; 284 | } 285 | --------------------------------------------------------------------------------