J.W. BRUCE / TTU_CSC1300

Dependents:   CSC1300_EduBaseV2_Lab0 mbed_blinky EduBaseV2_Lab0 mbed_blinky ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers TTU_CSC1300.cpp Source File

TTU_CSC1300.cpp

00001 /* A hardware support library for the STM32F031K6 (Nucleo32) + Edubase-V2 
00002  *
00003  * Copyright (c) 2020, jwbruce   (jwbruce@tntech.edu)
00004  *
00005  * Permission is hereby granted, free of charge, to any person obtaining a copy
00006  * of this software and associated documentation files (the "Software"), to deal
00007  * in the Software without restriction, including without limitation the rights
00008  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00009  * copies of the Software, and to permit persons to whom the Software is
00010  * furnished to do so, subject to the following conditions:
00011  *
00012  * The above copyright notice and this permission notice shall be included in
00013  * all copies or substantial portions of the Software.
00014  *
00015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00018  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00019  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00020  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00021  * THE SOFTWARE.
00022  */
00023 
00024 #include "TTU_CSC1300.h"
00025 #include "mbed.h"
00026 
00027 /**************************************************************************
00028 **
00029 ** GLOBAL VARIABLE (HARDWARE) INSTANTIATIONS
00030 **
00031 **************************************************************************/
00032 // create the communications ports
00033 SPI             spi(MOSI_PIN, MISO_PIN, SCLK_PIN);
00034 
00035 // Removed I2C fow now. Inclusion seemed to cause us to run out of
00036 // flash RAM storage.  The mbed run-time alone seems to use up most
00037 // of the F031K6 flash... uses about 26 of 32KB.
00038 //I2C             i2c(SDA_PIN, SCL_PIN);
00039 
00040 // not sure why other PinNames cause error..... Investigate further.
00041 Serial          pc(USBTX, USBRX, 57600);
00042 
00043 // create the LEDs
00044 DigitalOut      led0(LED0_PIN);
00045 DigitalOut      led1(LED1_PIN);
00046 DigitalOut      led2(LED2_PIN);
00047 
00048 // led3 only works if the solder jumper SB18 on the Nucleo32
00049 // board (back side) has been removed. The default state of SB18
00050 // (shorted) ties LED3_PIN (PB_7) to SW5_PIN (PA_5).  Only
00051 // uncomment the following LoC if you have removed SB18, else you
00052 // will get a badly behaved SW5.
00053 //
00054 #ifdef USE_LED3
00055   DigitalOut      led3(LED3_PIN);
00056 #endif
00057 
00058 // create the speaker
00059 DigitalOut      speaker(SPK_PIN);
00060 
00061 //create the chip-selects
00062 DigitalOut      cs_sd(CS_SD_PIN);
00063 DigitalOut      cs_lcd(CS_LCD_PIN);
00064 DigitalOut      cs_7seg(CS_7SEG_PIN);
00065 
00066 // create the switches
00067 DigitalIn       sw4(SW4_PIN);
00068 DigitalIn       sw5(SW5_PIN);
00069 
00070 // create the analog sensors
00071 AnalogIn        lightSensor(LGT_SENS_PIN);
00072 AnalogIn        pot(POT_PIN);
00073 AnalogIn        tempSensor(TEMP_SENS_PIN);
00074 
00075 /**************************************************************************
00076 **
00077 ** UTILITY FUNCTIONS (mostly initialization routines)
00078 **
00079 **************************************************************************/
00080 void init_spi(int i_spiBaud) {
00081     // Deassert the chip-selects. Remember our chip-selects are active-low.
00082     cs_sd = 1;
00083     cs_lcd = 1;
00084     cs_7seg = 1;
00085     // configure the SPI port
00086     spi.format(8,0);               // 8-bit SPI mode 0
00087     if (i_spiBaud == 0) {
00088         spi.frequency(1000000);     // default to 1Mbps     
00089     } else {
00090         spi.frequency(i_spiBaud);  // else, set the user-defined bitrate
00091     }
00092 } // end init_spi()
00093 
00094 /*
00095 void init_i2c(int i_i2cBaud) {
00096     if (i_i2cBaud == I2C_SPEED_FAST) {
00097         // 400 kbps (most chips should be able to handle this speed)
00098         i2c.frequency(I2C_SPEED_FAST);          
00099     } else if (i_i2cBaud == I2C_SPEED_FASTPLUS) {
00100         // 1Mbps (many chips can't go this fast)
00101         i2c.frequency(I2C_SPEED_FASTPLUS);      
00102     } else { 
00103         // 100 kbps (the original I2C bitrate)
00104         i2c.frequency(I2C_SPEED_STD);      
00105     }
00106 } // end init_i2c()
00107 */
00108 
00109 void init_serial(int i_serialBaud) {
00110     // for now, we will use
00111     //  19200 Baud, 8 data bits, no parity, and 1 stop bit (8N1)
00112     
00113     //pc.baud(19200);         // default to 19.2 kBaud for now
00114     //pc.format(8, SerialBase::None, 1);       
00115     
00116 } // end init_serial()
00117 
00118 void init_leds(void) {
00119     // turn off all LEDs
00120     led0 = 0;
00121     led1 = 0;
00122     led2 = 0;
00123     #ifdef USE_LED3
00124     led3 = 0;
00125     #endif
00126 } // end init_leds()
00127 
00128 void init_all() {
00129     // a single call to initialize all hardware to something reasonable
00130     init_spi(500000);           // 500 kbps
00131     //init_i2c(I2C_SPEED_STD);  // 100 kbps
00132     init_serial(0);             // 19.2k/8/N/1
00133     init_leds();
00134 } // end init_all()
00135 
00136 /*************************************************************************
00137 **
00138 ** SEVEN-SEGMENT LED (SSLED) CLASS FUNCTIONS
00139 **
00140 *************************************************************************/
00141 // constructor
00142 SSLED::SSLED(int display, int pattern) {
00143     setDisplay( display, pattern);
00144 }
00145 
00146 // SSLED MEMBER FUNCTIONS
00147 /* a private function used to actually write 16 bits to LED shift registers
00148 **
00149 ** We need to assert/deassert /CS_LED around the 16-bit SPI
00150 **   transfer becase /CS_LED is the register STROBE/CLK
00151 **   on the 74HC595 shift registers.  See EduBase_V2 1173D_2 schematic.
00152 */
00153 void SSLED::setDisplay(int disp, int patt) {
00154     // make sure SSLED display requested is valid
00155     if ((disp >= 1) && (disp <=4)) {
00156         cs_7seg = 0;                            /* ASSERT /CS_7 */
00157         spi.write(patt & 0xFF);                 /* write segment pattern */
00158         spi.write(1 << (4-disp));               /* write display cathode */
00159         cs_7seg = 1;                            /* DEASSERT /CS_7 */
00160     }
00161 }
00162 
00163 /****************************************************************************
00164 **
00165 ** TEXTLCD CLASS FUNCTIONS
00166 **
00167 ****************************************************************************/
00168 
00169 // Some useful defines to make code more readable
00170 // See HD44780 data sheet and the EduBase schematic for 74HC595 to LCD wiring
00171 #define CMD_BIT     0           /* BIT0 mask for HD44780 commands */
00172 #define RS_BIT      0x01        /* BIT0 mask for HD44780 register select */
00173 #define E_BIT       0x02        /* BIT1 mask for ENABLE BIT */
00174 
00175 // constructor
00176 TextLCD::TextLCD(LCDCursor cur) : _cursorState(cur) {
00177     _maxRows = 2;       // set display size
00178     _maxColumns = 16;   // set display size
00179     wait_ms(15);        // Wait 15ms to ensure powered up
00180 
00181     // send data to initialize the LCD into 4-bit mode (via our shift register)
00182     // send "Display Settings" 3 times (Only top nibble of 0x30 as we've got 4-bit bus)
00183     for (int i=0; i<3; i++) {
00184         writeNibble(0x30, CMD_BIT);     // NOTE:  NOT SURE ABOUT THE CMD BIT (0) HERE
00185         wait_ms(2);                     // this command takes 1.64ms, so wait for it
00186     }
00187     writeNibble(0x20,CMD_BIT);   // 4-bit mode
00188     wait_us(40);                 // datasheet indicates most instructions take 40us
00189 
00190     /* OK, now the display should be alive, so we can send
00191     ** commands and data "normally" via the member functions
00192     */
00193     writeCommand(0x28);          /* set 4-bit data, 2-line, 5x7 font */
00194     writeCommand(0x06);          /* move cursor right */
00195     writeCommand(0x01);          /* clear screen, move cursor to home */
00196     /* turn on display and set cursor as requested */    
00197     writeCommand(0x0C | _cursorState);
00198     cls();
00199 }
00200 
00201 // TEXTLCD CLASS MEMBER FUNCTIONS
00202 void TextLCD::setCursor(LCDCursor c) {
00203     writeCommand(0x0C | c);     // turn on display and set cursor request
00204     wait_us(1640);              // This command takes 1.64 ms
00205 }
00206 
00207 void TextLCD::setCharacter(int row, int column, int c) {
00208     setLocation(row, column);
00209     writeData(c);
00210 }
00211 
00212 void TextLCD::cls() {
00213     writeCommand(0x01);         // cls, and set cursor to 0
00214     wait_us(1640);              // This command takes 1.64 ms
00215     setLocation(0, 0);
00216 }
00217 
00218 void TextLCD::setLocation(int row, int column) {
00219     int a = address(row, column);
00220     writeCommand(a);
00221     _column = column;
00222     _row = row;
00223 }
00224 
00225 // support _putc() so the .printf() member function works on TextLCD objects
00226 int TextLCD::_putc(int value) {
00227     if (value == '\n') {
00228         _column = 0;
00229         _row++;
00230         if (_row >= _maxRows) {
00231             _row = 0;
00232         }
00233     } else {
00234         setCharacter(_row, _column, value);
00235         _column++;
00236         if (_column >= _maxColumns) {
00237             _column = 0;
00238             _row++;
00239             if (_row >= _maxRows) {
00240                 _row = 0;
00241             }
00242         }
00243     }
00244     return value;
00245 }
00246 
00247 /* our hardware does not support "reading" the LCD display
00248 ** so we have no way to _getc()
00249 **
00250 ** We could build a charater "buffer" in our class but that
00251 ** takes more memory and code ;-)
00252 */
00253 int TextLCD::_getc() {
00254     return -1;
00255 }
00256 
00257 /* write 4 bits to LCD controller
00258 **
00259 ** We need to assert/deassert /CS_LCD around each SPI
00260 **   nibble write becase /CS_LCD is the register STROBE/CLK
00261 **   on the 74HC595 shift register.  See EduBase_V2 1173D_2 schematic.
00262 */
00263 void TextLCD::writeNibble(char incoming, unsigned char rs) {
00264     incoming &= 0xF0;                       /* keep upper nibble (data) */
00265     rs &= 0x0F;                             /* keep lower nibble (room for RS bit, R/W, and E bits) */
00266     cs_lcd = 0;                             /* ASSERT /CS_LCD */
00267     spi.write(incoming | rs);               /* RS = ?, R/W = 0 , E=0 */
00268     cs_lcd = 1;                             /* DE-ASSERT /CS_LCD which enables 595 parallel outputs */
00269 
00270     cs_lcd = 0;                             /* ASSERT /CS_LCD */
00271     spi.write(incoming | rs | E_BIT);       /* RS = ?, R/W = 0 , E=1 */
00272     cs_lcd = 1;                             /* DE-ASSERT /CS_LCD which enables 595 parallel outputs */
00273     wait_us(100);                           /* short delay to make E pulse */
00274     
00275     cs_lcd = 0;                             /* ASSERT /CS_LCD */
00276     spi.write(incoming);                    /* RS = 0, R/W = 0 , E=0 */
00277     cs_lcd = 1;                             /* DE-ASSERT /CS_LCD which enables 595 parallel outputs */
00278 }    
00279 
00280 void TextLCD::writeCommand(int command) {
00281     /* RS = 0 for "command writes", so 2nd argument is 0 */
00282     writeNibble(command & 0xF0, CMD_BIT);    /* upper nibble first */
00283     writeNibble(command << 4, CMD_BIT);      /* then lower nibble */
00284 
00285     if (command < 4)
00286         wait_us(1640);              /* command 1 and 2 needs up to 1.64ms */
00287     else
00288         wait_us(40);                /* all others 40 us */
00289 }
00290 
00291 void TextLCD::writeData(int data) {
00292     /* RS = 1 for "data writes", so 2nd argument is 1 */
00293     writeNibble(data & 0xF0, RS_BIT);      /* upper nibble first */
00294     writeNibble(data << 4, RS_BIT);        /* then lower nibble */
00295     wait_ms(1);                            /* wait 1ms (CAN WE REMOVE THIS?) */
00296 }
00297 
00298 // EduBase-V2 uses HD44780-compatible 16x2 display so hard-code the calculation
00299 int TextLCD::address(int row, int column) {
00300     return 0x80 + (row * 0x40) + column;
00301 }