{"id":14523,"date":"2020-01-29T10:58:00","date_gmt":"2020-01-29T15:58:00","guid":{"rendered":"http:\/\/embedded-lab.com\/blog\/?p=14523"},"modified":"2023-09-06T02:50:08","modified_gmt":"2023-09-06T06:50:08","slug":"tinkering-ti-msp430f5529","status":"publish","type":"post","link":"https:\/\/embedded-lab.com\/blog\/tinkering-ti-msp430f5529\/","title":{"rendered":"Tinkering TI MSP430F5529"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">In my <a href=\"http:\/\/embedded-lab.com\/blog\/introducing-ti-msp430-microcontrollers\/\">past tutorials on MSP430s<\/a>, I demonstrated how to get started with MSP430 general purpose microcontrollers from <strong><em>Texas Instruments (TI)<\/em><\/strong>. Those tutorials covered most aspects of low and mid-end MSP430G2xxx series microcontrollers. For those tutorials, TI\u2019s official software suite \u2013 <strong><em>Code Composer Studio (CCS)<\/em><\/strong> \u2013 an Eclipse-based IDE and <strong><em>GRACE<\/em><\/strong> \u2013 a graphical peripheral initialization and configuration tool similar to STM32CubeMX were used. To me, those low and mid-end TIs chips are cool and offer best resources one can expect at affordable prices and small physical form-factors. I also briefly discussed about advanced MSP430 microcontrollers and the software resources needed to use them effectively. Given these factors, now it is high time that we start exploring an advanced 16-bit TI MSP430 microcontroller using a combination of past experiences and advanced tools. MSP430F5529 is such a robust high-end device and luckily it also comes with an affordable Launchpad board dedicated for it. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"945\" height=\"713\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/launchpad.jpg\" alt=\"\" class=\"wp-image-14524\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/launchpad.jpg 945w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/launchpad-580x438.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/launchpad-768x579.jpg 768w\" sizes=\"auto, (max-width: 945px) 100vw, 945px\" \/><\/figure>\n\n\n\n<!--more-->\n\n\n\n<p class=\"wp-block-paragraph\">First of all, MSP430F5529 is a monster microcontroller because it offers large memory spaces\u2013 128kB of flash and 8kB of RAM. Secondly, it is a 16-bit RISC microcontroller that host several advanced features like USB, DMA, 12-bit SAR ADC, analogue comparator, a real time clock (RTC), several sophisticated timers with multiple capture-compare I\/O channels, etc. There is an on-chip hardware multiplier apart from several bidirectional general-purpose digital input-output (DIO\/GPIO) pins, multipurpose communication peripherals (USCIs) and a highly complex clock and power system that can be tweaked to optimize the speed-power performances. The MSP430F5529LP microcontroller featured on-board MSP430F5529 Launchpad is a low power energy-efficient variant of MSP430F5529 and hence the <em>LP<\/em> designation at the end of the part naming. It can run at low voltage levels like 1.8V. In short, it is a hobbyist wildest dream come true. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">MSP-EXP430F5529LP Launchpad Board<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The MSP-EXP430F5529LP Launchpad board is just like other Launchpad boards, having similar form-factor and layout. Unlike the previously seen MSP-EXP430G2 Launchpads, its header pins are brought out using dual-sided male- female rail-connectors. These allow us to stack <strong><em>BoosterPacks<\/em><\/strong> on both sides.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"555\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MSP430F5529-Launchpad-1024x555.jpeg\" alt=\"\" class=\"wp-image-14526\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MSP430F5529-Launchpad-1024x555.jpeg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MSP430F5529-Launchpad-580x314.jpeg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MSP430F5529-Launchpad-768x416.jpeg 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Shown above and below are the pin maps of this Launchpad board.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1007\" height=\"439\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MSP430F5529LP-Launchpad-Pin-Map.png\" alt=\"\" class=\"wp-image-14525\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MSP430F5529LP-Launchpad-Pin-Map.png 1007w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MSP430F5529LP-Launchpad-Pin-Map-580x253.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MSP430F5529LP-Launchpad-Pin-Map-768x335.png 768w\" sizes=\"auto, (max-width: 1007px) 100vw, 1007px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The first pin map is useful for <strong><em>Energia<\/em><\/strong> users and the second one is useful for CCS users. I use a combination of both.  Like other Launchpad boards, this Launchpad comes with a separable MSP-FET USB programmer and debugger interface. Since MSP430F5529 micro has USB hardware embedded in it, the on-board micro USB port can act as a physical USB port when developing USB-based hardware. The micro USB port isn\u2019t, however, directly connected with the chip. Instead of that, the same USB port is connected to the on-board FET programmer and the MSP430F5529 chip via an on-board USB hub. The micro USB port also provides power to the board. The on-board MSP430 chip is powered by 3.3V LDO regulator. This LDO is not meant for driving large loads. There are sufficient power rail pins to hook-up low-power external devices like sensors, LCDs, etc without the need of power rail extenders.&nbsp;&nbsp;&nbsp; <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"789\" height=\"599\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Board.png\" alt=\"\" class=\"wp-image-14527\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Board.png 789w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Board-580x440.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Board-768x583.png 768w\" sizes=\"auto, (max-width: 789px) 100vw, 789px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">MSP430F5529 is not a low pin count micro and it has a sophisticated clock system that can be feed with both internal and external clock sources. Thus, unlike MSP430G2xxx Launchpads, this Launchpad comes with two external crystals \u2013 a 4MHz and a 32.768kHz crystal that are physically connected with GPIO pins. There are two user buttons and two LEDs also. Additionally, there are dedicated buttons for USB bootstrap loader and hardware reset. There are few jumpers that can be for measurements, debugging, programming, etc.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Shown below is the schematic of MSP430F5529LP Launchpad board:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"756\" height=\"1024\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Schematic-756x1024.png\" alt=\"\" class=\"wp-image-14530\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Schematic-756x1024.png 756w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Schematic-480x650.png 480w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Schematic-768x1041.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Schematic.png 1039w\" sizes=\"auto, (max-width: 756px) 100vw, 756px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">TI MSP430Ware Driver Library and Other Stuffs<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Like with other advanced microcontrollers from TI,\nthere is no GRACE-like support that can be found for MSP430F5529 and similar\ndevices. In fact, GRACE only supports few low-end and mid-end MSP430\nmicrocontrollers and for some reason TI stopped updating this great tool since\n2013. One probably reason may be the difficulty in developing a GUI-based\napplication that can be used across all computer platforms (Windows, Linux, Mac\nOS, etc) while maintaining support for all ever-growing families of MSP430\ndevices. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of upgrading GRACE, TI invested on something called <strong><em>MSP430Ware Driver Library<\/em><\/strong> or simply <strong><em>Driverlib<\/em><\/strong>. Driverlib replaces traditional register-level coding with a set of dedicated hardware libraries that reduces learning and implementation curves. These libraries consist of functions, variables and constants that have meaningful names. A sample code is shown below:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Timer_A_outputPWMParam outputPWMParam = {0}; \noutputPWMParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK; outputPWMParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_2; outputPWMParam.timerPeriod = 20000; \noutputPWMParam.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1; outputPWMParam.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET; outputPWMParam.dutyCycle = 0; \nTimer_A_outputPWM(TIMER_A2_BASE, &amp;outputPWMParam);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Note that there is no register-level coding involved\nand that\u2019s the beauty. Here all the settings of a timer in PWM mode are being\nset. Each parameter is named with a meaningful name instead of some meaningless\nmagic numbers and coding jargon.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Initially, I was doubtful and hesitant about using\nDriverlib because it hides away all the good-old register-level coding and at\nthe same time it lacks good documentations. Comparing Driverlib documentation\nwith the documentation of other manufacturers like STMicroelectronics or\nMicrochip, I would say that Driverlib documentation is somewhat incomplete,\nclumsy and difficult to perceive. Adding to this is the fact that TI while\ndeveloping and updating Driverlib made some changes to some function and\ndefinition names. This creates further confusion unless you are using the right\nversion of documentation alongside the right Driverlib version. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here\u2019s one example. Both are correct and the compiler won\u2019t throw any unexpected error but the first one is seen in older documentations while the second is used more often now. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Timer_A_startCounter(__MSP430_BASEADDRESS_T0A5__, TIMER_A_CONTINUOUS_MODE);\n\nor\n\nTimer_A_startCounter(TIMER_A0_BASE, TIMER_A_CONTINUOUS_MODE);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Issues like this one discussed above may not always\nbe that simple and when it comes to older codes\/examples, thing may become very\nugly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Another disadvantage that comes along with stuffs\nlike Driverlib is resource management. Indeed, Driverlib reduces coding efforts\na lot but at the expense of valuable and limited memory resources. Performance\nis also a bit compromised as execution speed is reduced due to additional\nhidden coding. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Despite these facts, I decided to go along with\nDriverlib because like other coders I didn\u2019t want to spend time going through register-by-registers.\nIn present day\u2019s embedded system arena, people like the easy, effective and\nquick paths. It happened to me that after few trials I was able to master\nDriverlib and could also pinpoint issues with documentation and even practically\nget rid of the issues. As of this moment, I am enjoying it a lot and this whole\ntutorial is based on it. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Use <strong><em>Resource Explorer<\/em><\/strong> of Code Composer\nStudio (CCS) IDE or visit the following link:<\/p>\n\n\n\n<figure class=\"wp-block-embed\"><div class=\"wp-block-embed__wrapper\">\nhttp:\/\/www.ti.com\/tool\/MSPWARE\n<\/div><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">to get access to MSP430Ware. MSP430Ware contains lot\nexample codes, libraries and other stuffs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The rest of the software suite and hardware tools\nwill be same as the ones used before. Grace support is unavailable and so it\nwon\u2019t be used. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Please also download MSP430F5529 <a href=\"https:\/\/www.ti.com\/product\/MSP430F5529\/technicaldocuments\">documentations<\/a> and Launchpad board <a href=\"http:\/\/www.ti.com\/tool\/MSP-EXP430F5529LP\">resources<\/a>. <\/p>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Digital Input-Output &#8211; DIO<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Digital Input-Output (DIO) <em>a.k.a<\/em>\nGeneral-Purpose Input-Output (GPIO) coding is the basic and simplest\nrequirement for any microcontroller. This is one area where a microcontroller\n(MCU) differs from a microprocessor (MPU). <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">MSP430F5529LP Launchpad comes with 40-pin dual-in-line headers. Of these 40 pins, 35 pin headers are connected to DIO pins. There seven DIO ports but they are not evenly divided, i.e. not all ports are 8-bit wide as one would typically expect. Most of the DIOs have more than one functionality, i.e. timer, ADC, communication, etc. DIO pins can be individually programmed as either inputs or outputs. There are independent input-output data registers. In input mode, DIOs can be pulled up or pulled down using internal pull resistors just like other MSP430s. To take care of Electromagnetic Interference (EMI) issues, output drive strength can be altered in output mode, adding incredible robustness. Additionally, pins can operate at high frequency (25MHz) conditions. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"467\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/GPIO1-1024x467.png\" alt=\"\" class=\"wp-image-14542\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/GPIO1-1024x467.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/GPIO1-580x264.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/GPIO1-768x350.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/GPIO1.png 1047w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Note in the diagram above that ports are grouped as <strong><em>PA<\/em><\/strong>,\n<strong><em>PB<\/em><\/strong>,\n<strong><em>PC<\/em><\/strong>\nand <strong><em>PD<\/em><\/strong>.\nPorts are usually 8-bit wide but after adjacently grouping them as such, they\nbecome 16-bit wide. PA port pins additionally have interrupt capability unlike\nother ports. PA port consists of P1 and P2, PB port consists of P3 and P4 and\nso forth. Port grouping is helpful when we need to drive parallel port\ninterfaces like TFT displays. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It is advised not to exceed output drive current or input voltage ranges\/polarity. Best practices are to avoid driving loads directly via output pins and using buffer ICs or isolation for input pins. We must check that whether we are not overloading the microcontroller pins any how because this may have undesired consequences. Try to keep MCU\u2019s total current consumption as low as possible. Any device is more stable at low power and optimum temperature conditions than otherwise. Remember MSP430s are low-power device.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n\nvoid GPIO_init(void);\n\nvoid main(void)\n{\n    WDT_A_hold(WDT_A_BASE);\n\n    GPIO_init();\n\n    while(1)\n    {\n        if(GPIO_getInputPinValue(GPIO_PORT_P1,\n                                 GPIO_PIN1) == 0)\n        {\n            GPIO_setOutputHighOnPin(GPIO_PORT_P4,\n                                    GPIO_PIN7);\n\n            GPIO_setOutputLowOnPin(GPIO_PORT_P1,\n                                   GPIO_PIN0);\n        }\n\n        if(GPIO_getInputPinValue(GPIO_PORT_P2,\n                                 GPIO_PIN1) == 0)\n        {\n            GPIO_setOutputHighOnPin(GPIO_PORT_P1,\n                                    GPIO_PIN0);\n\n            GPIO_setOutputLowOnPin(GPIO_PORT_P4,\n                                   GPIO_PIN7);\n        }\n    };\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1,\n                                         GPIO_PIN1);\n\n    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2,\n                                         GPIO_PIN1);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P1,\n                        GPIO_PIN0);\n\n    GPIO_setDriveStrength(GPIO_PORT_P1,\n                          GPIO_PIN0,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n\n    GPIO_setDriveStrength(GPIO_PORT_P4,\n                          GPIO_PIN7,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"999\" height=\"757\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DIO.png\" alt=\"\" class=\"wp-image-14543\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DIO.png 999w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DIO-580x439.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DIO-768x582.png 768w\" sizes=\"auto, (max-width: 999px) 100vw, 999px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The demo here alternatively turns on\/off the pair of on-board LEDs with on-board button presses. Since this is the first example, I did not configure clocks and so the default clock settings are used. There is nothing dependent on timing. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Inputs are configured as inputs with internal pull-up resistor. This is so because the on-board buttons are directly connected the GPIO pins without any pull resistor. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Outputs are configured full output drive output pins. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">GPIO_setAsOutputPin(GPIO_PORT_P4, GPIO_PIN7); GPIO_setDriveStrength(GPIO_PORT_P4, GPIO_PIN7, GPIO_FULL_OUTPUT_DRIVE_STRENGTH);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In the main loop, the LED pins are toggle alternatively with button presses. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">if(GPIO_getInputPinValue(GPIO_PORT_P1, GPIO_PIN1) == 0)\n{\n    GPIO_setOutputHighOnPin(GPIO_PORT_P4, GPIO_PIN7);\n\n    GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);\n}\n\nif(GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN1) == 0)\n{\n    GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0);\n\n    GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN7);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"886\" height=\"1024\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/GPIO-1-886x1024.jpg\" alt=\"\" class=\"wp-image-14544\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/GPIO-1-886x1024.jpg 886w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/GPIO-1-562x650.jpg 562w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/GPIO-1-768x888.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/GPIO-1.jpg 1237w\" sizes=\"auto, (max-width: 886px) 100vw, 886px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"886\" height=\"1024\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/GPIO-2-1-886x1024.jpg\" alt=\"\" class=\"wp-image-14546\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/GPIO-2-1-886x1024.jpg 886w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/GPIO-2-1-562x650.jpg 562w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/GPIO-2-1-768x888.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/GPIO-2-1.jpg 1237w\" sizes=\"auto, (max-width: 886px) 100vw, 886px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/6b1a15OIddg?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Unified Clock System &#8211; UCS<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">MSP430F5529 just like other MSP430s have a very sophisticated clock system called Unified Clock System (UCS). This is a modern trend for most microcontrollers. The goal of such sophistications is to allow users to balance between performance and power optimization with minute compromises. Shown below is the block diagram of UCS. Though it may appear complicated, it has two main parts &#8211; clocks signals and their sources.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"741\" height=\"827\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Block.png\" alt=\"\" class=\"wp-image-14549\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Block.png 741w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Block-580x647.png 580w\" sizes=\"auto, (max-width: 741px) 100vw, 741px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">In a MSP430F5529\nmicro, there are three clock signals or simply clocks that drive internal\nhardware peripheral modules and the CPU. These clocks can be feed with\ndifferent sources independently and have independent divider\/scalars. Different\nclocks have different primary uses. These clocks are as follows:<br>\n<br>\n<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong><em>Master Clock \u2013 MCLK <\/em><\/strong>&nbsp;&nbsp;<br>\n<br>\n<ul><li>Used primarily for CPU.<\/li><\/ul><ul><li>Usually very fast and usually fastest\namongst other clocks.<\/li><\/ul><\/li><\/ul>\n\n\n\n<ul class=\"wp-block-list\"><li><strong><em>Sub-Master Clock \u2013 SMCLK<\/em><\/strong><strong><em><br>\n<br>\n<\/em><\/strong><ul><li>Used for hardware peripheral modules\nlike timers, ADC, USCI, etc.<\/li><\/ul><ul><li>Can be as fast as MCLK.<br>\n<br>\n<\/li><\/ul><\/li><li><strong><em>Auxiliary Clock \u2013 ACLK <\/em><\/strong><strong><em><br>\n<br>\n<\/em><\/strong><strong><em><\/em><\/strong><ul><li>Can be used for hardware peripheral\nmodules specially the low power ones.<\/li><\/ul><ul><li>Typically, slower than other clocks\nand acts as a tertiary clock.<\/li><\/ul><\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The following clock sources can independently feed\nthe aforementioned clock signals:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong><em>Very Low Oscillator Clock \u2013 VLOCLK <\/em><\/strong><strong><em><br>\n<br>\n<\/em><\/strong><ul><li>On-chip very low frequency RC oscillator\n(about 10kHz).<\/li><\/ul><ul><li>Not very accurate.<\/li><\/ul><ul><li>Intended for idle\/sleep modes\nand timing insensitive tasks.<\/li><\/ul><\/li><\/ul>\n\n\n\n<ul class=\"wp-block-list\"><li><strong><em>Reference\nOscillator Clock \u2013 REFOCLK <\/em><\/strong><em><\/em><\/li><\/ul>\n\n\n\n<ul class=\"wp-block-list\"><li>On-chip reference oscillator (32.768kHz).<ul><li>Moderately accurate.<\/li><\/ul><\/li><\/ul>\n\n\n\n<ul class=\"wp-block-list\"><li><strong><em>Digitally Controlled Oscillator \u2013 DCO <\/em><\/strong><\/li><\/ul>\n\n\n\n<ul class=\"wp-block-list\"><li>Digitally-controlled fast oscillator\nsource.<ul><li>Stabilized Frequency-Locked-Loop (FLL).\n<\/li><\/ul><\/li><\/ul>\n\n\n\n<ul class=\"wp-block-list\"><li><strong><em>External\nOscillator 1 \u2013 XT1CLK&nbsp;&nbsp;&nbsp; <\/em><\/strong><em><\/em><\/li><\/ul>\n\n\n\n<ul class=\"wp-block-list\"><li>32.768kHz crystal.<ul><li>Useful for driving the RTC module.<\/li><\/ul><ul><li>Can be feed with other external crystals\nor external clock sources from 4 \u2013 32MHz.<\/li><\/ul><\/li><\/ul>\n\n\n\n<ul class=\"wp-block-list\"><li><strong><em>External\nOscillator 2 \u2013 XT2CLK<\/em><\/strong><strong><em><br>\n<br>\n<\/em><\/strong><em><\/em><ul><li>In a Launchpad board, this is connected\nto an external onboard 4 MHz crystal.<\/li><\/ul><ul><li>Can be feed with crystals or external\nclock sources from 4 \u2013 32MHz.<\/li><\/ul><\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">All of these sources and clock signals can be applied in a vast number of combinations, allowing us to set, fine tune and run the <strong><em>Digitally Controlled Oscillator (DCO)<\/em><\/strong> at an astonishing speed of 25MHz.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>delay.h<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#define XT1_FREQ          32768\n#define XT2_FREQ          4000000\n#define MCLK_FREQ         25000000\n\n#define XT1_KHZ           (XT1_FREQ \/ 1000)\n#define XT2_KHZ           (XT2_FREQ \/ 1000)\n#define MCLK_KHZ          (MCLK_FREQ \/ 1000)\n\n#define scale_factor       4\n\n#define MCLK_FLLREF_RATIO (MCLK_KHZ \/ (XT2_KHZ \/ scale_factor))\n\n#define CPU_F             ((double)MCLK_FREQ)\n\n#define delay_us(delay) __delay_cycles((long)(CPU_F*(((double)delay)\/1000000.0)))\n#define delay_ms(delay) __delay_cycles((long)(CPU_F*(((double)delay)\/1000.0)))<strong><em>main.c<\/em><\/strong><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>main.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n\nvoid indicate(void)\n{\n    GPIO_setOutputHighOnPin(GPIO_PORT_P4, GPIO_PIN7);\n\n    delay_ms(20);\n\n    GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN7);\n\n    delay_ms(20);\n}\n\nvoid toggle_LED(void)\n{\n    signed char i = 2;\n\n    while(i &gt; -1)\n    {\n        GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);\n\n        delay_ms(40);\n        i--;\n    };\n\n    GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);\n}\n\nvoid main(void)\n{\n    WDT_A_hold(WDT_A_BASE);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P1,\n                        GPIO_PIN0);\n\n    GPIO_setDriveStrength(GPIO_PORT_P1,\n                          GPIO_PIN0,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n\n    GPIO_setDriveStrength(GPIO_PORT_P4,\n                          GPIO_PIN7,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    indicate();\n    toggle_LED();\n\n    UCS_initClockSignal(UCS_MCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    indicate();\n    toggle_LED();\n\n    UCS_initClockSignal(UCS_MCLK,\n                        UCS_REFOCLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    indicate();\n    toggle_LED();\n\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_FLLREF,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initFLLSettle(MCLK_KHZ,\n                      MCLK_FLLREF_RATIO);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_REFOCLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    indicate();\n\n    while (1)\n    {\n        toggle_LED();\n    };\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"700\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UCS-1024x700.png\" alt=\"\" class=\"wp-image-14550\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UCS-1024x700.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UCS-580x396.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UCS-768x525.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UCS.png 1099w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Unless altered or set by coder, the default clock\nspeeds of the three clocks are as follows:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>MCLK\n<\/strong><strong>\u2248 1.0\nMHz<\/strong><\/li><li><strong>SMCLK\n<\/strong><strong>\u2248 1.0\nMHz<\/strong><\/li><li><strong>ACLK\n= 32.768 kHz<\/strong><\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">However, we don\u2019t want to use these defaults as it is pointless to\nuse so when we have better options. We can alter clock settings and tune the <strong><em>Digitally\nControlled Oscillator (DCO)<\/em><\/strong> to run at 25MHz which is, by the way, the\nmax clock speed of MSP430F5529 micro.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The demo here demonstrates how clock speed affects LED blinking over the same amount of delay. Different clocks are initiated with different settings and LED blinking is monitored. The on-board green LED (<em>indicate function<\/em>) indicates a change in clock settings while the on-board red LED (<em>toggle function<\/em>) is blinked as an indicator of speed. This is possibly the simplest arrangement. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{\n    GPIO_setOutputHighOnPin(GPIO_PORT_P4, GPIO_PIN7);\n    delay_ms(20);\n\n    GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN7);\n    delay_ms(20);\n}\n\nvoid toggle_LED(void)\n{\n    signed char i = 2;\n\n    while(i &gt; -1)\n    {\n        GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);\n        delay_ms(40);\n        i--;\n    };\n\n    GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">At first, no clock settings are applied and so the clocks operate at their respective default speeds. Note that software delays are dependent on MCLK frequency and so LED flashing will differ with different MCLK speeds. Please refer to delay library header file. In the code, the delay amounts are not adjusted with clock speeds. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#define XT1_FREQ          32768\n#define XT2_FREQ          4000000\n#define MCLK_FREQ         25000000\n\n#define XT1_KHZ           (XT1_FREQ \/ 1000)\n#define XT2_KHZ           (XT2_FREQ \/ 1000)\n#define MCLK_KHZ          (MCLK_FREQ \/ 1000)\n\n#define scale_factor       4\n\n#define MCLK_FLLREF_RATIO (MCLK_KHZ \/ (XT2_KHZ \/ scale_factor))\n\n#define CPU_F             ((double)MCLK_FREQ)\n\n#define delay_us(delay)    __delay_cycles((long)(CPU_F*(((double)delay)\/1000000.0)))\n#define delay_ms(delay)    __delay_cycles((long)(CPU_F*(((double)delay)\/1000.0)))<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In the code, you\u2019ll notice that only MCLK is altered for the aforementioned reason.&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">UCS_initClockSignal(UCS_MCLK, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_1);\n....\nUCS_initClockSignal(UCS_MCLK, UCS_REFOCLK_SELECT, UCS_CLOCK_DIVIDER_1);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Up to this point only internal sources have been employed but we do have options for external and high frequency clocks. To use on-board external crystals, we have to initialize their respective pins.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, (GPIO_PIN4 | GPIO_PIN2));\n\nGPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, (GPIO_PIN5 | GPIO_PIN3));<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">These pins should be initiated as alternative\/secondary function\npins. Port Mapping Controller (PMC) does this job in background. If these pins\nare not initialized properly as such, the crystals may not function at all and\nwe may end up with an inert lifeless microcontroller.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As per onboard crystal placement, keep in mind that<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>XT1 = 32.768 kHz<\/li><li>XT2 = 4.0 MHz<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">With the pins initialized, we are ready to set the external sources as per their respective frequencies. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">UCS_setExternalClockSource(XT1_FREQ, XT2_FREQ);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We can directly use these sources for clocks:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">UCS_initClockSignal(UCS_ACLK, UCS_XT1CLK_SELECT, UCS_CLOCK_DIVIDER_1);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We can also use these sources to tune the DCO. To tune the DCO, we must initialize the <strong><em>Frequency Locked Loop (FLL)<\/em><\/strong> using either internal or external sources. First, the FLL\u2019s reference clock source is initialized. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">UCS_initClockSignal(UCS_FLLREF, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_4);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After this, the FLL is allowed to stabilize or settle.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">UCS_initFLLSettle(MCLK_KHZ, MCLK_FLLREF_RATIO);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The following lines in the delay header file are important because their values alter MCLK frequency.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#define MCLK_KHZ          (MCLK_FREQ \/ 1000)\n\n#define scale_factor       4\n\n#define MCLK_FLLREF_RATIO (MCLK_KHZ \/ (XT2_KHZ \/ scale_factor))<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Another thing that is very important to note is the relation between system frequency and core power mode. The graph below shows this relation. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"630\" height=\"480\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PMM.png\" alt=\"\" class=\"wp-image-14551\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PMM.png 630w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PMM-580x442.png 580w\" sizes=\"auto, (max-width: 630px) 100vw, 630px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">From the graph, we can see that higher the system clock frequency, the higher is the required supply voltage, i.e. core power. By default, the core power mode is 0 and, in this mode, the maximum system clock frequency is 8 MHz. My example code goes to maximum operating frequency of 25 MHz at the ending and so core power mode 3 is applied before setting the FLL. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">PMM_setVCore(PMM_CORE_LEVEL_3);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The rest of the clocks (ACLK and SMCLK) are set after setting the MCLK.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"886\" height=\"982\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UCS-1.jpg\" alt=\"\" class=\"wp-image-14552\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UCS-1.jpg 886w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UCS-1-580x643.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UCS-1-768x851.jpg 768w\" sizes=\"auto, (max-width: 886px) 100vw, 886px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"886\" height=\"982\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UCS-2.jpg\" alt=\"\" class=\"wp-image-14553\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UCS-2.jpg 886w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UCS-2-580x643.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UCS-2-768x851.jpg 768w\" sizes=\"auto, (max-width: 886px) 100vw, 886px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/o32kFY6SymA?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Alphanumerical LCD<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Alphanumerical LCDs are probably the easiest devices to quickly project information visually. They are easy to use and cheap. To be able to use them, we do not need any additional hardware feature of a micro or any special communication hardware like I2C and SPI. Digital I\/Os are what we need to use these displays. Just like my other tutorials, this tutorial includes three LCD examples \u2013 one with software SPI communication, one with software I2C communication and one with direct DIO-based 4-bit LCD interface. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"495\" height=\"231\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/lcd.png\" alt=\"\" class=\"wp-image-14556\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Be sure to use 3.3V compatible LCD because most of them don\u2019t operate at 3.3V power level. Most of the LCD are designed for 5V operation. It is okay to use 5V power supply for powering LCD if there is no other option. LCDs accept 0V &#8211; 3.3V logic level. However, there should be no way with which a 5V power supply\/device can get connected with MSP430\u2019s 3.3V power bus. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>lcd.h<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n\n#define LCD_RS_PORT           GPIO_PORT_P8\n#define LCD_RS_PIN            GPIO_PIN1\n\n#define LCD_EN_PORT           GPIO_PORT_P8\n#define LCD_EN_PIN            GPIO_PIN2\n\n#define LCD_D4_PORT           GPIO_PORT_P2\n#define LCD_D4_PIN            GPIO_PIN3\n\n#define LCD_D5_PORT           GPIO_PORT_P3\n#define LCD_D5_PIN            GPIO_PIN7\n\n#define LCD_D6_PORT           GPIO_PORT_P2\n#define LCD_D6_PIN            GPIO_PIN6\n\n#define LCD_D7_PORT           GPIO_PORT_P4\n#define LCD_D7_PIN            GPIO_PIN0\n\n#define LCD_RS_HIGH           GPIO_setOutputHighOnPin(LCD_RS_PORT, LCD_RS_PIN)\n#define LCD_RS_LOW            GPIO_setOutputLowOnPin(LCD_RS_PORT, LCD_RS_PIN)\n\n#define LCD_EN_HIGH           GPIO_setOutputHighOnPin(LCD_EN_PORT, LCD_EN_PIN)\n#define LCD_EN_LOW            GPIO_setOutputLowOnPin(LCD_EN_PORT, LCD_EN_PIN)\n\n#define LCD_DB4_HIGH          GPIO_setOutputHighOnPin(LCD_D4_PORT, LCD_D4_PIN)\n#define LCD_DB4_LOW           GPIO_setOutputLowOnPin(LCD_D4_PORT, LCD_D4_PIN)\n\n#define LCD_DB5_HIGH          GPIO_setOutputHighOnPin(LCD_D5_PORT, LCD_D5_PIN)\n#define LCD_DB5_LOW           GPIO_setOutputLowOnPin(LCD_D5_PORT, LCD_D5_PIN)\n\n#define LCD_DB6_HIGH          GPIO_setOutputHighOnPin(LCD_D6_PORT, LCD_D6_PIN)\n#define LCD_DB6_LOW           GPIO_setOutputLowOnPin(LCD_D6_PORT, LCD_D6_PIN)\n\n#define LCD_DB7_HIGH          GPIO_setOutputHighOnPin(LCD_D7_PORT, LCD_D7_PIN)\n#define LCD_DB7_LOW           GPIO_setOutputLowOnPin(LCD_D7_PORT, LCD_D7_PIN)\n\n#define clear_display         0x01\n#define goto_home             0x02\n\n#define cursor_direction_inc  (0x04 | 0x02)\n#define cursor_direction_dec  (0x04 | 0x00)\n#define display_shift         (0x04 | 0x01)\n#define display_no_shift      (0x04 | 0x00)\n\n#define display_on            (0x08 | 0x04)\n#define display_off           (0x08 | 0x02)\n#define cursor_on             (0x08 | 0x02)\n#define cursor_off            (0x08 | 0x00)\n#define blink_on              (0x08 | 0x01)\n#define blink_off             (0x08 | 0x00)\n\n#define _8_pin_interface      (0x20 | 0x10)\n#define _4_pin_interface      (0x20 | 0x00)\n#define _2_row_display        (0x20 | 0x08)\n#define _1_row_display        (0x20 | 0x00)\n#define _5x10_dots            (0x20 | 0x40)\n#define _5x7_dots             (0x20 | 0x00)\n\n#define DAT                   1\n#define CMD                   0\n\n#define dly                   2\n\nvoid LCD_DIO_init(void);\nvoid LCD_init(void);\nvoid LCD_send(unsigned char value, unsigned char mode);\nvoid LCD_4bit_send(unsigned char lcd_data);\nvoid LCD_putstr(char *lcd_string);\nvoid LCD_putchar(char char_data);\nvoid LCD_clear_home(void);\nvoid LCD_goto(unsigned char x_pos, unsigned char y_pos);\nvoid toggle_EN_pin(void);\nvoid toggle_io(unsigned char lcd_data, unsigned char bit_pos, unsigned int PORT, unsigned int PIN);<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>lcd.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"lcd.h\"\n\nvoid LCD_DIO_init(void)\n{\n    GPIO_setAsOutputPin(LCD_RS_PORT, LCD_RS_PIN);\n    GPIO_setAsOutputPin(LCD_EN_PORT, LCD_EN_PIN);\n    GPIO_setAsOutputPin(LCD_D4_PORT, LCD_D4_PIN);\n    GPIO_setAsOutputPin(LCD_D5_PORT, LCD_D5_PIN);\n    GPIO_setAsOutputPin(LCD_D6_PORT, LCD_D6_PIN);\n    GPIO_setAsOutputPin(LCD_D7_PORT, LCD_D7_PIN);\n\n    _delay_cycles(100);\n}\n\nvoid LCD_init(void)\n{\n    LCD_DIO_init();\n\n    LCD_RS_LOW;\n    delay_ms(dly);\n    toggle_EN_pin();\n\n    LCD_send(0x33, CMD);\n    LCD_send(0x32, CMD);\n\n    LCD_send((_4_pin_interface | _2_row_display | _5x7_dots), CMD);\n    LCD_send((display_on | cursor_off | blink_off), CMD);\n    LCD_send((clear_display), CMD);\n    LCD_send((cursor_direction_inc | display_no_shift), CMD);\n}\n\nvoid LCD_send(unsigned char value, unsigned char type)\n\n{\n    switch(type)\n    {\n      case DAT:\n      {\n          LCD_RS_HIGH;\n         break;\n      }\n      default:\n      {\n         LCD_RS_LOW;\n         break;\n      }\n    }\n\n    LCD_4bit_send(value);\n}\n\nvoid LCD_4bit_send(unsigned char lcd_data)\n{\n    toggle_io(lcd_data, 7, LCD_D7_PORT, LCD_D7_PIN);\n    toggle_io(lcd_data, 6, LCD_D6_PORT, LCD_D6_PIN);\n    toggle_io(lcd_data, 5, LCD_D5_PORT, LCD_D5_PIN);\n    toggle_io(lcd_data, 4, LCD_D4_PORT, LCD_D4_PIN);\n\n    toggle_EN_pin();\n\n    toggle_io(lcd_data, 3, LCD_D7_PORT, LCD_D7_PIN);\n    toggle_io(lcd_data, 2, LCD_D6_PORT, LCD_D6_PIN);\n    toggle_io(lcd_data, 1, LCD_D5_PORT, LCD_D5_PIN);\n    toggle_io(lcd_data, 0, LCD_D4_PORT, LCD_D4_PIN);\n\n    toggle_EN_pin();\n}\n\nvoid LCD_putstr(char *lcd_string)\n{\n    do\n    {\n        LCD_send(*lcd_string++, DAT);\n    }while(*lcd_string != '\\0');\n}\n\nvoid LCD_putchar(char char_data)\n{\n    LCD_send(char_data, DAT);\n}\n\nvoid LCD_clear_home(void)\n{\n    LCD_send(clear_display, CMD);\n    LCD_send(goto_home, CMD);\n}\n\nvoid LCD_goto(unsigned char x_pos, unsigned char y_pos)\n{\n    if(y_pos == 0)\n    {\n        LCD_send((0x80 | x_pos), CMD);\n    }\n    else\n    {\n        LCD_send((0x80 | 0x40 | x_pos), CMD);\n    }\n}\n\nvoid toggle_EN_pin(void)\n{\n    LCD_EN_HIGH;\n    delay_ms(dly);\n    LCD_EN_LOW;\n    delay_ms(dly);\n}\n\nvoid toggle_io(unsigned char lcd_data, unsigned char bit_pos, unsigned int PORT, unsigned int PIN)\n{\n    unsigned char temp = 0x00;\n\n    temp = (0x01 &amp; (lcd_data &gt;&gt; bit_pos));\n\n    switch(temp)\n    {\n        case 0:\n        {\n            GPIO_setOutputLowOnPin(PORT, PIN);\n            break;\n        }\n\n        default:\n        {\n            GPIO_setOutputHighOnPin(PORT, PIN);\n            break;\n        }\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>main.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"lcd.h\"\n\nvoid clock_init(void);\nvoid show_value(unsigned char value);\n\nvoid main(void)\n{\n    unsigned char s = 0x00;\n\n    char txt1[] = {\"MICROARENA\"};\n    char txt2[] = {\"SShahryiar\"};\n    char txt3[] = {\"MSP430F5529LP\"};\n    char txt4[] = {\"Launchpad!\"};\n\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n\n    LCD_init();\n\n    LCD_clear_home();\n\n    LCD_goto(3, 0);\n    LCD_putstr(txt1);\n    LCD_goto(3, 1);\n    LCD_putstr(txt2);\n    delay_ms(4000);\n\n    LCD_clear_home();\n\n    for(s = 0; s &lt; 13; s++)\n    {\n        LCD_goto((1 + s), 0);\n        LCD_putchar(txt3[s]);\n        delay_ms(60);\n    }\n    for(s = 0; s &lt; 10; s++)\n    {\n        LCD_goto((3 + s), 1);\n        LCD_putchar(txt4[s]);\n        delay_ms(60);\n    }\n    delay_ms(4000);\n\n    s = 0;\n    LCD_clear_home();\n\n    LCD_goto(3, 0);\n    LCD_putstr(txt1);\n\n    while(1)\n    {\n        show_value(s);\n        s++;\n        delay_ms(400);\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_FLLREF,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initFLLSettle(MCLK_KHZ,\n                      MCLK_FLLREF_RATIO);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_REFOCLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid show_value(unsigned char value)\n{\n   unsigned char ch = 0x00;\n\n   ch = ((value \/ 100) + 0x30);\n   LCD_goto(6, 1);\n   LCD_putchar(ch);\n\n   ch = (((value \/ 10) % 10) + 0x30);\n   LCD_goto(7, 1);\n   LCD_putchar(ch);\n\n   ch = ((value % 10) + 0x30);\n   LCD_goto(8, 1);\n   LCD_putchar(ch);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"711\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/LCD-1024x711.png\" alt=\"\" class=\"wp-image-14557\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/LCD-1024x711.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/LCD-580x403.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/LCD-768x533.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/LCD.png 1169w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Since alphanumerical displays utilize GPIOs, there\u2019s hardly anything\nto explain here. Try not to use GPIOs that have alternate roles because you may\nnever know when would you need their alternative functions. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Most popularly alphanumerical LCDs are driven in 4-bit data mode and this is what that has been done here. First let\u2019s see some typical LCD instructions.  <br>Since alphanumerical displays utilize GPIOs, there\u2019s hardly anything to explain here. Try not to use GPIOs that have alternate roles because you may never know when would you need their alternative functions.  <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"949\" height=\"761\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/reg-map.png\" alt=\"\" class=\"wp-image-14558\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/reg-map.png 949w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/reg-map-580x465.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/reg-map-768x616.png 768w\" sizes=\"auto, (max-width: 949px) 100vw, 949px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Most popularly alphanumerical LCDs are driven in 4-bit data mode and this is what that has been done here. First let\u2019s see some typical LCD instructions.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#define LCD_RS_PORT           GPIO_PORT_P8\n#define LCD_RS_PIN            GPIO_PIN1\n\n#define LCD_EN_PORT           GPIO_PORT_P8\n#define LCD_EN_PIN            GPIO_PIN2\n\n#define LCD_D4_PORT           GPIO_PORT_P2\n#define LCD_D4_PIN            GPIO_PIN3\n\n#define LCD_D5_PORT           GPIO_PORT_P3\n#define LCD_D5_PIN            GPIO_PIN7\n\n#define LCD_D6_PORT           GPIO_PORT_P2\n#define LCD_D6_PIN            GPIO_PIN6\n\n#define LCD_D7_PORT           GPIO_PORT_P4\n#define LCD_D7_PIN            GPIO_PIN0<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This declaration in the LCD header file is very important as it\nstates GPIO pin purposes. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Initialization of the LCD is done by going through the steps in the following program flow graph and manipulating the LCD pins accordingly. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"780\" height=\"848\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/init.png\" alt=\"\" class=\"wp-image-14559\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/init.png 780w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/init-580x631.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/init-768x835.png 768w\" sizes=\"auto, (max-width: 780px) 100vw, 780px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"729\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/LCD-1024x729.jpg\" alt=\"\" class=\"wp-image-14560\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/LCD-1024x729.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/LCD-580x413.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/LCD-768x547.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/LCD.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/eydLbB-tdIc?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">2 Wire (Software I2C) LCD<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Alphanumerical LCDs need lot of pins (6 pins at least) for interfacing and in some cases, this is an expensive requirement. In such cases, hardware designs become complex and every pin is precious for their secondary roles. We can avoid this by using software-based I2C or SPI LCD drivers. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"451\" height=\"428\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/I2C-LCD.png\" alt=\"\" class=\"wp-image-14566\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">We can use I2C-based port expanders like PCF8574 or MCP23017 for this purpose. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>SW_I2C.h<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n\n#define SW_I2C_SDA_PORT GPIO_PORT_P8\n#define SW_I2C_SCL_PORT GPIO_PORT_P8\n\n#define SDA_pin         GPIO_PIN1\n#define SCL_pin         GPIO_PIN2\n\n#define SDA_DIR_OUT()   GPIO_setAsOutputPin(SW_I2C_SDA_PORT, SDA_pin)\n#define SDA_DIR_IN()    GPIO_setAsInputPin(SW_I2C_SDA_PORT, SDA_pin)\n#define SCL_DIR_OUT()   GPIO_setAsOutputPin(SW_I2C_SCL_PORT, SCL_pin)\n#define SCL_DIR_IN()    GPIO_setAsInputPin(SW_I2C_SCL_PORT, SCL_pin)\n\n#define SDA_HIGH()      GPIO_setOutputHighOnPin(SW_I2C_SDA_PORT, SDA_pin)\n#define SDA_LOW()       GPIO_setOutputLowOnPin(SW_I2C_SDA_PORT, SDA_pin)\n#define SCL_HIGH()      GPIO_setOutputHighOnPin(SW_I2C_SCL_PORT, SCL_pin)\n#define SCL_LOW()       GPIO_setOutputLowOnPin(SW_I2C_SCL_PORT, SCL_pin)\n\n#define SDA_IN()        GPIO_getInputPinValue(SW_I2C_SDA_PORT, SDA_pin)\n\n#define I2C_ACK         0xFF\n#define I2C_NACK        0x00\n\n#define I2C_timeout     1000\n\nvoid SW_I2C_init(void);\nvoid SW_I2C_start(void);\nvoid SW_I2C_stop(void);\nunsigned char SW_I2C_read(unsigned char ack);\nvoid SW_I2C_write(unsigned char value);\nvoid SW_I2C_ACK_NACK(unsigned char mode);\nunsigned char SW_I2C_wait_ACK(void);<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>SW_I2C.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"SW_I2C.h\"\n\nvoid SW_I2C_init(void)\n{\n    SDA_DIR_OUT();\n    SCL_DIR_OUT();\n    delay_ms(1);\n    SDA_HIGH();\n    SCL_HIGH();\n}\n\nvoid SW_I2C_start(void)\n{\n    SDA_DIR_OUT();\n    SDA_HIGH();\n    SCL_HIGH();\n    delay_us(4);\n    SDA_LOW();\n    delay_us(4);\n    SCL_LOW();\n}\n\nvoid SW_I2C_stop(void)\n{\n    SDA_DIR_OUT();\n    SDA_LOW();\n    SCL_LOW();\n    delay_us(4);\n    SDA_HIGH();\n    SCL_HIGH();\n    delay_us(4);\n}\n\nunsigned char SW_I2C_read(unsigned char ack)\n{\n    unsigned char i = 8;\n    unsigned char j = 0;\n\n    SDA_DIR_IN();\n\n    while(i &gt; 0)\n    {\n        SCL_LOW();\n        delay_us(2);\n        SCL_HIGH();\n        delay_us(2);\n        j &lt; 0)\n    {\n\n        if(((value &amp; 0x80) &gt;&gt; 7) != 0x00)\n        {\n            SDA_HIGH();\n        }\n        else\n        {\n            SDA_LOW();\n        }\n\n        value &lt; I2C_timeout)\n        {\n            SW_I2C_stop();\n            return 1;\n        }\n    };\n\n    SCL_LOW();\n    return 0;\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">PCF8574.h<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"SW_I2C.h\"\n\n#define PCF8574_address                 0x4E\n\n#define PCF8574_write_cmd               PCF8574_address\n#define PCF8574_read_cmd                (PCF8574_address + 1)\n\nvoid PCF8574_init(void);\nunsigned char PCF8574_read(void);\nvoid PCF8574_write(unsigned char data_byte);<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>PCF8574.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"PCF8574.h\"\n\nvoid PCF8574_init(void)\n{\n    SW_I2C_init();\n    delay_ms(100);\n}\n\nunsigned char PCF8574_read(void)\n{\n    unsigned char port_byte = 0;\n\n    SW_I2C_start();\n    SW_I2C_write(PCF8574_read_cmd);\n    port_byte = SW_I2C_read(I2C_NACK);\n    SW_I2C_stop();\n\n    return port_byte;\n}\n\nvoid PCF8574_write(unsigned char data_byte)\n{\n    SW_I2C_start();\n    SW_I2C_write(PCF8574_write_cmd);\n    SW_I2C_ACK_NACK(I2C_ACK);\n    SW_I2C_write(data_byte);\n    SW_I2C_ACK_NACK(I2C_ACK);\n    SW_I2C_stop();\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>lcd.h<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"PCF8574.h\"\n\n#define clear_display                                0x01\n#define goto_home                                    0x02\n         \n#define cursor_direction_inc                         (0x04 | 0x02)\n#define cursor_direction_dec                         (0x04 | 0x00)\n#define display_shift                                (0x04 | 0x01)\n#define display_no_shift                             (0x04 | 0x00)\n\n#define display_on                                   (0x08 | 0x04)\n#define display_off                                  (0x08 | 0x02)\n#define cursor_on                                    (0x08 | 0x02)\n#define cursor_off                                   (0x08 | 0x00)\n#define blink_on                                     (0x08 | 0x01)\n#define blink_off                                    (0x08 | 0x00)\n                                    \n#define _8_pin_interface                             (0x20 | 0x10)\n#define _4_pin_interface                             (0x20 | 0x00)\n#define _2_row_display                               (0x20 | 0x08)\n#define _1_row_display                               (0x20 | 0x00)\n#define _5x10_dots                                   (0x20 | 0x40)\n#define _5x7_dots                                    (0x20 | 0x00)\n\n#define BL_ON                                        1\n#define BL_OFF                                       0\n\n#define dly                                          2\n\n#define DAT                                          1\n#define CMD                                          0\n\nvoid LCD_init(void);\nvoid LCD_toggle_EN(void);\nvoid LCD_send(unsigned char value, unsigned char mode); \nvoid LCD_4bit_send(unsigned char lcd_data);            \nvoid LCD_putstr(char *lcd_string);\nvoid LCD_putchar(char char_data);\nvoid LCD_clear_home(void);\nvoid LCD_goto(unsigned char x_pos, unsigned char y_pos);<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>lcd.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"lcd.h\"\n\nstatic unsigned char bl_state;\nstatic unsigned char data_value;\n\nvoid LCD_init(void)\n{                       \n  PCF8574_init();\n  delay_ms(100);\n\n  bl_state = BL_ON;\n  data_value = 0x04;\n  PCF8574_write(data_value);\n\n  delay_ms(10);\n\n  LCD_send(0x33, CMD);\n  LCD_send(0x32, CMD);\n\n  LCD_send((_4_pin_interface | _2_row_display | _5x7_dots), CMD);         \n  LCD_send((display_on | cursor_off | blink_off), CMD);     \n  LCD_send((clear_display), CMD);         \n  LCD_send((cursor_direction_inc | display_no_shift), CMD);        \n}   \n\nvoid LCD_toggle_EN(void)\n{\n  data_value |= 0x04;\n  PCF8574_write(data_value);\n  delay_ms(dly);\n  data_value &amp;= 0xF9;\n  PCF8574_write(data_value);\n  delay_ms(dly);\n}\n   \n\nvoid LCD_send(unsigned char value, unsigned char mode)\n{\n  switch(mode)\n  {\n     case CMD:\n     {\n        data_value &amp;= 0xF4;\n        break;\n     }\n     case DAT:\n     {\n        data_value |= 0x01;\n        break;\n     }\n  }\n\n  switch(bl_state)\n  {\n     case BL_ON:\n     {\n        data_value |= 0x08;\n        break;\n     }\n     case BL_OFF:\n     {\n        data_value &amp;= 0xF7;\n        break;\n     }\n  }\n\n  PCF8574_write(data_value);\n  LCD_4bit_send(value);\n  delay_ms(dly);\n}\n    \n\nvoid LCD_4bit_send(unsigned char lcd_data)       \n{\n  unsigned char temp = 0x00;\n\n  temp = (lcd_data &amp; 0xF0);\n  data_value &amp;= 0x0F;\n  data_value |= temp;\n  PCF8574_write(data_value);\n  LCD_toggle_EN();\n\n  temp = (lcd_data &amp; 0x0F);\n  temp &lt;= 0x20) &amp;&amp; (char_data &lt;= 0x7F))\n  {\n    LCD_send(char_data, DAT);\n  }\n}\n\nvoid LCD_clear_home(void)\n{\n  LCD_send(clear_display, CMD);\n  LCD_send(goto_home, CMD);\n}\n\nvoid LCD_goto(unsigned char x_pos,unsigned char y_pos)\n{                                                   \n  if(y_pos == 0)    \n  {                              \n    LCD_send((0x80 | x_pos), CMD);\n  }\n  else \n  {                                              \n    LCD_send((0x80 | 0x40 | x_pos), CMD); \n  }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>main.c <\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"lcd.h\"\n\nvoid clock_init(void);\nvoid show_value(unsigned char value);\n\nvoid main(void)\n{\n    unsigned char s = 0x00;\n\n    char txt1[] = {\"MICROARENA\"};\n    char txt2[] = {\"SShahryiar\"};\n    char txt3[] = {\"MSP430F5529LP\"};\n    char txt4[] = {\"Launchpad!\"};\n\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n\n    LCD_init();\n\n    LCD_clear_home();\n\n    LCD_goto(3, 0);\n    LCD_putstr(txt1);\n    LCD_goto(3, 1);\n    LCD_putstr(txt2);\n    delay_ms(4000);\n\n    LCD_clear_home();\n\n    for(s = 0; s &lt; 13; s++)\n    {\n        LCD_goto((1 + s), 0);\n        LCD_putchar(txt3[s]);\n        delay_ms(60);\n    }\n    for(s = 0; s &lt; 10; s++)\n    {\n        LCD_goto((3 + s), 1);\n        LCD_putchar(txt4[s]);\n        delay_ms(60);\n    }\n    delay_ms(4000);\n\n    s = 0;\n    LCD_clear_home();\n\n    LCD_goto(3, 0);\n    LCD_putstr(txt1);\n\n    while(1)\n    {\n        show_value(s);\n        s++;\n        delay_ms(400);\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_FLLREF,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initFLLSettle(MCLK_KHZ,\n                      MCLK_FLLREF_RATIO);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_REFOCLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid show_value(unsigned char value)\n{\n   unsigned char ch = 0x00;\n\n   ch = ((value \/ 100) + 0x30);\n   LCD_goto(6, 1);\n   LCD_putchar(ch);\n\n   ch = (((value \/ 10) % 10) + 0x30);\n   LCD_goto(7, 1);\n   LCD_putchar(ch);\n\n   ch = ((value % 10) + 0x30);\n   LCD_goto(8, 1);\n   LCD_putchar(ch);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"577\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/2LCD-MPY32-ADC-1024x577.png\" alt=\"\" class=\"wp-image-14567\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/2LCD-MPY32-ADC-1024x577.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/2LCD-MPY32-ADC-580x327.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/2LCD-MPY32-ADC-768x433.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/2LCD-MPY32-ADC.png 1358w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The initialization and working procedure of the LCD module is\nnothing different from the first LCD example. The only exception is the fact\nthat a PCF8574 port expander is used to manipulate the LCD I\/Os instead of\ndirect host micro connection. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">PCF8574 from NXP is an I2C-based 8-bit port expander. With just two\nGPIO pins or I2C pins we can read and write a complete external 8-bit GPIO port.\nThis is what makes PCF8574 a GPIO expander. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Since we are yet to check out the hardware I2C option of MSP430F5529 micro, we will be using software-based I2C. The software I2C driver is coded in <em>SW_I2C<\/em>header and source files. The lines of code there are self-explanatory. All of the I2C operations are simulated by altering two GPIO pin states and using software delays. The important part, however, is the GPIO declarations and it is found in the following part of the <em>SW_I2C<\/em> header file. &nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#define SW_I2C_SDA_PORT            GPIO_PORT_P8\n#define SW_I2C_SCL_PORT            GPIO_PORT_P8\n\n#define SDA_pin                    GPIO_PIN1\n#define SCL_pin                    GPIO_PIN2<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We are not going to read our LCD module and so we don\u2019t need <em>PCF8574_read<\/em> function of PCF8574 library. We\u2019ll just need the write function. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void PCF8574_write(unsigned char data_byte)\n{\n    SW_I2C_start();\n    SW_I2C_write(PCF8574_write_cmd);\n    SW_I2C_ACK_NACK(I2C_ACK);\n    SW_I2C_write(data_byte);\n    SW_I2C_ACK_NACK(I2C_ACK);\n    SW_I2C_stop();\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We send the address and command of the PCF8574 module first and then we send the port states. Note that the port states are sent just like the first LCD example. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"652\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/I2C-LCD-1024x652.jpg\" alt=\"\" class=\"wp-image-14568\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/I2C-LCD-1024x652.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/I2C-LCD-580x369.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/I2C-LCD-768x489.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/I2C-LCD.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/jbVioP6Uh30?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">3 Wire (Software SPI) LCD<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Another way of driving alphanumerical LCDs is by using software SPI. Software SPI uses the same concept as in software I2C. The only exceptions here are an additional GPIO pin and the mode of communication. We can use shift registers like CD4094B or 74HC595 for this purpose. Both are equally fine. We can also use dedicated SPI-based port expander like Microchip\u2019s MCP23S17.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"447\" height=\"218\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/SPI-LCD.png\" alt=\"\" class=\"wp-image-14570\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Software SPI, as in this example, can be used to read\/write other SPI-compatible hardware. This is often a requirement when hardware SPI or its pins are inaccessible. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>lcd.h <\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n\n#define SDO_PORT                    GPIO_PORT_P8\n#define SCK_PORT                    GPIO_PORT_P8\n#define STB_PORT                    GPIO_PORT_P3\n\n#define SDO_pin                     GPIO_PIN1\n#define SCK_pin                     GPIO_PIN2\n#define STB_pin                     GPIO_PIN7\n\n#define SDO_DIR_OUT                 GPIO_setAsOutputPin(SDO_PORT, SDO_pin)\n#define SCK_DIR_OUT                 GPIO_setAsOutputPin(SCK_PORT, SCK_pin)\n#define STB_DIR_OUT                 GPIO_setAsOutputPin(STB_PORT, STB_pin)\n\n#define SDO_HIGH                    GPIO_setOutputHighOnPin(SDO_PORT, SDO_pin)\n#define SDO_LOW                     GPIO_setOutputLowOnPin(SDO_PORT, SDO_pin)\n#define SCK_HIGH                    GPIO_setOutputHighOnPin(SCK_PORT, SCK_pin)\n#define SCK_LOW                     GPIO_setOutputLowOnPin(SCK_PORT, SCK_pin)\n#define STB_HIGH                    GPIO_setOutputHighOnPin(STB_PORT, STB_pin)\n#define STB_LOW                     GPIO_setOutputLowOnPin(STB_PORT, STB_pin)\n\n#define clear_display               0x01\n#define goto_home                   0x02\n         \n#define cursor_direction_inc        (0x04 | 0x02)\n#define cursor_direction_dec        (0x04 | 0x00)\n#define display_shift               (0x04 | 0x01)\n#define display_no_shift            (0x04 | 0x00)\n\n#define display_on                  (0x08 | 0x04)\n#define display_off                 (0x08 | 0x02)\n#define cursor_on                   (0x08 | 0x02)\n#define cursor_off                  (0x08 | 0x00)\n#define blink_on                    (0x08 | 0x01)\n#define blink_off                   (0x08 | 0x00)\n                                    \n#define _8_pin_interface            (0x20 | 0x10)\n#define _4_pin_interface            (0x20 | 0x00)\n#define _2_row_display              (0x20 | 0x08)\n#define _1_row_display              (0x20 | 0x00)\n#define _5x10_dots                  (0x20 | 0x40)\n#define _5x7_dots                   (0x20 | 0x00)\n                                   \n#define dly                         1\n\n                                                                          \nvoid SIPO(void);\nvoid LCD_init(void);\nvoid LCD_command(unsigned char value);\nvoid LCD_send_data(unsigned char value); \nvoid LCD_4bit_send(unsigned char lcd_data);                                      \nvoid LCD_putstr(char *lcd_string);\nvoid LCD_putchar(char char_data);\nvoid LCD_clear_home(void);\nvoid LCD_goto(unsigned char x_pos, unsigned char y_pos);<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>lcd.c <\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"lcd.h\"\n\nstatic unsigned char data_value;\n\nvoid SIPO(void)\n{\n    unsigned char bit = 0x00;\n    unsigned char clk = 0x08;\n    unsigned char temp = 0x00;\n    \n    temp = data_value;\n    STB_LOW;\n    \n    while(clk &gt; 0)\n    {\n        bit = ((temp &amp; 0x80) &gt;&gt; 0x07);\n        bit &amp;= 0x01;\n\n        switch(bit)\n        {\n            case 0:\n            {\n                SDO_LOW;\n                break;\n            }\n            default:\n            {\n                SDO_HIGH;\n                break;\n            }\n\n        }\n\n        SCK_HIGH;\n\n        temp &lt;&lt;= 1;\n        clk--;\n\n        SCK_LOW;\n    }\n\n    STB_HIGH;\n}\n                              \n\nvoid LCD_init(void)\n{\n    SDO_DIR_OUT;\n    SCK_DIR_OUT;\n    STB_DIR_OUT;\n\n    data_value = 0x08;\n    SIPO();\n    delay_ms(10);\n    \n    data_value = 0x30;\n    SIPO();\n                              \n    data_value |= 0x08;\n    SIPO();\n    delay_ms(dly);\n    data_value &amp;= 0xF7;\n    SIPO();\n    delay_ms(dly); \n             \n    data_value = 0x30;\n    SIPO();\n                    \n    data_value |= 0x08;\n    SIPO();\n    delay_ms(dly);\n    data_value &amp;= 0xF7;\n    SIPO();\n    delay_ms(dly);\n\n    data_value = 0x30;\n    SIPO();\n\n    data_value |= 0x08;\n    SIPO();\n    delay_ms(dly);\n    data_value &amp;= 0xF7;\n    SIPO();\n    delay_ms(dly);\n\n    data_value = 0x20;\n    SIPO();\n                    \n    data_value |= 0x08;\n    SIPO();\n    delay_ms(dly);\n    data_value &amp;= 0xF7;\n    SIPO();\n    delay_ms(dly);\n\n    LCD_command(_4_pin_interface | _2_row_display | _5x7_dots);         \n    LCD_command(display_on | cursor_off | blink_off);     \n    LCD_command(clear_display);         \n    LCD_command(cursor_direction_inc | display_no_shift);        \n}   \n\nvoid LCD_command(unsigned char value)\n{                                   \n    data_value &amp;= 0xFB;\n    SIPO();\n    LCD_4bit_send(value);           \n}\n   \n\nvoid LCD_send_data(unsigned char value)\n{                               \n    data_value |= 0x04;\n    SIPO();\n    LCD_4bit_send(value);\n}  \n    \n\nvoid LCD_4bit_send(unsigned char lcd_data)       \n{\n    unsigned char temp = 0x00;\n    \n    temp = (lcd_data &amp; 0xF0);\n    data_value &amp;= 0x0F;\n    data_value |= temp;\n    SIPO();\n                                          \n    data_value |= 0x08;\n    SIPO();\n    delay_ms(dly);\n    data_value &amp;= 0xF7;\n    SIPO();\n    delay_ms(dly);\n\n    temp = (lcd_data &amp; 0x0F);\n    temp &lt;&lt;= 0x04;\n    data_value &amp;= 0x0F;\n    data_value |= temp;\n    SIPO();\n               \n    data_value |= 0x08;\n    SIPO();\n    delay_ms(dly);\n    data_value &amp;= 0xF7;\n    SIPO();\n    delay_ms(dly);\n}  \n\nvoid LCD_putstr(char *lcd_string)\n{\n    while (*lcd_string != '\\0')   \n    {\n        LCD_send_data(*lcd_string);\n        lcd_string++;\n    };\n}\n\nvoid LCD_putchar(char char_data)\n{\n    LCD_send_data(char_data);\n}\n\nvoid LCD_clear_home(void)\n{\n    LCD_command(clear_display);\n    LCD_command(goto_home);\n}\n\nvoid LCD_goto(unsigned char x_pos,unsigned char y_pos)\n{                                                   \n    if(y_pos == 0)    \n    {                              \n        LCD_command(0x80 | x_pos);\n    }\n    else \n    {                                              \n        LCD_command(0x80 | 0x40 | x_pos); \n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>main.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"lcd.h\"\n\nvoid clock_init(void);\nvoid show_value(unsigned char value);\n\nvoid main(void)\n{\n    unsigned char s = 0x00;\n\n    char txt1[] = {\"MICROARENA\"};\n    char txt2[] = {\"SShahryiar\"};\n    char txt3[] = {\"MSP430F5529LP\"};\n    char txt4[] = {\"Launchpad!\"};\n\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n\n    LCD_init();\n\n    LCD_clear_home();\n\n    LCD_goto(3, 0);\n    LCD_putstr(txt1);\n    LCD_goto(3, 1);\n    LCD_putstr(txt2);\n    delay_ms(4000);\n\n    LCD_clear_home();\n\n    for(s = 0; s &lt; 13; s++)\n    {\n        LCD_goto((1 + s), 0);\n        LCD_putchar(txt3[s]);\n        delay_ms(60);\n    }\n    for(s = 0; s &lt; 10; s++)\n    {\n        LCD_goto((3 + s), 1);\n        LCD_putchar(txt4[s]);\n        delay_ms(60);\n    }\n    delay_ms(4000);\n\n    s = 0;\n    LCD_clear_home();\n\n    LCD_goto(3, 0);\n    LCD_putstr(txt1);\n\n    while(1)\n    {\n        show_value(s);\n        s++;\n        delay_ms(400);\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_FLLREF,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initFLLSettle(MCLK_KHZ,\n                      MCLK_FLLREF_RATIO);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_REFOCLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid show_value(unsigned char value)\n{\n   unsigned char ch = 0x00;\n\n   ch = ((value \/ 100) + 0x30);\n   LCD_goto(6, 1);\n   LCD_putchar(ch);\n\n   ch = (((value \/ 10) % 10) + 0x30);\n   LCD_goto(7, 1);\n   LCD_putchar(ch);\n\n   ch = ((value % 10) + 0x30);\n   LCD_goto(8, 1);\n   LCD_putchar(ch);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"630\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/3LCD-1024x630.png\" alt=\"\" class=\"wp-image-14571\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/3LCD-1024x630.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/3LCD-580x357.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/3LCD-768x472.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/3LCD.png 1226w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">As with the past example, GPIO pins will be used to emulate software SPI. Thus, we need to declare them first. SDO pin is serial data out pin, SCK is SPI clock pin and lastly, STB is SPI strobe\/chip enable (CE)\/slave select (SS) pin. Though 74HC595 and CD4094B are functionally same, my favorite is CD4094B due to its wide voltage range. This is what I have used here and the SPI pins are named in its respect.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#define SDO_PORT                    GPIO_PORT_P8\n#define SCK_PORT                    GPIO_PORT_P8\n#define STB_PORT                    GPIO_PORT_P3\n\n#define SDO_pin                     GPIO_PIN1\n#define SCK_pin                     GPIO_PIN2\n#define STB_pin                     GPIO_PIN7\n\n\n#define SDO_DIR_OUT                 GPIO_setAsOutputPin(SDO_PORT, SDO_pin)\n#define SCK_DIR_OUT                 GPIO_setAsOutputPin(SCK_PORT, SCK_pin)\n#define STB_DIR_OUT                 GPIO_setAsOutputPin(STB_PORT, STB_pin)\n\n#define SDO_HIGH                    GPIO_setOutputHighOnPin(SDO_PORT, SDO_pin)\n#define SDO_LOW                     GPIO_setOutputLowOnPin(SDO_PORT, SDO_pin)\n#define SCK_HIGH                    GPIO_setOutputHighOnPin(SCK_PORT, SCK_pin)\n#define SCK_LOW                     GPIO_setOutputLowOnPin(SCK_PORT, SCK_pin)\n#define STB_HIGH                    GPIO_setOutputHighOnPin(STB_PORT, STB_pin)\n#define STB_LOW                     GPIO_setOutputLowOnPin(STB_PORT, STB_pin)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We will not be modifying any function of the LCD itself. It is same\nas like other LCD examples. This is why we will just be going through the software\nfunction responsible for port expansion. Function named <em>SPIO <\/em>is\nresponsible for serially taking data from host micro and providing 8-bit\nparallel output, hence the name SIPO. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Strobe pin is held low before serially shifting data one bit at a time. Data is shifted on every high to low transition of clock signal for 8 clock transitions, i.e. 8-bit of data is transferred. After shifting out 8 bits of data, the strobe pin is held high and at that moment the 8 output pins of CD4094B shift-register are updated. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void SIPO(void)\n{\n    unsigned char bit = 0x00;\n    unsigned char clk = 0x08;\n    unsigned char temp = 0x00;\n    \n    temp = data_value;\n    STB_LOW;\n    \n    while(clk &gt; 0)\n    {\n        bit = ((temp &amp; 0x80) &gt;&gt; 0x07);\n        bit &amp;= 0x01;\n\n        switch(bit)\n        {\n            case 0:\n            {\n                SDO_LOW;\n                break;\n            }\n            default:\n            {\n                SDO_HIGH;\n                break;\n            }\n        }\n\n        SCK_HIGH;\n\n        temp &lt;&lt;= 1;\n        clk--;\n\n        SCK_LOW;\n    }\n\n    STB_HIGH;\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"537\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/SPI-LCD-1024x537.jpg\" alt=\"\" class=\"wp-image-14572\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/SPI-LCD-1024x537.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/SPI-LCD-580x304.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/SPI-LCD-768x403.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/SPI-LCD.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/UPakLxBDb0E?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Low Power Modes (LPM) and External Interrupt <\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">At present era, the energy consumption of a device is\na very important part of its design. Low power consumption along with optimum\nperformance and long endurance are highly preferable aspects one can think of\nwhile crafting a new electronic product. With such in mind, MSP430s were\ndeveloped with low power consumption feature. In terms of power consumption, MSP430s\noffer six modes of operation with five being low power or sleep modes of\ndifferent consumption levels. In TI docs, low power modes are often simply\nreferred as <strong><em>LPMs<\/em><\/strong>. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">External interrupt is an important DIO input mode feature. It can break the continuity of a regular program flow, i.e. the main routine, and perform certain higher priority secondary tasks separately. Interrupts can be also used to wake up micros from low power sleep modes. Combinations of LPMs and external interrupts have many uses. A good example of such combinations is a wireless mouse. Unless moved or its buttons pressed, the mouse remains in dormant\/sleep state to conserve precious battery energy. The internal electronics of the mouse fires up otherwise as if it has been triggered by interrupts caused by motion or button presses. Port A (PA) pins of MSP430F5529 micro are all external interrupt capable pins. Shown below is the structure of a P1 port pin with red regions highlighting external interrupt resources:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"779\" height=\"596\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block.png\" alt=\"\" class=\"wp-image-14574\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block.png 779w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-580x444.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-768x588.png 768w\" sizes=\"auto, (max-width: 779px) 100vw, 779px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Apart from external interrupts, other interrupts like\ntimer interrupts can also wake up a MSP430F5529 from LPM states.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There are 5 LPM modes and an Active Mode of operation. The intent of\nthese modes is to change power consumption by suspending certain hardware and\nclocks. These are as follows:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><em>\u2022 Active mode (AM)<\/em><\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>All clocks are active.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><em>\u2022 Low-power mode 0 (LPM0)<\/em><\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>CPU and MCLK are disabled.<\/li><li>FLL loop control, ACLK and SMCLK remain active. <\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><em>\u2022 Low-power mode 1 (LPM1)<\/em><\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>CPU, MCLK and FLL loop control are disabled.<\/li><li>ACLK and SMCLK remain active.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><em>\u2022 Low-power mode 2 (LPM2)<\/em><\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>CPU, MCLK, FLL loop control and DCOCLK are disabled.<\/li><li>DC generator of the DCO remains enabled.<\/li><li>ACLK remains active<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><em>\u2022 Low-power mode 3 (LPM3)<\/em><\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>CPU, MCLK, FLL loop control, DC generator of the DCO and DCOCLK are\ndisabled.<\/li><li>ACLK remains active.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><em>\u2022 Low-power mode 4 (LPM4)<\/em><\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>CPU, ACLK, MCLK, FLL loop control, DC generator of the DCO and\nDCOCLK are disabled.<\/li><li>Crystal oscillator is stopped.<\/li><li>Complete data retention.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><em>\u2022 Low-power mode 4.5 (LPM4.5)<\/em><\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Internal regulator disabled.<\/li><li>No data retention.<\/li><li>Wake-up signal from RST or NMI, P1, and P2.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Wake up times from various LPM states also varies but these variations are so tiny in terms of time that they are rarely observed visually. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n\nunsigned char toggle = 0;\n\nvoid GPIO_init(void);\n\n#pragma vector = PORT1_VECTOR\n__interrupt void PORT1_ISR(void)\n{\n    LPM3_EXIT;\n\n    if(GPIO_getInterruptStatus(GPIO_PORT_P1,\n                               GPIO_PIN1) != 0)\n    {\n        GPIO_clearInterrupt(GPIO_PORT_P1,\n                            GPIO_PIN1);\n\n        toggle = 1;\n        _nop();\n    }\n}\n\nvoid main(void)\n{\n    unsigned char i = 0;\n    unsigned char j = 0;\n\n    WDT_A_hold(WDT_A_BASE);\n\n    GPIO_init();\n\n    while(1)\n    {\n        for(j = 0; j &lt; 10; j++)\n        {\n            GPIO_toggleOutputOnPin(GPIO_PORT_P1,\n                                   GPIO_PIN0);\n\n            __delay_cycles(1000000);\n        }\n\n        if(toggle)\n        {\n            for(i = 0; i &lt;= 9; i++)\n            {\n                GPIO_toggleOutputOnPin(GPIO_PORT_P4,\n                                       GPIO_PIN7);\n\n                __delay_cycles(100000);\n            }\n\n            toggle = 0;\n        }\n\n        LPM3;\n    };\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsOutputPin(GPIO_PORT_P1,\n                        GPIO_PIN0);\n\n    GPIO_setDriveStrength(GPIO_PORT_P1,\n                          GPIO_PIN0,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n\n    GPIO_setDriveStrength(GPIO_PORT_P4,\n                          GPIO_PIN7,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1,\n                                         GPIO_PIN1);\n\n    GPIO_clearInterrupt(GPIO_PORT_P1,\n                        GPIO_PIN1);\n\n    GPIO_selectInterruptEdge(GPIO_PORT_P1,\n                             GPIO_PIN1,\n                             GPIO_HIGH_TO_LOW_TRANSITION);\n\n    GPIO_enableInterrupt(GPIO_PORT_P1,\n                         GPIO_PIN1);\n\n    __enable_interrupt();\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"942\" height=\"690\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/EXTILPM-and-WDTA.png\" alt=\"\" class=\"wp-image-14575\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/EXTILPM-and-WDTA.png 942w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/EXTILPM-and-WDTA-580x425.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/EXTILPM-and-WDTA-768x563.png 768w\" sizes=\"auto, (max-width: 942px) 100vw, 942px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For this demo, on-board P1.1 button, P1.0 and P4.7 LEDs are used. The LEDs are set as in the GPIO example, i.e. as outputs. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">P1.1 button pin is set as input pin with pull-up resistor. This pin is also used as the external interrupt pin. At first, any pending interrupt is cleared. We, then, have to set interrupt edge, i.e. polarity sensitivity. Finally, we enable interrupt on the interrupt pin and enable global interrupt. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1);\n\nGPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN1);\n\nGPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN1, GPIO_HIGH_TO_LOW_TRANSITION);\n\nGPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN1);\n\n__enable_interrupt();<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now the button pin is ready to behave like an external interrupt pin\nrather than a regular input pin. Remember that P1 belongs to PA port and only\nPA port pins are interrupt capable.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s look at the main loop now. Here, we see that P1.0 LED will be\ntoggled 10 times first. The <em>if-condition<\/em> will not be initially executed\nsince it is linked with the external interrupt. Thus, the conditional statement\nwill be skipped and LPM3 condition will be set. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Once LPM is applied, everything seems to be suspended. P1.0 LED is supposed to keep flashing but that doesn\u2019t happen.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">for(j = 0; j &lt; 10; j++)\n{\n    GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);\n\n    __delay_cycles(1000000);\n}\n\nif(toggle)\n{\n    for(i = 0; i &lt;= 9; i++)\n    {\n        GPIO_toggleOutputOnPin(GPIO_PORT_P4, GPIO_PIN7);\n\n        __delay_cycles(100000);\n    }\n\n    toggle = 0;\n}\n\nLPM3;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When the button is pressed, external interrupt kicks in, LPM3 is exited, interrupt flag is cleared and variable <em>toggle<\/em> is set. Since there is one interrupt vector for the entire P1 port pins, it is needed to be sure which pin caused the interrupt. This is why the state of P1.1 needs to be checked right after interrupt.&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#pragma vector = PORT1_VECTOR\n__interrupt void PORT1_ISR(void)\n{\n    LPM3_EXIT;\n\n    if(GPIO_getInterruptStatus(GPIO_PORT_P1, GPIO_PIN1) != 0)\n    {\n        GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN1);\n\n        toggle = 1;\n        _nop();\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Since now the <em>toggle<\/em> variable is set, P1.0 LED flashes and then P4.7 LED flashes, indicating that an external interrupt has been processed. &nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"870\" height=\"1024\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/INT-870x1024.gif\" alt=\"\" class=\"wp-image-14576\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/INT-870x1024.gif 870w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/INT-552x650.gif 552w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/INT-768x904.gif 768w\" sizes=\"auto, (max-width: 870px) 100vw, 870px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/R9Wmk0dMdl4?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Internal Flash Memory and Cyclic Redundancy Check (CRC)\nModule<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">There are many microcontrollers in today\u2019s market that don\u2019t come with embedded EEPROM memory. Most ARM microcontrollers, for example, don\u2019t have EEPROM memories. EEPROM is typically used for the storage of non-volatile data like configurations, calibrations, etc that are usually not changed frequently and need to be retained even after reset\/power failure. EEPROM memories are slow and have lower endurance. Due to these limitations, it is better to use segments of flash memory that will not be used to hold application code. Flash memories have comparatively higher life cycles, high reliability and are faster. The only problem with them is writing. We can\u2019t write to individual locations. We have to write\/erase a whole segment of multiple byte areas at a time. No matter which memory class we are dealing with, frequent writing\/erasing of memory locations also leads to wear and permanent damage. These issues can be avoided by a number of software-based means like wear-leveling. Data reading has no issues as data can be read individually or as a whole. MSP430F5529 has four flash memory areas called information memory (<strong><em>A<\/em><\/strong> to <strong><em>D<\/em><\/strong>). Information memory is where we can store non-volatile data and these locations have no conflict with application\/main memory locations.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"445\" height=\"888\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Memory.png\" alt=\"\" class=\"wp-image-14578\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Memory.png 445w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Memory-326x650.png 326w\" sizes=\"auto, (max-width: 445px) 100vw, 445px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"> <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In MSP430F5529 micro, there is a Cyclic Redundancy Check (CRC) hardware. This hardware has several uses. Most commonly it is used to ensure or check data integrity against data corruption. In communications and data storage, CRC is highly needed since there is no other good and simple mean to cross-check data integrity efficiently and quickly. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">CRC is like an agreement\/encryption that two\/more\nparties agree upon. As an example, consider two people, <strong><em>A<\/em><\/strong> and <strong><em>B<\/em><\/strong>\nsharing a common safe. <strong><em>A<\/em><\/strong> leaves a message in the safe for <strong><em>B<\/em><\/strong>.\n<strong><em>B<\/em><\/strong> has to open the safe with the same kind of key that <strong><em>A<\/em><\/strong>\nused to lock the safe or else <strong><em>B<\/em><\/strong> won\u2019t get the message. Here the keys\nform the agreement that both of these persons agreed upon and the safe is the\nmethod to encapsulate the message from unwanted people. &nbsp;&nbsp;&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Modern communication and data storage use CRC just\nlike the example detailed above. CRC is an algorithm that tells dictates this\nencryption. Data is sent\/stored along with a CRC code. When the sent\/stored\ndata is received\/read along with the CRC content of the data, CRC is\nrecalculated and verified against the sent\/stored CRC. If both sent\/stored CRC\nand received\/read CRC match then it is safe to assume that no data corruption\nhas occurred. &nbsp;&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Shown below is the CRC module block diagram of MSP430F5529. The CRC module produces a signature for a given sequence of data values. The signature is generated through a feedback path from data bits 0, 4, 11, and 15. The CRC signature is based on the polynomial given in the CRC-CCITT-BR polynomial.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"998\" height=\"548\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/CRC-Module.png\" alt=\"\" class=\"wp-image-14579\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/CRC-Module.png 998w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/CRC-Module-580x318.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/CRC-Module-768x422.png 768w\" sizes=\"auto, (max-width: 998px) 100vw, 998px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"lcd.h\"\n#include \"lcd_print.h\"\n\n#define INFOA_START     0x1980\n#define INFOA_END       0x19FF\n\n#define INFOB_START     0x1900\n#define INFOB_END       0x197F\n\n#define INFOC_START     0x1880\n#define INFOC_END       0x18FF\n\n#define INFOD_START     0x1800\n#define INFOD_END       0x187F\n\nvoid clock_init(void);\nvoid GPIO_init(void);\nchar Flash_Read_Char(unsigned int address);\nunsigned int Flash_Read_Word(unsigned int address);\n\nvoid main(void)\n{\n    unsigned char s = 0x00;\n    unsigned char temp = 0x00;\n    unsigned char value[2] = {0x00, 0x00};\n    unsigned char set_values[4] = {33, 64, 99, 16};\n    unsigned int status = 0x0000;\n\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    GPIO_init();\n\n    LCD_init();\n    LCD_clear_home();\n\n    CRC_setSeed(CRC_BASE,\n                0xABCD);\n\n    CRC_set8BitData(CRC_BASE,\n                    Flash_Read_Char(INFOB_START));\n\n    temp = CRC_getResult(CRC_BASE);\n\n    LCD_goto(0, 0);\n    LCD_putstr(\"Checking CRC\");\n\n    LCD_goto(0, 1);\n    LCD_putstr(\"STO\");\n\n    LCD_goto(8, 1);\n    LCD_putstr(\"CRC\");\n\n    print_C(3, 1, Flash_Read_Char(INFOB_START + 1));\n    print_C(11, 1, temp);\n\n    delay_ms(1600);\n\n    LCD_clear_home();\n\n    LCD_goto(0, 0);\n    LCD_putstr(\"INFO A Seg.\");\n\n    if(temp != Flash_Read_Char(INFOB_START + 1))\n    {\n        do\n        {\n            FlashCtl_eraseSegment((unsigned char *)INFOB_START);\n\n            status = FlashCtl_performEraseCheck((unsigned char *)INFOB_START,\n                                                128);\n        }while (status == STATUS_FAIL);\n    }\n\n    if((GPIO_getInputPinValue(GPIO_PORT_P2,\n                              GPIO_PIN1) == false))\n    {\n        GPIO_setOutputHighOnPin(GPIO_PORT_P4,\n                                GPIO_PIN7);\n\n        FlashCtl_unlockInfoA();\n\n        do\n        {\n            FlashCtl_eraseSegment((unsigned char *)INFOA_START);\n\n            status = FlashCtl_performEraseCheck((unsigned char *)INFOA_START,\n                                                128);\n        }while (status == STATUS_FAIL);\n\n        FlashCtl_write8(set_values,\n                        (unsigned char *)INFOA_START,\n                        4);\n\n        FlashCtl_lockInfoA();\n\n        LCD_goto(0, 1);\n        LCD_putstr(\"Set: 33 64 99 16\");\n\n        delay_ms(3000);\n\n        GPIO_setOutputLowOnPin(GPIO_PORT_P4,\n                               GPIO_PIN7);\n    }\n\n    else\n    {\n        LCD_goto(0, 1);\n        LCD_putstr(\"Read\");\n\n        for(s = 0; s &lt; 4; s++)\n        {\n            temp = Flash_Read_Char(INFOA_START + s);\n            print_C(5, 1, s);\n            print_C(13, 1, temp);\n            delay_ms(2000);\n        }\n    }\n\n    LCD_clear_home();\n\n    LCD_goto(0, 0);\n    LCD_putstr(\"INFO B Seg.\");\n\n    temp = Flash_Read_Char(INFOB_START);\n    LCD_goto(0, 1);\n    LCD_putstr(\"WR: ---\");\n    LCD_goto(9, 1);\n    LCD_putstr(\"RD:\");\n    print_C(12, 1, temp);\n    delay_ms(2000);\n\n    temp = 0;\n\n    while(1)\n    {\n        if(GPIO_getInputPinValue(GPIO_PORT_P1,\n                                 GPIO_PIN1) == false)\n        {\n            while(GPIO_getInputPinValue(GPIO_PORT_P1,\n                                        GPIO_PIN1) == false);\n\n            print_C(3, 1, value[0]);\n\n            do\n            {\n                FlashCtl_eraseSegment((unsigned char *)INFOB_START);\n\n                status = FlashCtl_performEraseCheck((unsigned char *)INFOB_START,\n                                                    128);\n            }while (status == STATUS_FAIL);\n\n            CRC_setSeed(CRC_BASE,\n                        0xABCD);\n\n            CRC_set8BitData(CRC_BASE,\n                            value[0]);\n\n            value[1] = CRC_getResult(CRC_BASE);\n\n            FlashCtl_write8(value,\n                            (unsigned char *)INFOB_START,\n                            2);\n\n            GPIO_setOutputHighOnPin(GPIO_PORT_P4,\n                                    GPIO_PIN7);\n\n            delay_ms(1000);\n\n            GPIO_setOutputLowOnPin(GPIO_PORT_P4,\n                                   GPIO_PIN7);\n\n        }\n\n        delay_ms(20);\n\n        print_C(3, 1, value[0]);\n        value[0] = temp++;\n\n        delay_ms(200);\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_FLLREF,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initFLLSettle(MCLK_KHZ,\n                      MCLK_FLLREF_RATIO);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_2);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1,\n                                         GPIO_PIN1);\n\n    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2,\n                                         GPIO_PIN1);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P1,\n                        GPIO_PIN0);\n\n    GPIO_setDriveStrength(GPIO_PORT_P1,\n                          GPIO_PIN0,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n\n    GPIO_setDriveStrength(GPIO_PORT_P4,\n                          GPIO_PIN7,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n}\n\nchar Flash_Read_Char(unsigned int address)\n{\n    char value = 0x00;\n    char *FlashPtr = (char *)address;\n\n    value = *FlashPtr;\n\n    return value;\n}\n\nunsigned int Flash_Read_Word(unsigned int address)\n{\n    unsigned int value = 0x0000;\n    unsigned int *FlashPtr = (unsigned int *)address;\n\n    value = *FlashPtr;\n\n    return value;\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"622\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/CRCFlash-1024x622.png\" alt=\"\" class=\"wp-image-14580\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/CRCFlash-1024x622.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/CRCFlash-580x352.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/CRCFlash-768x467.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/CRCFlash.png 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The idea here is to use internal flash memory for storing non-volatile\nuser data and CRC module for verification of data integrity. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">MSP430F5529\u2019s flash memory is partitioned into main, information,\nand BSL memory sections. The main flash memory is used for storing application\ncode, BSL memory is used for storing bootloader and the information memory is\nused for storing non-volatile user data. Check the memory map shown below. Here\ntwo out of three types of flash memories are shown only. Different sizes of\ndata can be read\/written in flash memory but when erasing only segment-sized\nerase is possible. The segment size of main and BSL memories is 512 bytes and\nthe segment size of information memories is 128 bytes. Since information memory\nsegments are smaller than other flash memories, it is best suited for user data\nstorage for obvious memory segment size advantage. Lesser size means faster\noperation, lesser wear and efficient memory management. As mentioned before,\nfrequent writes\/erases wear memories and so it is a good practice not do either\nfrequently. Complex software-based wear-levelling techniques and using RAM-backed\nbuffers can be applied to reduce memory wears.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Segment A is a very important segment as it can be used to stores important\/critical internal calibration data, configurations and other important set points. This is why, it is protected and locked separately. It is wise to leave it and use the other three segments of information memory space to store user data that frequently change.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"441\" height=\"463\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Information-Memory.png\" alt=\"\" class=\"wp-image-14581\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Now let\u2019s see how the code works here. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Firstly, let us start by defining the location boundaries of the information memory segments. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#define INFOA_START     0x1980\n#define INFOA_END       0x19FF\n\n#define INFOB_START     0x1900\n#define INFOB_END       0x197F\n\n#define INFOC_START     0x1880\n#define INFOC_END       0x18FF\n\n#define INFOD_START     0x1800\n#define INFOD_END       0x187F<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">CRC check is done in the beginning of the code although at first run\nCRC check is invalid as no user data is initially stored. However, this comes\nto use when we reset or power up after saving our data. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For CRC module to work, we need to give a seed, i.e. a number in form of a key. Here it is arbitrarily set as <em>0XABCD<\/em>. CRC module uses this seed and given data to compute CRC result. After this we visually check if the stored CRC matches with the calculated CRC. The check is done in code too. The CRC values are stored in two locations of the B segment of information memory. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">CRC_setSeed(CRC_BASE, 0xABCD);\n\nCRC_set8BitData(CRC_BASE, Flash_Read_Char(INFOB_START));\n\ntemp = CRC_getResult(CRC_BASE);\n\nLCD_goto(0, 0);\nLCD_putstr(\"Checking CRC\");\n\nLCD_goto(0, 1);\nLCD_putstr(\"STO\");\n\nLCD_goto(8, 1);\nLCD_putstr(\"CRC\");\n\nprint_C(3, 1, Flash_Read_Char(INFOB_START + 1));\nprint_C(11, 1, temp);\n\n\ndelay_ms(1600);\n\nLCD_clear_home();\n\nLCD_goto(0, 0);\nLCD_putstr(\"INFO A Seg.\");\n\nif(temp != Flash_Read_Char(INFOB_START + 1))\n{\n    do\n    {\n        FlashCtl_eraseSegment((unsigned char *)INFOB_START);\n\n        status = FlashCtl_performEraseCheck((unsigned char *)INFOB_START,\n                                             128);\n     }while(status == STATUS_FAIL);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If the contents of both locations of Info B memory are different\nthen it is likely that the memories are corrupt\/empty and so an erase cycle is\nnecessary to wipe out inconsistent data. The entire Info B segment is erased.\nIf it is otherwise then the erase is not performed. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now let us put some simulated fixed data as if these data are set\npoints of some process or hardware. To set these data in Info A memory we have\nto push P2.1 button. First, the segment is unlocked and then an erase is\nperformed to get rid of old data. After the erase cycle, data (array named \u201c<em>set_values\u201d<\/em>)\nis stored and the flash segment is locked. The locking ensures that no other\noperation is possible with this memory unless unlocked. &nbsp;&nbsp; <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the P2.1 button is not pressed then stored data is\nsimply read. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Note no CRC check is performed for this segment. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">if((GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN1) == false))\n{\n    GPIO_setOutputHighOnPin(GPIO_PORT_P4, GPIO_PIN7);\n\n    FlashCtl_unlockInfoA();\n\n    do\n    {\n       FlashCtl_eraseSegment((unsigned char *)INFOA_START);\n\n       status = FlashCtl_performEraseCheck((unsigned char *)INFOA_START, 128);\n     }while (status == STATUS_FAIL);\n\n     FlashCtl_write8(set_values, (unsigned char *)INFOA_START, 4);\n\n     FlashCtl_lockInfoA();\n\n     LCD_goto(0, 1);\n     LCD_putstr(\"Set: 33 64 99 16\");\n\n     delay_ms(2600);\n\n     GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN7);\n    }\n\nelse\n{\n    LCD_goto(0, 1);\n    LCD_putstr(\"Read\");\n\n    for(s = 0; s &lt; 4; s++)\n    {\n        temp = Flash_Read_Char(INFOA_START + s);\n        print_C(5, 1, s);\n        print_C(13, 1, temp);\n        delay_ms(2000);\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">All of the tasks mentioned so far are done before the\nmain loop. In the main loop a value named <em>\u201ctemp\u201d<\/em> is incremented. When\nP1.1 button is pressed, the current value of <em>temp <\/em>is stored in Info B\nsegment. Since we cannot rewrite or overwrite a flash memory, we must perform\nan erase operation before storing new data. When a new data is stored, a CRC is\nalso performed with <em>0xABCD<\/em> as seed as in the beginning of the code. The\nnew data and CRC are saved in two different locations. These two values will be\nused for checking data integrity when the MSP430 micro resets or powers up\nnext. This is what we saw at the beginning of the code. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Note that there is no Info B locking unlocking feature. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">if(GPIO_getInputPinValue(GPIO_PORT_P1, GPIO_PIN1) == false)\n{\n   while(GPIO_getInputPinValue(GPIO_PORT_P1, GPIO_PIN1) == false);\n\n   print_C(3, 1, value[0]);\n\n   do\n   {\n       FlashCtl_eraseSegment((unsigned char *)INFOB_START);\n\n       status = FlashCtl_performEraseCheck((unsigned char *)INFOB_START, 128);\n    }while (status == STATUS_FAIL);\n\n    CRC_setSeed(CRC_BASE, 0xABCD);\n    \n    CRC_set8BitData(CRC_BASE, value[0]);\n\n    value[1] = CRC_getResult(CRC_BASE);\n\n    FlashCtl_write8(value, (unsigned char *)INFOB_START, 2);\n\n    GPIO_setOutputHighOnPin(GPIO_PORT_P4, GPIO_PIN7);\n\n    delay_ms(1000);\n\n    GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN7);\n}\n\ndelay_ms(20);\n\nprint_C(3, 1, value[0]);\nvalue[0] = temp++;\n\ndelay_ms(200);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"615\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-1-1024x615.jpg\" alt=\"\" class=\"wp-image-14582\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-1-1024x615.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-1-580x348.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-1-768x461.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-1-600x360.jpg 600w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-1.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"615\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-2-1024x615.jpg\" alt=\"\" class=\"wp-image-14583\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-2-1024x615.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-2-580x348.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-2-768x461.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-2-600x360.jpg 600w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-2.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"615\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-3-1024x615.jpg\" alt=\"\" class=\"wp-image-14584\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-3-1024x615.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-3-580x348.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-3-768x461.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-3-600x360.jpg 600w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"880\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-4-1024x880.jpg\" alt=\"\" class=\"wp-image-14585\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-4-1024x880.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-4-580x498.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-4-768x660.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Flash-CRC-4.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/EeHk4eZ3WEw?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Timer Overview<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">MSP430F5529 microcontroller has six timers divided in\nthree categories \u2013 General Purpose Timers like Timer A and Timer B, Watchdog\nTimer (WDT) and Real Time Clock (RTC). <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There are <\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>3 Timer As \u2013 T0A5, T1A3 and T2A3<\/li><li>1 Timer B \u2013 T0B7<\/li><li>1 WDT_A <\/li><li>1 RTC_A <\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The cut-away block diagram of MSP430F5529\u2019s internal peripherals shown below highlights these timers.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"643\" height=\"515\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Overview-1.png\" alt=\"\" class=\"wp-image-14586\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Overview-1.png 643w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Overview-1-580x465.png 580w\" sizes=\"auto, (max-width: 643px) 100vw, 643px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Timer A and Timer B are almost same with minor\ndifferences. Timer B offers better PWM options. As their names suggest, RTC_A and WDTA_A are\nspecialized timers for specific or special purposes. They can be alternatively\nused like regular timers with some limitations.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">These timers can be fed with bewildering number of\nclock combinations offered by the UCS. There are options for external sources\nin some cases too. The structures and the operations of all of these timers is\nsimilar to what we have seen in my <a href=\"http:\/\/embedded-lab.com\/blog\/category\/msp430-launchpad\/\">previous MSP430\ntutorial<\/a>. The only exception is the RTC_A module as this timer was not\navailable then. Before trying to use any timer, it is my recommendation to go\nthrough the driverlib files of the respective timer. This will enable visualizing\nwhat can and cannot be done with a given timer module. This also reduces time\nto read technical documents and datasheet. However, I will still recommend\nreading these docs should one want to master the timers. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Timer A and B are 16-bit general-purpose timers with\ncapture-compare (CC) modules. The CC modules can be used for either capturing waveforms\nor PWM\/waveform generations. If CC modules are not needed, these timers can be\nused for timing events and keeping track of time. &nbsp;In TI\u2019s literature, we will see that timers\nare named as <strong><em>TxYn<\/em><\/strong> where <strong><em>Y<\/em><\/strong> represents timer class\/category,\ni.e. Timer A, Timer B, etc, <strong><em>x<\/em><\/strong> represents timer number or\ninstantiation and <strong><em>n <\/em><\/strong>represents number of CC channels. Therefore, <strong><em>T0A5 <\/em><\/strong>means\n0<sup>th<\/sup> instantiation of Timer A having 5 CC channels or simply 0<sup>th<\/sup>\nA-type timer having 5 CC channels. Sometimes, the CC channels are ignored and\nthe timers are simply named like <strong><em>TA2<\/em><\/strong>. This naming states 2<sup>nd<\/sup>\ninstantiation of Timer A or simply 2<sup>nd<\/sup> A-type Timer. Thus, there is\na short naming format and a long naming format for general purpose timers.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">MSP430x5xxx and MSP430x6xxx family of\nmicrocontrollers have three types of RTCs and they vary slightly in some\nfeatures. MSP430F5529 has one RTC_A module which is the basic of all three\ntypes. RTC_A lacks battery-backup option unlike other RTCs. RTC_A is a special\ntimer with a 32-bit counter that is intended for time-keeping applications,\ni.e., clock and calendar. Since time-keeping needs to be very accurate, RTC has\nspecial hardware arrangements to take care of so. It is my personal\nrecommendation to use dedicated 32.768 kHz temperature-compensated crystal\noscillator (TCXO) as the source of RTC_A clock. This will ensure better\naccuracy and precision. It is a common problem for most RTCs to either lead ahead\nor lack behind actual time. RTC_A can also be used as a 32-bit timer if\ntime-keeping is not needed. However, there are no hardware CC channels with\nRTC_A. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">WDT_A is similar but more advanced than the WDT+ seen in my <a href=\"http:\/\/embedded-lab.com\/blog\/category\/msp430-launchpad\/\">previous MSP430 tutorial<\/a>. It has 8 timer intervals rather than 4. This special timer is primarily intended for avoiding erratic\/irresponsive behaviour in the event of an electromagnetic interference (EMI) or conditions that leave a micro into an unforeseen loop or other software issue. Again, this timer can be alternatively used like a regular timer if watchdog feature is not needed. However, this timer too doesn\u2019t have any CC channel.<\/p>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Free-Running Timer \u2013 TA0 <\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A free-running timer is a timer that is left to run on its own. It has limited uses in regular life as it is based on polling. Such timers are useful for generating random numbers, timer-based delay functions, etc. Any timer of a MSP430 microcontroller can be used for making such a timer.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"513\" height=\"573\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer_A.png\" alt=\"\" class=\"wp-image-14589\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n\nvoid clock_init(void);\nvoid GPIO_init(void);\nvoid timer_T0A5_init(void);\n\nvoid main(void)\n{\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    GPIO_init();\n    timer_T0A5_init();\n\n    while(1)\n    {\n        if(Timer_A_getCounterValue(__MSP430_BASEADDRESS_T0A5__) &gt;= 32768)\n        {\n            GPIO_setOutputLowOnPin(GPIO_PORT_P1,\n                                   GPIO_PIN0);\n\n            GPIO_setOutputHighOnPin(GPIO_PORT_P4,\n                                    GPIO_PIN7);\n        }\n        else\n        {\n            GPIO_setOutputHighOnPin(GPIO_PORT_P1,\n                                    GPIO_PIN0);\n\n            GPIO_setOutputLowOnPin(GPIO_PORT_P4,\n                                   GPIO_PIN7);\n        }\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_2);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_MCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_REFOCLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsOutputPin(GPIO_PORT_P1,\n                        GPIO_PIN0);\n\n    GPIO_setDriveStrength(GPIO_PORT_P1,\n                          GPIO_PIN0,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n\n    GPIO_setDriveStrength(GPIO_PORT_P4,\n                          GPIO_PIN7,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n}\n\nvoid timer_T0A5_init(void)\n{\n    Timer_A_initContinuousModeParam ContinuousModeParam =\n    {\n         TIMER_A_CLOCKSOURCE_SMCLK,\n         TIMER_A_CLOCKSOURCE_DIVIDER_1,\n         TIMER_A_TAIE_INTERRUPT_DISABLE,\n         TIMER_A_DO_CLEAR,\n         false\n    };\n\n    Timer_A_stop(__MSP430_BASEADDRESS_T0A5__);\n\n    Timer_A_clearTimerInterrupt(__MSP430_BASEADDRESS_T0A5__);\n\n    Timer_A_initContinuousMode(__MSP430_BASEADDRESS_T0A5__,\n                               &amp;ContinuousModeParam);\n\n    Timer_A_startCounter(__MSP430_BASEADDRESS_T0A5__,\n                         TIMER_A_CONTINUOUS_MODE);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"961\" height=\"685\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Free-Timer-RTC-Counter-WDT-Counter.png\" alt=\"\" class=\"wp-image-14590\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Free-Timer-RTC-Counter-WDT-Counter.png 961w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Free-Timer-RTC-Counter-WDT-Counter-580x413.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Free-Timer-RTC-Counter-WDT-Counter-768x547.png 768w\" sizes=\"auto, (max-width: 961px) 100vw, 961px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">On-board LED GPIOs are setup as outputs. It is same as with other examples. The interesting part for us here is the timer setup.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void timer_T0A5_init(void)\n{\n    Timer_A_initContinuousModeParam ContinuousModeParam =\n    {\n         TIMER_A_CLOCKSOURCE_SMCLK,\n         TIMER_A_CLOCKSOURCE_DIVIDER_1,\n         TIMER_A_TAIE_INTERRUPT_DISABLE,\n         TIMER_A_DO_CLEAR,\n         false\n    };\n    Timer_A_stop(__MSP430_BASEADDRESS_T0A5__);\n    Timer_A_clearTimerInterrupt(__MSP430_BASEADDRESS_T0A5__);\n    Timer_A_initContinuousMode(__MSP430_BASEADDRESS_T0A5__, &amp;ContinuousModeParam);\n    Timer_A_startCounter(__MSP430_BASEADDRESS_T0A5__, TIMER_A_CONTINUOUS_MODE);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For demoing free-running timer, i.e. timer without interrupt or CC channels, TA0 is used. Note it is driven by SMCLK. SMCLK\u2019s clock source is the internal 32 kHz REFOCLK oscillator. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">UCS_initClockSignal(UCS_SMCLK, UCS_REFOCLK_SELECT, UCS_CLOCK_DIVIDER_1);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">No divider is used and so we can roughly expect 32000 ticks per second. We would also want to clear past settings and disable timer interrupt since it is a no-interrupt timer example. Initially the timer is halted because we want to start it right after setting the timer up. Note that here the timer is set in continuous mode of operation. In continuous mode, the timer counts up from 0 to top value of 0xFFFF or 65535 and then rolls over to zero. Shown below are modes of operation of Timer A. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"149\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/timer-modes-1024x149.png\" alt=\"\" class=\"wp-image-14591\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/timer-modes-1024x149.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/timer-modes-580x84.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/timer-modes-768x112.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/timer-modes.png 1053w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">We want to have the on-board LEDs flash equally and alternatively. Since the timer is running at approximately 32 kHz, it will overflow in about 2 second time. To get the LEDs alter state every second, we have to divide 65535 timer count into two equal fractions and check the timer count on every main loop passes. It is checked if the timer count is 32678 or more, i.e. half of 65535. For one count fraction, i.e. from 0 to 32767, the red LED will be lit while the green LED will be off. The same goes for the other fraction, i.e. from 32768 to 65535 count, but the LEDs will be in different logic states.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">if(Timer_A_getCounterValue(__MSP430_BASEADDRESS_T0A5__) &gt;= 32768)\n{\n   GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);\n   GPIO_setOutputHighOnPin(GPIO_PORT_P4, GPIO_PIN7);\n}\n\nelse\n{\n    GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0); \n    GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN7);\n} <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"579\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Free-Running-1024x579.png\" alt=\"\" class=\"wp-image-14592\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Free-Running-1024x579.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Free-Running-580x328.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Free-Running-768x434.png 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/ZVoiIhzBDVg?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Timer Interrupt \u2013 TA1 <\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Timers become more useful when used with interrupts. At fixed intervals, interrupts occur and this process allows us to perform tasks that need periodic update. One common use of timer interrupt is to drive multiple seven segment displays. A timer is coded in such a way that its overflow interrupt triggers every millisecond. During this time, one seven segment display is updated. Since one millisecond interval is a very short duration for human vision to notice, we can update several seven segment displays in a matter of few milliseconds and our eyes will see that all displays have been simultaneously updated. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"794\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Arduino-Duemilanove-Tick-Tock-Shield-Demo-Time-Display-1024x794.jpg\" alt=\"\" class=\"wp-image-14593\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Arduino-Duemilanove-Tick-Tock-Shield-Demo-Time-Display-1024x794.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Arduino-Duemilanove-Tick-Tock-Shield-Demo-Time-Display-580x450.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Arduino-Duemilanove-Tick-Tock-Shield-Demo-Time-Display-768x596.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Arduino-Duemilanove-Tick-Tock-Shield-Demo-Time-Display.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n\n#define GATE_HIGH                   GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN2)\n#define GATE_LOW                    GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN2)\n\n#define CLK_HIGH                    GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN1)\n#define CLK_LOW                     GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN1)\n\n#define A_HIGH                      GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN6)\n#define A_LOW                       GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN6)\n\n#define B_HIGH                      GPIO_setOutputHighOnPin(GPIO_PORT_P4, GPIO_PIN0)\n#define B_LOW                       GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN0)\n\n#define C_HIGH                      GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN3)\n#define C_LOW                       GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN3)\n\n#define D_HIGH                      GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN7)\n#define D_LOW                       GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN7)\n\n#define SW                          GPIO_getInputPinValue(GPIO_PORT_P3, GPIO_PIN1)\n\n#define top_seg                     4\n#define bot_seg                     0\n\n#define HIGH                        true\n#define LOW                         false\n\nconst unsigned char num[0x0A] = {0xED, 0x21, 0x8F, 0xAB, 0x63, 0xEA, 0xEE, 0xA1, 0xEF, 0xEB};\nunsigned char data_values[0x09] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n\nunsigned char n = 0x00;\nunsigned char SW_in = 0x00;\n\nvoid clock_init(void);\nvoid GPIO_init(void);\nvoid timer_T1A1_init(void);\nvoid write_74HC164(register unsigned char value);\nvoid write_74HC145(register unsigned char channel);\nvoid show_LEDs(unsigned char LED1_state, unsigned char LED2_state, unsigned char LED3_state, unsigned char LED4_state);\nvoid show_numbers(signed int value, unsigned char pos);\n\n#pragma vector = TIMER1_A1_VECTOR\n__interrupt void Timer_A_ISR(void)\n{\n    Timer_A_clearTimerInterrupt(TIMER_A1_BASE);\n\n    write_74HC164(data_values[n]);\n    write_74HC145(n);\n\n    n++;\n\n    if(n &gt; 9)\n    {\n      n = 0;\n    }\n}\n\nvoid main(void)\n{\n    signed int i = 0;\n    signed int j = 9999;\n\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    GPIO_init();\n    timer_T1A1_init();\n\n    while(true)\n    {\n        switch(SW_in)\n        {\n             case 1:\n             {\n                 show_LEDs(1, 0, 0, 0);\n                 break;\n             }\n\n             case 2:\n             {\n                 show_LEDs(0, 1, 0, 0);\n                 break;\n             }\n\n             case 3:\n             {\n                 show_LEDs(0, 0, 1, 0);\n                 break;\n             }\n\n             case 4:\n             {\n                 show_LEDs(0, 0, 0, 1);\n                 break;\n             }\n        }\n\n        SW_in = 0x00;\n\n        i++;\n        j--;\n\n        if(i &gt; 9999)\n        {\n            i = 0;\n            j = 9999;\n        }\n\n        show_numbers(i, bot_seg);\n        show_numbers(j, top_seg);\n\n        delay_ms(100);\n        show_LEDs(0, 0, 0, 0);\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_2);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_MCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsInputPin(GPIO_PORT_P3,\n                       GPIO_PIN1);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P2,\n                        GPIO_PIN3);\n    GPIO_setDriveStrength(GPIO_PORT_P2,\n                          GPIO_PIN3,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P2,\n                        GPIO_PIN6);\n\n    GPIO_setDriveStrength(GPIO_PORT_P2,\n                          GPIO_PIN6,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P3,\n                        GPIO_PIN7);\n\n    GPIO_setDriveStrength(GPIO_PORT_P3,\n                          GPIO_PIN7,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN0);\n\n    GPIO_setDriveStrength(GPIO_PORT_P4,\n                          GPIO_PIN0,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P8,\n                        GPIO_PIN1);\n\n    GPIO_setDriveStrength(GPIO_PORT_P8,\n                          GPIO_PIN1,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P8,\n                        GPIO_PIN2);\n\n    GPIO_setDriveStrength(GPIO_PORT_P8,\n                          GPIO_PIN2,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n}\n\nvoid timer_T1A1_init(void)\n{\n    Timer_A_initUpModeParam UpModeParam = {0};\n\n    UpModeParam.clockSource = TIMER_A_CLOCKSOURCE_ACLK;\n    UpModeParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;\n    UpModeParam.timerPeriod = 9999;\n    UpModeParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE;\n    UpModeParam.captureCompareInterruptEnable_CCR0_CCIE =                                                                      \n                                      TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;\n    UpModeParam.timerClear = TIMER_A_DO_CLEAR;\n    UpModeParam.startTimer = true;\n\n    Timer_A_initUpMode(TIMER_A1_BASE,\n                       &amp;UpModeParam);\n\n    Timer_A_startCounter(TIMER_A1_BASE,\n                         TIMER_A_UP_MODE);\n\n    __enable_interrupt();\n}\n\nvoid write_74HC164(register unsigned char value)\n{\n  register unsigned char s = 0x08;\n\n  while(s &gt; 0)\n  {\n        if((value &amp; 0x80) != 0x00)\n        {\n            GATE_HIGH;\n        }\n        else\n        {\n            GATE_LOW;\n        }\n\n        CLK_HIGH;\n        CLK_LOW;\n\n        value &lt;= 0) &amp;&amp; (value  9) &amp;&amp; (value  99) &amp;&amp; (value  999) &amp;&amp; (value &lt;= 9999))\n  {\n    ch = (value % 10);\n    data_values[(0 + pos)] = num[ch];\n    ch = ((value \/ 10) % 10);\n    data_values[(1 + pos)] = num[ch];\n    ch = ((value \/ 100) % 10);\n    data_values[(2 + pos)] = num[ch];\n    ch = (value \/ 1000);\n    data_values[(3 + pos)] = num[ch];\n  }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"944\" height=\"656\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/tmr_int.png\" alt=\"\" class=\"wp-image-14594\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/tmr_int.png 944w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/tmr_int-580x403.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/tmr_int-768x534.png 768w\" sizes=\"auto, (max-width: 944px) 100vw, 944px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Timer interrupt is best understood by using it to scan multiple seven segment displays and buttons. This time timer TA1 is used. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void timer_T1A1_init(void)\n{\n    Timer_A_initUpModeParam UpModeParam = {0};\n\n    UpModeParam.clockSource = TIMER_A_CLOCKSOURCE_ACLK;\n    UpModeParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;\n    UpModeParam.timerPeriod = 9999;\n    UpModeParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE;\n    UpModeParam.captureCompareInterruptEnable_CCR0_CCIE =        \n                                          TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;\n    UpModeParam.timerClear = TIMER_A_DO_CLEAR;\n    UpModeParam.startTimer = true;\n\n    Timer_A_initUpMode(TIMER_A1_BASE, &amp;UpModeParam);\n\n    Timer_A_startCounter(TIMER_A1_BASE, TIMER_A_UP_MODE);\n\n    __enable_interrupt();\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Timer TA1 is clocked with ACLK which in turn is being feed with 4MHz XT2CLK source. No divider is used at any stage and so, the timer will tick every 0.25\u00b5s. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">UCS_initClockSignal(UCS_ACLK, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_1);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We wish to have a time period of 2.5 ms and thus, here we will be using the timer in up mode with a top value of 9999, i.e. 10000 counts. Up mode is similar to previously seen continuous mode. The only difference is the fact that in continuous mode the top value of a timer is fixed at 65535 count while in up mode, the top value can be set to anything between 0 to 65535. The timer will count from 0 to 9999, i.e. there are 10000 ticks before timer overflow. Since one tick is 0.25 \u00b5s, 10000 ticks equal 2.5 ms (0.25 \u00b5s x 10000 = 2.5 ms). <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We will only need timer interrupt. We won\u2019t be using any\ncapture-compare interrupt and so we have to disable it. As with previous\nexamples we have to clear any past setting although there is none. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After setting up the timer\u2019s settings, we will just start it and enable global interrupt as to begin time count. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now let\u2019s see what\u2019s being done inside the timer interrupt? According to the schematic and objective of this project, we need to update all seven segment displays and read the 4-bit keypad so quickly as if everything appears to work in real time and without any lag. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#pragma vector = TIMER1_A1_VECTOR\n__interrupt void Timer_A_ISR(void)\n{\n    Timer_A_clearTimerInterrupt(TIMER_A1_BASE);\n\n    write_74HC164(data_values[n]);\n    write_74HC145(n);\n\n    n++;\n\n    if(n &gt; 9)\n    {\n      n = 0;\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Inside timer interrupt subroutine, both logic ICs are updated. Firstly, the number to be displayed is sent to the 74HC164 IC and then the seven-segment display to show the number is updated by writing the 74HC145 IC. At every interrupt, one seven segment display is updated. There are 8 such displays and so it takes about 20 ms to update all of these displays. During this time the keypad is also scanned in the main loop. With different key presses, different LEDs light up. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">switch(SW_in)\n{\n       case 1:\n        {\n            show_LEDs(1, 0, 0, 0);\n            break;\n        }\n        case 2:\n        {\n             show_LEDs(0, 1, 0, 0);\n             break;\n        }\n  case 3:\n        {\n             show_LEDs(0, 0, 1, 0);\n             break;\n        }\n  case 4:\n         {\n             show_LEDs(0, 0, 0, 1);\n             break;\n         }\n}\n\nSW_in = 0x00;<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"736\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-ISR-1024x736.jpg\" alt=\"\" class=\"wp-image-14596\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-ISR-1024x736.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-ISR-580x417.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-ISR-768x552.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-ISR.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/SXanUMbreIs?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Single Pulse Width Module (PWM) \u2013 TA2 <\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">PWM is an output feature of timers\u2019 CC channels. Pulse width modulation (PWM) is needed in crafting switch-mode power supplies, inverters, motor controllers, servos and many other devices. PWM can also be used to generate analogue output similar to a Digital-to-Analogue Converter (DAC). In this example, we will see how we can use a single PWM channel to drive a servo motor.&nbsp; <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"558\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Pololus-Micro-Maestro-Controller-1024x558.jpg\" alt=\"\" class=\"wp-image-14606\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Pololus-Micro-Maestro-Controller-1024x558.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Pololus-Micro-Maestro-Controller-580x316.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Pololus-Micro-Maestro-Controller-768x419.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Pololus-Micro-Maestro-Controller.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n\n#define INC         1\n#define DEC         0\n\nvoid clock_init(void);\nvoid GPIO_init(void);\nvoid timer_T2A3_init(void);\n\nvoid main(void)\n{\n    unsigned char dir = INC;\n    unsigned int r = 0;\n\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    GPIO_init();\n    timer_T2A3_init();\n\n    while(true)\n    {\n        if((r  0) &amp;&amp; (dir == DEC))\n        {\n            r--;\n        }\n\n        if((r == 0) &amp;&amp; (dir == DEC))\n        {\n            dir = INC;\n        }\n\n        Timer_A_setCompareValue(TIMER_A2_BASE,\n                                TIMER_A_CAPTURECOMPARE_REGISTER_1,\n                                (1000 + r));\n\n        delay_ms(2);\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_MCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_2);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P2,\n                                                GPIO_PIN4);\n}\n\nvoid timer_T2A3_init(void)\n{\n    Timer_A_outputPWMParam outputPWMParam = {0};\n\n    outputPWMParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;\n    outputPWMParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_2;\n    outputPWMParam.timerPeriod = 20000;\n    outputPWMParam.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;\n    outputPWMParam.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;\n    outputPWMParam.dutyCycle = 0;\n\n    Timer_A_outputPWM(TIMER_A2_BASE,\n                      &amp;outputPWMParam);\n\n    Timer_A_setCompareValue(TIMER_A2_BASE,\n                            TIMER_A_CAPTURECOMPARE_REGISTER_1,\n                            1000);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"581\" height=\"629\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PWM_Single.png\" alt=\"\" class=\"wp-image-14598\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PWM_Single.png 581w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PWM_Single-580x628.png 580w\" sizes=\"auto, (max-width: 581px) 100vw, 581px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">As mentioned, the goal of this demo is to drive a regular servo motor using a single PWM pin of MSP430F5529. Firstly, it must be noted that PWM or Capture-Compare function is a secondary function of GPIO pins. Thus, to use a PWM pin, it must be declared as Output Peripheral Module Function pin.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P2, GPIO_PIN4);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Typical servos have a timing as shown below:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"448\" height=\"590\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/servo-timing.png\" alt=\"\" class=\"wp-image-14599\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Note that every pulse has a period of 20ms. However, the high time\nvaries from 5 &#8211; 10%, i.e. the duty cycle of the PWM should be between 5 \u2013 10%\nin order to rotate the servo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This time TA2 is used. We could have used Timer B as it is better suited for PWM. This won\u2019t matter much though for this example. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void timer_T2A3_init(void)\n{\n    Timer_A_outputPWMParam outputPWMParam = {0};\n\n    outputPWMParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;\n    outputPWMParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_2;\n    outputPWMParam.timerPeriod = 20000;\n    outputPWMParam.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;\n    outputPWMParam.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;\n    outputPWMParam.dutyCycle = 0;\n\n    Timer_A_outputPWM(TIMER_A2_BASE, &amp;outputPWMParam);\n\n    Timer_A_setCompareValue(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_1, 1000);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">SMCLK is again used to clock the timer but this time it is scaled by a factor of 2. SMCLK will thus have a frequency of 2MHz as it is feed with 4MHz XT2_CLK. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">UCS_initClockSignal(UCS_SMCLK, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_2);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Inside the timer, this incoming clock signal is further divided by 2 and so the timer will tick at every 1\u00b5s. Like up mode, the top value or max PWM duty cycle is set to 20000. This means that the period of the PWM will be 20000 \u00b5s or 20 ms. Initially, the duty cycle is set to 0ms and the output mode is set to reset-set mode. Different output modes of MSP430\u2019s PWM are shown below.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"420\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/timer-PWM-modes-1024x420.png\" alt=\"\" class=\"wp-image-14600\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/timer-PWM-modes-1024x420.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/timer-PWM-modes-580x238.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/timer-PWM-modes-768x315.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/timer-PWM-modes.png 1056w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">After setting the PWM parameters, the timer and its PWM are started. Initially the pulse high time is set to 1 ms, i.e. the servo will at 0\u00b0 (-90\u00b0) position. We want the servo to rotate back and forth, i.e. from 0\u00b0 (-90\u00b0) to 180\u00b0 (+90\u00b0). To do this, we have to increase and decrease the pulse high time in the main loop.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">if((r  0) &amp;&amp; (dir == DEC))\n{\n    r--;\n}\nif((r == 0) &amp;&amp; (dir == DEC))\n{\n   dir = INC;\n}\nTimer_A_setCompareValue(TIMER_A2_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1, (1000 + r));\n\ndelay_ms(2);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The line below is responsible of duty cycle variation:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Timer_A_setCompareValue(TIMER_A2_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1, (1000 + r));<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It states which timer it is, which channel it is and the duty cycle of that channel. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"479\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PWM-Single-1-1024x479.jpg\" alt=\"\" class=\"wp-image-14602\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PWM-Single-1-1024x479.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PWM-Single-1-580x272.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PWM-Single-1-768x360.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PWM-Single-1.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"417\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PWM-Single-2-1024x417.jpg\" alt=\"\" class=\"wp-image-14603\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PWM-Single-2-1024x417.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PWM-Single-2-580x236.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PWM-Single-2-768x312.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PWM-Single-2.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/eDl7YJNfCO0?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Multiple Pulse Width Module (PWM) \u2013 TA0 <\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Single PWM is useful for simple purposes but in many applications, we need multiple PWMs. In case of inverters, MOSFET\/IGBT drives and bridges, there is no alternative other than to use multi-channel PWM. In this example, we will see how we can use multiple PWM to drive an RGB LED. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"648\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/output_bzvo9g-1024x648.gif\" alt=\"\" class=\"wp-image-14607\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/output_bzvo9g-1024x648.gif 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/output_bzvo9g-580x367.gif 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/output_bzvo9g-768x486.gif 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n\n#define steps 32\n\nvoid clock_init(void);\nvoid GPIO_init(void);\nvoid timer_T0A5_init(void);\n\nvoid main(void)\n{\n    unsigned char i = 0x00;\n\n    const unsigned int duty1_value[steps] = {0, \n                                             6424, \n                                             12786, \n                                             19026, \n                                             25082, \n                                      30896, \n                                      36413, \n                                      41579, \n                                      46344, \n                                             50664,             \n                                             54494, \n                                             57801, \n                                             60550, \n                                             62716, \n                                             64278,                                                \n                                             65220, \n                                             65534, \n                                             65218, \n                                             64272, \n                                             62708, \n                                             60540,\n                                             57788, \n                                             54480, \n                                             50647, \n                                             46326, \n                                             41558, \n                                             36391, \n                                             30873, \n                                             25057, \n                                             19000, \n                                             12760, \n                                             6397};\n\n    const unsigned int duty2_value[steps] = {57801, \n                                             60550, \n                                             62716, \n                                             64278,                                                \n                                             65220, \n                                             65534, \n                                             65218, \n                                             64272, \n                                             62708, \n                                             60540,\n                                             57788, \n                                             54480, \n                                             50647, \n                                             46326, \n                                             41558, \n                                             36391, \n                                             30873, \n                                             25057, \n                                             19000, \n                                             12760, \n                                             6397, \n                                             0, \n                                             6424, \n                                             12786, \n                                             19026, \n                                             25082, \n                                      30896, \n                                      36413, \n                                      41579, \n                                      46344, \n                                             50664,             \n                                             54494};\n\n    const unsigned int duty3_value[steps] = {57788, \n                                             54480, \n                                             50647, \n                                             46326, \n                                             41558, \n                                             36391, \n                                             30873, \n                                             25057, \n                                             19000, \n                                             12760, \n                                             6397, \n                                             0, \n                                             6424, \n                                             12786, \n                                             19026, \n                                             25082, \n                                      30896, \n                                      36413, \n                                      41579, \n                                      46344, \n                                             50664,             \n                                             54494,\n                                             57801, \n                                             60550, \n                                             62716, \n                                             64278,                                                \n                                             65220, \n                                             65534, \n                                             65218, \n                                             64272, \n                                             62708, \n                                             60540};\n\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    GPIO_init();\n    timer_T0A5_init();\n\n    while(true)\n    {\n        for(i = 0; i &lt; steps; i++)\n        {\n            Timer_A_setCompareValue(TIMER_A0_BASE,\n                                    TIMER_A_CAPTURECOMPARE_REGISTER_1,\n                                    duty1_value[i]);\n\n            Timer_A_setCompareValue(TIMER_A0_BASE,\n                                    TIMER_A_CAPTURECOMPARE_REGISTER_2,\n                                    duty2_value[i]);\n\n            Timer_A_setCompareValue(TIMER_A0_BASE,\n                                    TIMER_A_CAPTURECOMPARE_REGISTER_3,\n                                    duty3_value[i]);\n\n            delay_ms(250);\n        }\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_MCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P1,\n                                                (GPIO_PIN2 + GPIO_PIN3 + GPIO_PIN4));\n}\n\nvoid timer_T0A5_init(void)\n{\n    Timer_A_initCompareModeParam CompareModeParam1 = {0};\n    Timer_A_initCompareModeParam CompareModeParam2 = {0};\n    Timer_A_initCompareModeParam CompareModeParam3 = {0};\n\n    Timer_A_initContinuousModeParam ContinuousModeParam = {0};\n\n    ContinuousModeParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;\n    ContinuousModeParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;\n    ContinuousModeParam.timerClear = TIMER_A_DO_CLEAR;\n    ContinuousModeParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;\n    ContinuousModeParam.startTimer = false;\n\n    CompareModeParam1.compareInterruptEnable = TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;\n    CompareModeParam1.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;\n    CompareModeParam1.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;\n    CompareModeParam1.compareValue = 0;\n\n    CompareModeParam2.compareInterruptEnable = TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;\n    CompareModeParam2.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;\n    CompareModeParam2.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_2;\n    CompareModeParam2.compareValue = 0;\n\n    CompareModeParam3.compareInterruptEnable = TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;\n    CompareModeParam3.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;\n    CompareModeParam3.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_3;\n    CompareModeParam3.compareValue = 0;\n\n    Timer_A_initCompareMode(TIMER_A0_BASE,\n                            &amp;CompareModeParam1);\n\n    Timer_A_initCompareMode(TIMER_A0_BASE,\n                            &amp;CompareModeParam2);\n\n    Timer_A_initCompareMode(TIMER_A0_BASE,\n                            &amp;CompareModeParam3);\n\n    Timer_A_initContinuousMode(TIMER_A0_BASE,\n                               &amp;ContinuousModeParam);\n\n    Timer_A_startCounter(TIMER_A0_BASE,\n                         TIMER_A_CONTINUOUS_MODE);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"595\" height=\"755\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PWM_Multi.png\" alt=\"\" class=\"wp-image-14608\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PWM_Multi.png 595w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/PWM_Multi-512x650.png 512w\" sizes=\"auto, (max-width: 595px) 100vw, 595px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Multi-PWM example here uses the same concepts as in the single PWM example. This time timer TA0 is used and the following pins are set for PWM output:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P1,\n                                            (GPIO_PIN2 + GPIO_PIN3 + GPIO_PIN4));<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Note that this timer has 5 CC channels associated with it but we are\nusing only three of them since we have connected an RGB LED to these pins.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">4MHz XT2CLK source feeds SMCLK which in turn is used to run timer TA0. Thus, timer TA0 is operating at 4MHz speed.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">UCS_initClockSignal(UCS_SMCLK, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_1);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Timer PWM setup is not very much different. The only differences are timer mode, the number of channels and their individual settings. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void timer_T0A5_init(void)\n{\n    Timer_A_initCompareModeParam CompareModeParam1 = {0};\n    Timer_A_initCompareModeParam CompareModeParam2 = {0};\n    Timer_A_initCompareModeParam CompareModeParam3 = {0};\n\n    Timer_A_initContinuousModeParam ContinuousModeParam = {0};\n\n    ContinuousModeParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;\n    ContinuousModeParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;\n    ContinuousModeParam.timerClear = TIMER_A_DO_CLEAR;\n    ContinuousModeParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;\n    ContinuousModeParam.startTimer = false;\n\n    CompareModeParam1.compareInterruptEnable = TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;\n    CompareModeParam1.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;\n    CompareModeParam1.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;\n    CompareModeParam1.compareValue = 0;\n\n    CompareModeParam2.compareInterruptEnable = TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;\n    CompareModeParam2.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;\n    CompareModeParam2.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_2;\n    CompareModeParam2.compareValue = 0;\n\n    CompareModeParam3.compareInterruptEnable = TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;\n    CompareModeParam3.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;\n    CompareModeParam3.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_3;\n    CompareModeParam3.compareValue = 0;\n\n    Timer_A_initCompareMode(TIMER_A0_BASE, &amp;CompareModeParam1);\n\n    Timer_A_initCompareMode(TIMER_A0_BASE, &amp;CompareModeParam2);\n\n    Timer_A_initCompareMode(TIMER_A0_BASE, &amp;CompareModeParam3);\n\n    Timer_A_initContinuousMode(TIMER_A0_BASE, &amp;ContinuousModeParam);\n\n    Timer_A_startCounter(TIMER_A0_BASE, TIMER_A_CONTINUOUS_MODE);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Unlike in the previous PWM example, timer TA0 is set for continuous mode of operation and so the top PWM count value is 65535. Thus, the period of the PWMs is about 16 ms. No interrupt is used. We just have to setup each channel individually and then run the timer in continuous mode. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the main loop, PWMs of each channel are altered and the effect is visible in the form of RGB LED\u2019s changing colour. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">for(i = 0; i &lt; steps; i++)\n{\n     Timer_A_setCompareValue(TIMER_A0_BASE,\n                             TIMER_A_CAPTURECOMPARE_REGISTER_1,\n                             duty1_value[i]);\n\n     Timer_A_setCompareValue(TIMER_A0_BASE,\n                             TIMER_A_CAPTURECOMPARE_REGISTER_2,\n                             duty2_value[i]);\n\n     Timer_A_setCompareValue(TIMER_A0_BASE,\n                             TIMER_A_CAPTURECOMPARE_REGISTER_3,\n                             duty3_value[i]);\n\n     delay_ms(250);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The duty cycle of each PWM channel is coded to in a half-sine wave pattern but each of them has a different phase shift from the other.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">const unsigned int duty3_value[steps] = {57788, \n                                         54480, \n                                         50647, \n                                         46326, \n                                         41558, \n                                         36391, \n                                         30873, \n                                         25057, \n                                         19000, \n                                         12760, \n                                         6397, \n                                         0, \n                                         6424, \n                                         12786, \n                                         19026, \n                                         25082, \n                                         30896, \n                                         36413, \n                                         41579, \n                                         46344, \n                                         50664,             \n                                         54494,\n                                         57801, \n                                         60550, \n                                         62716, \n                                         64278,                                                \n                                         65220, \n                                         65534, \n                                         65218, \n                                         64272, \n                                         62708, \n                                         60540};<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When combined with the three LEDs of the RGB, this creates a beautiful rhythmic color pattern.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"633\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-PWM-1-1024x633.jpg\" alt=\"\" class=\"wp-image-14609\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-PWM-1-1024x633.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-PWM-1-580x358.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-PWM-1-768x475.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-PWM-1.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"633\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-PWM-2-1024x633.jpg\" alt=\"\" class=\"wp-image-14610\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-PWM-2-1024x633.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-PWM-2-580x358.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-PWM-2-768x475.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-PWM-2.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/aJrqjpIhGx8?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Timer as Counter \u2013 TA2 <\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When the clock source of a timer is both regular and repetitive, the timer can be used for tracking\/keeping time. When the same timer is fed with an irregular source, the timer acts like a counter. In both cases, pulses are counted \u2013 one in synchronous while the other is asynchronous. We can make software-based counters by incrementing\/decrementing variables. However, we can do this on hardware level if we use timers as counters and feed them with external inputs.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"lcd.h\"\n#include \"lcd_print.h\"\n\nvoid clock_init(void);\nvoid GPIO_init(void);\nvoid timer_T2A3_init(void);\n\nvoid main(void)\n{\n    signed int value = 0;\n\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    GPIO_init();\n    timer_T2A3_init();\n    LCD_init();\n\n    LCD_clear_home();\n\n    LCD_goto(1, 0);\n    LCD_putstr(\"TA2 as Counter\");\n\n    LCD_goto(0, 1);\n    LCD_putstr(\"Count:\");\n\n    while(true)\n    {\n        value = Timer_A_getCounterValue(TIMER_A2_BASE);\n        print_C(12, 1, value);\n\n        if((value &gt; 20) &amp;&amp; (value  40) &amp;&amp; (value  60) &amp;&amp; (value &lt; 120))\n        {\n            GPIO_setOutputHighOnPin(GPIO_PORT_P1,\n                                    GPIO_PIN0);\n\n            GPIO_setOutputHighOnPin(GPIO_PORT_P4,\n                                    GPIO_PIN7);\n        }\n\n        else\n        {\n            GPIO_setOutputLowOnPin(GPIO_PORT_P1,\n                                   GPIO_PIN0);\n\n            GPIO_setOutputLowOnPin(GPIO_PORT_P4,\n                                   GPIO_PIN7);\n        }\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_MCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P2,\n                                               GPIO_PIN2);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P1,\n                        GPIO_PIN0);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n}\n\nvoid timer_T2A3_init(void)\n{\n    Timer_A_initUpModeParam UpModeParam = {0};\n\n    UpModeParam.clockSource = TIMER_A_CLOCKSOURCE_EXTERNAL_TXCLK;\n    UpModeParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;\n    UpModeParam.timerPeriod = 120;\n    UpModeParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;\n    UpModeParam.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;\n    UpModeParam.timerClear = TIMER_A_SKIP_CLEAR;\n    UpModeParam.startTimer = true;\n\n    Timer_A_stop(TIMER_A2_BASE);\n\n    Timer_A_clearTimerInterrupt(TIMER_A2_BASE);\n\n    Timer_A_initUpMode(TIMER_A2_BASE,\n                       &amp;UpModeParam);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"619\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/counter-1024x619.png\" alt=\"\" class=\"wp-image-14611\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/counter-1024x619.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/counter-580x351.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/counter-768x464.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/counter.png 1340w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Here timer T2A3 is used to count incoming pulses. Since counting pulses involves timer\u2019s external input pin, this input pin must be declared as an Input Peripheral Module Function pin.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P2, GPIO_PIN2);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Timer TA2 is setup as follows:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void timer_T2A3_init(void)\n{\n    Timer_A_initUpModeParam UpModeParam = {0};\n\n    UpModeParam.clockSource = TIMER_A_CLOCKSOURCE_EXTERNAL_TXCLK;\n    UpModeParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;\n    UpModeParam.timerPeriod = 120;\n    UpModeParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;\n    UpModeParam.captureCompareInterruptEnable_CCR0_CCIE =                         TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;                                                                                                \n    UpModeParam.timerClear = TIMER_A_SKIP_CLEAR;\n    UpModeParam.startTimer = true;\n\n    Timer_A_stop(TIMER_A2_BASE);\n\n    Timer_A_clearTimerInterrupt(TIMER_A2_BASE);\n\n    Timer_A_initUpMode(TIMER_A2_BASE, &amp;UpModeParam);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Clock source is the very first thing to note in this example. ACLK\nor SMCLK is not used. Externally clock pulses are applied via timer input pin.\nNote however timer input pin is also not a CC channel pin. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Up mode counting is used with a top value of 120 and so the timer\nwill count from 0 to 120 and then roll over. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Interrupts are avoided and so polling method is used. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Initially, the timer is kept in halt state and timer settings are\nnot cleared because no setting was applied beforehand. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After setting up the timer, the timer is started but counting\ndoesn\u2019t start until there is a logic transition in the timer\u2019s external input\npin. Each incoming pulse increases the timer\u2019s count.&nbsp; <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the main loop, timer\u2019s count is checked or polled on each loop passes. The value of timer count is displayed on an LCD and -LEDs are flashed according to count values.&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">value = Timer_A_getCounterValue(TIMER_A2_BASE);\nprint_C(12, 1, value);\n\nif((value &gt; 20) &amp;&amp; (value  40) &amp;&amp; (value  60) &amp;&amp; (value &lt; 120))\n{\n    GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0);\n\n    GPIO_setOutputHighOnPin(GPIO_PORT_P4, GPIO_PIN7);\n}\n\nelse\n{\n    GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);\n\n    GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN7);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"641\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Counter-1024x641.jpg\" alt=\"\" class=\"wp-image-14612\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Counter-1024x641.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Counter-580x363.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Counter-768x481.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Counter.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/ZHtPsZM9G2Y?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Timer Input Capture Mode \u2013 TA0<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Just like PWM, timer input capture is another important feature of a timer. This is an input-side feature unlike PWM. Input capture is needed for measurement of pulse widths, frequency and time period of an incoming waveform. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"lcd.h\"\n#include \"lcd_print.h\"\n\nunsigned int pulse_ticks = 0;\nunsigned int start_time = 0;\nunsigned int end_time = 0;\n\nvoid clock_init(void);\nvoid GPIO_init(void);\nvoid timer_T0A5_init(void);\nvoid timer_T2A3_init(void);\n\n#pragma vector=TIMER0_A1_VECTOR\n__interrupt void TIMER0_A1_ISR(void)\n{\n  switch(__even_in_range(TA0IV, 10))\n  {\n       case 0x00: break;             \/\/ None\n       case 0x02:                    \/\/ CCR1 IFG\n       {\n           end_time = Timer_A_getCaptureCompareCount(TIMER_A0_BASE,\n                                                     TIMER_A_CAPTURECOMPARE_REGISTER_1);\n\n           pulse_ticks = (end_time - start_time);\n\n           start_time = end_time;\n\n           Timer_A_clearCaptureCompareInterrupt(TIMER_A0_BASE,\n                                                TIMER_A_CAPTURECOMPARE_REGISTER_1);\n\n           break;\n       }\n       case 0x04: break;             \/\/ CCR2 IFG\n       case 0x06: break;             \/\/ CCR3 IFG\n       case 0x08: break;             \/\/ CCR4 IFG\n       case 0x0A: break;             \/\/ CCR5 IFG\n       case 0x0C: break;             \/\/ CCR6 IFG\n       case 0x0E:                    \/\/ TA0IFG\n       {\n           GPIO_toggleOutputOnPin(GPIO_PORT_P1,\n                                  GPIO_PIN0);\n\n           break;\n       }\n       default:   _never_executed();\n  }\n}\n\nvoid main(void)\n{\n    unsigned char i = 0;\n    unsigned char settings_changed = false;\n    unsigned long timer_clock_frequency = 0;\n\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    GPIO_init();\n    timer_T0A5_init();\n    timer_T2A3_init();\n\n    LCD_init();\n    LCD_clear_home();\n\n    LCD_goto(0, 0);\n    LCD_putstr(\"PWM.\/Hz:\");\n\n    LCD_goto(0, 1);\n    LCD_putstr(\"Cap.\/Hz:\");\n\n    timer_clock_frequency = UCS_getSMCLK();\n\n    while(true)\n    {\n\n        if(GPIO_getInputPinValue(GPIO_PORT_P2,\n                                 GPIO_PIN1) == false)\n        {\n            while(GPIO_getInputPinValue(GPIO_PORT_P2,\n                                        GPIO_PIN1) == false);\n\n            i++;\n\n            GPIO_setOutputHighOnPin(GPIO_PORT_P4,\n                                    GPIO_PIN7);\n\n            delay_ms(100);\n\n            GPIO_setOutputLowOnPin(GPIO_PORT_P4,\n                                   GPIO_PIN7);\n\n            if(i &gt; 5)\n            {\n                i = 0;\n            }\n\n            settings_changed = false;\n\n        }\n\n        switch(settings_changed)\n        {\n            case true:\n            {\n                print_I(8, 1, (timer_clock_frequency \/ pulse_ticks));\n                delay_ms(100);\n                break;\n            }\n\n            default:\n            {\n                switch(i)\n                {\n                    case 1:\n                    {\n                        LCD_goto(9, 0);\n                        LCD_putstr(\"200  \");\n\n                        Timer_A_outputPWMParam outputPWMParam = {0};\n\n                        outputPWMParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;\n                        outputPWMParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_4;\n                        outputPWMParam.timerPeriod = 5000;\n                        outputPWMParam.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;\n                        outputPWMParam.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;\n                        outputPWMParam.dutyCycle = 0;\n\n                        Timer_A_outputPWM(TIMER_A2_BASE,\n                                          &amp;outputPWMParam);\n\n                        Timer_A_setCompareValue(TIMER_A2_BASE,\n                                                TIMER_A_CAPTURECOMPARE_REGISTER_1,\n                                                2000);\n\n                        break;\n                    }\n\n                    case 2:\n                    {\n                        LCD_goto(9, 0);\n                        LCD_putstr(\"125  \");\n\n                        Timer_A_outputPWMParam outputPWMParam = {0};\n\n                        outputPWMParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;\n                        outputPWMParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_4;\n                        outputPWMParam.timerPeriod = 8000;\n                        outputPWMParam.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;\n                        outputPWMParam.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;\n                        outputPWMParam.dutyCycle = 0;\n\n                        Timer_A_outputPWM(TIMER_A2_BASE,\n                                          &amp;outputPWMParam);\n\n                        Timer_A_setCompareValue(TIMER_A2_BASE,\n                                                TIMER_A_CAPTURECOMPARE_REGISTER_1,\n                                                4000);\n\n                        break;\n                    }\n\n                    case 3:\n                    {\n                        LCD_goto(9, 0);\n                        LCD_putstr(\"1000 \");\n\n                        Timer_A_outputPWMParam outputPWMParam = {0};\n\n                        outputPWMParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;\n                        outputPWMParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_4;\n                        outputPWMParam.timerPeriod = 1000;\n                        outputPWMParam.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;\n                        outputPWMParam.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;\n                        outputPWMParam.dutyCycle = 0;\n\n                        Timer_A_outputPWM(TIMER_A2_BASE,\n                                          &amp;outputPWMParam);\n\n                        Timer_A_setCompareValue(TIMER_A2_BASE,\n                                                TIMER_A_CAPTURECOMPARE_REGISTER_1,\n                                                600);\n\n                        break;\n                    }\n\n                    case 4:\n                    {\n                        LCD_goto(9, 0);\n                        LCD_putstr(\"8000 \");\n\n                        Timer_A_outputPWMParam outputPWMParam = {0};\n\n                        outputPWMParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;\n                        outputPWMParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_4;\n                        outputPWMParam.timerPeriod = 125;\n                        outputPWMParam.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;\n                        outputPWMParam.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;\n                        outputPWMParam.dutyCycle = 0;\n\n                        Timer_A_outputPWM(TIMER_A2_BASE,\n                                          &amp;outputPWMParam);\n\n                        Timer_A_setCompareValue(TIMER_A2_BASE,\n                                                TIMER_A_CAPTURECOMPARE_REGISTER_1,\n                                                60);\n\n                        break;\n                    }\n\n                    case 5:\n                    {\n                        LCD_goto(9, 0);\n                        LCD_putstr(\"2000 \");\n\n                        Timer_A_outputPWMParam outputPWMParam = {0};\n\n                        outputPWMParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;\n                        outputPWMParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_4;\n                        outputPWMParam.timerPeriod = 500;\n                        outputPWMParam.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;\n                        outputPWMParam.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;\n                        outputPWMParam.dutyCycle = 0;\n\n                        Timer_A_outputPWM(TIMER_A2_BASE,\n                                          &amp;outputPWMParam);\n\n                        Timer_A_setCompareValue(TIMER_A2_BASE,\n                                                TIMER_A_CAPTURECOMPARE_REGISTER_1,\n                                                250);\n\n                        break;\n                    }\n\n                    default:\n                    {\n\n                        LCD_goto(9, 0);\n                        LCD_putstr(\"333.3\");\n\n                        Timer_A_outputPWMParam outputPWMParam = {0};\n\n                        outputPWMParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;\n                        outputPWMParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_4;\n                        outputPWMParam.timerPeriod = 3000;\n                        outputPWMParam.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;\n                        outputPWMParam.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;\n                        outputPWMParam.dutyCycle = 0;\n\n                        Timer_A_outputPWM(TIMER_A2_BASE,\n                                          &amp;outputPWMParam);\n\n                        Timer_A_setCompareValue(TIMER_A2_BASE,\n                                                TIMER_A_CAPTURECOMPARE_REGISTER_1,\n                                                1500);\n\n                        break;\n                    }\n\n                }\n\n                settings_changed = true;\n\n                break;\n            }\n        }\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_MCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2,\n                                         GPIO_PIN1);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P1,\n                        GPIO_PIN0);\n\n    GPIO_setDriveStrength(GPIO_PORT_P1,\n                          GPIO_PIN0,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n\n    GPIO_setDriveStrength(GPIO_PORT_P4,\n                          GPIO_PIN7,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,\n                                               GPIO_PIN2);\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P2,\n                                                GPIO_PIN4);\n}\n\nvoid timer_T0A5_init(void)\n{\n    Timer_A_initCaptureModeParam CaptureModeParam = {0};\n    Timer_A_initContinuousModeParam ContinuousModeParam = {0};\n\n    Timer_A_stop(TIMER_A0_BASE);\n    Timer_A_clearTimerInterrupt(TIMER_A0_BASE);\n\n    ContinuousModeParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;\n    ContinuousModeParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;\n    ContinuousModeParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE;\n    ContinuousModeParam.timerClear = TIMER_A_SKIP_CLEAR;\n    ContinuousModeParam.startTimer = true;\n\n    CaptureModeParam.captureRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;\n    CaptureModeParam.captureMode = TIMER_A_CAPTUREMODE_RISING_EDGE;\n    CaptureModeParam.captureInputSelect = TIMER_A_CAPTURE_INPUTSELECT_CCIxA;\n    CaptureModeParam.synchronizeCaptureSource = TIMER_A_CAPTURE_ASYNCHRONOUS;\n    CaptureModeParam.captureInterruptEnable = TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE;\n\n    Timer_A_initContinuousMode(TIMER_A0_BASE,\n                               &amp;ContinuousModeParam);\n\n    Timer_A_initCaptureMode(TIMER_A0_BASE,\n                            &amp;CaptureModeParam);\n\n    __enable_interrupt();\n}\n\nvoid timer_T2A3_init(void)\n{\n    Timer_A_outputPWMParam outputPWMParam = {0};\n\n    outputPWMParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;\n    outputPWMParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_4;\n    outputPWMParam.timerPeriod = 2000;\n    outputPWMParam.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;\n    outputPWMParam.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;\n    outputPWMParam.dutyCycle = 0;\n\n    Timer_A_outputPWM(TIMER_A2_BASE,\n                      &amp;outputPWMParam);\n\n    Timer_A_setCompareValue(TIMER_A2_BASE,\n                            TIMER_A_CAPTURECOMPARE_REGISTER_1,\n                            1000);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"616\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Capture-1024x616.png\" alt=\"\" class=\"wp-image-14614\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Capture-1024x616.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Capture-580x349.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Capture-768x462.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Capture-600x360.png 600w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Capture.png 1323w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In this example, two timers are used. One is set to provide variable\nfrequency PWM while the other is set to measure PWM frequency. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First, let\u2019s see how the PWM is configured. Timer TA2 is used to provide PWM output.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void clock_init(void)\n{\n....\n    UCS_initClockSignal(UCS_SMCLK, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_1);\n....\n}\n\n\nvoid GPIO_init(void)\n{\n....\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P2, GPIO_PIN4);\n}\n\n\nvoid timer_T2A3_init(void)\n{\n    Timer_A_outputPWMParam outputPWMParam = {0};\n\n    outputPWMParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;\n    outputPWMParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_4;\n    outputPWMParam.timerPeriod = 2000;\n    outputPWMParam.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;\n    outputPWMParam.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;\n    outputPWMParam.dutyCycle = 0;\n\n    Timer_A_outputPWM(TIMER_A2_BASE,\n                      &amp;outputPWMParam);\n\n    Timer_A_setCompareValue(TIMER_A2_BASE,\n                            TIMER_A_CAPTURECOMPARE_REGISTER_1,\n                            1000);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">One CC channel of timer T2A3 is used to generate a PWM output of\n500Hz with these settings. I believe, by now, the code is not difficult to\nunderstand. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">On P2.1 button press, the time period and duty cycle of this timer\nare altered and square waves of different frequencies are generated. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now let\u2019s see how the capture timer is setup. Capture hardware is made with timer TA0. CC channel 1 is used and therefore P1.2\u2019s secondary function is enabled.&nbsp;&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void clock_init(void)\n{\n....\n    UCS_initClockSignal(UCS_SMCLK, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_1);\n....\n}\n\nvoid GPIO_init(void)\n{\n....\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, GPIO_PIN2);\n....\n}\n\n\nvoid timer_T0A5_init(void)\n{\n    Timer_A_initCaptureModeParam CaptureModeParam = {0};\n    Timer_A_initContinuousModeParam ContinuousModeParam = {0};\n\n    Timer_A_stop(TIMER_A0_BASE);\n    Timer_A_clearTimerInterrupt(TIMER_A0_BASE);\n\n    ContinuousModeParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;\n    ContinuousModeParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;\n    ContinuousModeParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE;\n    ContinuousModeParam.timerClear = TIMER_A_SKIP_CLEAR;\n    ContinuousModeParam.startTimer = true;\n\n    CaptureModeParam.captureRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;\n    CaptureModeParam.captureMode = TIMER_A_CAPTUREMODE_RISING_EDGE;\n    CaptureModeParam.captureInputSelect = TIMER_A_CAPTURE_INPUTSELECT_CCIxA;\n    CaptureModeParam.synchronizeCaptureSource = TIMER_A_CAPTURE_ASYNCHRONOUS;\n    CaptureModeParam.captureInterruptEnable = TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE;\n\n    Timer_A_initContinuousMode(TIMER_A0_BASE, &amp;ContinuousModeParam);\n\n    Timer_A_initCaptureMode(TIMER_A0_BASE, &amp;CaptureModeParam);\n\n    __enable_interrupt();\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Capture hardware consists of two parts \u2013 CC input capture and\ncontinuous mode timer. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Firstly, the continuous mode timer is setup. This timer is fed with\n4MHz SMCLK. It ticks at every 250ns and approximately overflows every 16ms.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Secondly, the capture part is setup using CC channel 1. It is set to\nlook for rising edges of incoming waveform.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the interrupt, respective flags are checked. Note both flags are under same interrupt vector. When timer overflow occurs, P1.0 LED is only toggled. However, the interesting part happens inside the CCR1 flag. It is at this stage, time period of capture waveform is captured and calculated.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#pragma vector=TIMER0_A1_VECTOR\n__interrupt void TIMER0_A1_ISR(void)\n{\n  switch(__even_in_range(TA0IV, 10))\n  {\n       case 0x00: break;             \/\/ None\n       case 0x02:                    \/\/ CCR1 IFG\n       {\n           end_time = Timer_A_getCaptureCompareCount(TIMER_A0_BASE,                                           TIMER_A_CAPTURECOMPARE_REGISTER_1);\n\n           pulse_ticks = (end_time - start_time);\n\n           start_time = end_time;\n\n           Timer_A_clearCaptureCompareInterrupt(TIMER_A0_BASE,                                                TIMER_A_CAPTURECOMPARE_REGISTER_1);\n\n           break;\n       }\n       case 0x04: break;             \/\/ CCR2 IFG\n       case 0x06: break;             \/\/ CCR3 IFG\n       case 0x08: break;             \/\/ CCR4 IFG\n       case 0x0A: break;             \/\/ CCR5 IFG\n       case 0x0C: break;             \/\/ CCR6 IFG\n       case 0x0E:                    \/\/ TA0IFG\n       {\n           GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);\n\n           break;\n       }\n       default:   _never_executed();\n  }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When a rising-edge is detected, timer\u2019s current count is immediately\nstored. When another rising-edge is detected, the timer count of that instance\nis also stored. Subtracting these two counts results in a count difference. Since\nwe know timer\u2019s tick period, we can use the count difference to compute\nperiod\/frequency of the incoming waveform. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">SMCLK\u2019s frequency is the timer\u2019s operating speed and it is found out by the code as shown below:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">timer_clock_frequency = UCS_getSMCLK();<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Dividing timer clock frequency (4 MHz) with time count differences, i.e. <em>pulse_ticks<\/em>, gives us the frequency of capture waveform. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">print_I(8, 1, (timer_clock_frequency \/ pulse_ticks));\ndelay_ms(100);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The limitation of this code is inaccuracy of measurement at high frequencies and that\u2019s because at high frequencies, capture resolution decreases. To capture high frequencies, we can use faster clocks or more sampling.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"579\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Capture-1-1024x579.jpg\" alt=\"\" class=\"wp-image-14615\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Capture-1-1024x579.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Capture-1-580x328.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Capture-1-768x434.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Capture-1.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"537\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Capture-2-1024x537.jpg\" alt=\"\" class=\"wp-image-14617\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Capture-2-1024x537.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Capture-2-580x304.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Capture-2-768x403.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Capture-2.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"572\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Capture-4-1024x572.jpg\" alt=\"\" class=\"wp-image-14616\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Capture-4-1024x572.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Capture-4-580x324.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Capture-4-768x429.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Timer-Capture-4.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/SbxmKmFN6Pw?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Real Time Clock \u2013 RTC_A<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">As stated before, RTC_A is mainly intended for time keeping and, in this demo, we will see how make a real-time clock with the RTC_A module. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"649\" height=\"865\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-1.png\" alt=\"\" class=\"wp-image-14618\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-1.png 649w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-1-488x650.png 488w\" sizes=\"auto, (max-width: 649px) 100vw, 649px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s see some insights of RTC_A module. Firstly, we can see that the RTC_A module can be feed with either SMCLK or ACLK. Since SMCLK has other important uses, it is better to use ACLK for RTC_A. ACLK should have a frequency of 32.768 kHz and to achieve that it is better to use dedicated external crystal or TCXO. The RTC\u2019s counter <em>RTCBCD<\/em> can be then clocked directly by clock signals or via <em>RTxPS<\/em> registers. The desired tick period for RTC is obviously 1 Hz. Selectable either in BCD or hexadecimal format, the RTC_A calendar block gives time and date. A cool feature is the fact that internal algorithm takes care of leap-years from the year 1901 AD to 2099 AD. It is also possible to set calendar alarms but coder has to be careful because out-of-range or invalid date-time settings may result in unpredictable behavior. Lastly, there are several interrupts for various timer events. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"lcd.h\"\n#include \"lcd_print.h\"\n\nCalendar current_Time;\nunsigned char update_time = false;\n\nvoid clock_init(void);\nvoid GPIO_init(void);\nvoid RTC_init(void);\nvoid display_year(unsigned char x_pos, unsigned char y_pos, unsigned int value);\nvoid display_time_date(unsigned char x_pos, unsigned char y_pos, unsigned char value);\nunsigned int change_value(unsigned char x_pos, unsigned char y_pos, signed int value, signed int value_min, signed int value_max, unsigned char value_type);\nvoid set_RTC(void);\n\n#pragma vector = RTC_VECTOR\n__interrupt void RTC_A_ISR (void)\n{\n    switch(__even_in_range(RTCIV, 16))\n    {\n        case 0: break;  \/\/No interrupts\n        case 2:         \/\/RTCRDYIFG\n        {\n            GPIO_toggleOutputOnPin(GPIO_PORT_P4,\n                                   GPIO_PIN7);\n\n            current_Time = RTC_A_getCalendarTime(RTC_A_BASE);\n\n            update_time = true;\n\n            break;\n        }\n        case 4: break;  \/\/RTCEVIFG\n        case 6: break;  \/\/RTCAIFG\n        case 8: break;  \/\/RT0PSIFG\n        case 10: break; \/\/RT1PSIFG\n        case 12: break; \/\/Reserved\n        case 14: break; \/\/Reserved\n        case 16: break; \/\/Reserved\n        default: break;\n    }\n}\n\nvoid main(void)\n{\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    GPIO_init();\n    RTC_init();\n    LCD_init();\n\n    LCD_clear_home();\n\n    LCD_goto(6, 0);\n    LCD_putstr(\":  :\");\n\n    LCD_goto(5, 1);\n    LCD_putstr(\"\/  \/\");\n\n    while(1)\n    {\n\n        set_RTC();\n\n         if(update_time)\n         {\n             display_time_date(4, 0, current_Time.Hours);\n             display_time_date(7, 0, current_Time.Minutes);\n             display_time_date(10, 0, current_Time.Seconds);\n             display_time_date(3, 1, current_Time.DayOfMonth);\n             display_time_date(6, 1, current_Time.Month);\n             display_year(9, 1, current_Time.Year);\n             update_time = 0;\n         }\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_FLLREF,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initFLLSettle(MCLK_KHZ,\n                      MCLK_FLLREF_RATIO);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_2);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1,\n                                         GPIO_PIN1);\n\n    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2,\n                                         GPIO_PIN1);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P1,\n                        GPIO_PIN0);\n\n    GPIO_setDriveStrength(GPIO_PORT_P1,\n                          GPIO_PIN0,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n\n    GPIO_setDriveStrength(GPIO_PORT_P4,\n                          GPIO_PIN7,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n}\n\nvoid RTC_init(void)\n{\n    current_Time.Seconds = 30;\n    current_Time.Minutes = 10;\n    current_Time.Hours = 10;\n    current_Time.DayOfWeek = 1;\n    current_Time.DayOfMonth = 1;\n    current_Time.Month = 1;\n    current_Time.Year = 2000;\n\n    RTC_A_initCalendar(RTC_A_BASE,\n                       &amp;current_Time,\n                       RTC_A_FORMAT_BINARY);\n\n    RTC_A_setCalendarEvent(RTC_A_BASE,\n                           RTC_A_CALENDAREVENT_MINUTECHANGE);\n\n    RTC_A_clearInterrupt(RTC_A_BASE,\n                         (RTCRDYIFG | RTCTEVIFG | RTCAIFG));\n\n    RTC_A_enableInterrupt(RTC_A_BASE,\n                          (RTCRDYIE | RTCTEVIE | RTCAIE));\n\n    RTC_A_startClock(RTC_A_BASE);\n\n    __enable_interrupt();\n}\n\nvoid display_year(unsigned char x_pos, unsigned char y_pos, unsigned int value)\n{\n    unsigned char tmp = 0;\n\n    tmp = (value \/ 100);\n    display_time_date(x_pos, y_pos, tmp);\n    tmp = (value % 100);\n    display_time_date((x_pos + 2), y_pos, tmp);\n}\n\nvoid display_time_date(unsigned char x_pos, unsigned char y_pos, unsigned char value)\n{\n    unsigned char ch = 0;\n\n    ch = (value \/ 10);\n    LCD_goto(x_pos, y_pos);\n    LCD_putchar((ch + 0x30));\n\n    ch = (value % 10);\n    LCD_goto((1 + x_pos), y_pos);\n    LCD_putchar((ch + 0x30));\n}\n\nunsigned int change_value(unsigned char x_pos, unsigned char y_pos, signed int value, signed int value_min, signed int value_max, unsigned char value_type)\n{\n    while(1)\n    {\n        LCD_goto(x_pos, y_pos);\n\n        switch(value_type)\n        {\n            case 1:\n            {\n                LCD_putstr(\"    \");\n                break;\n            }\n            default:\n            {\n                LCD_putstr(\"  \");\n                break;\n            }\n        }\n\n        delay_ms(60);\n\n        if(GPIO_getInputPinValue(GPIO_PORT_P1,\n                                 GPIO_PIN1) == false)\n        {\n            value++;\n        }\n\n        if(value &gt; value_max)\n        {\n            value = value_min;\n        }\n\n        switch(value_type)\n        {\n            case 1:\n            {\n                display_year(x_pos, y_pos, ((unsigned int)value));\n                break;\n            }\n            default:\n            {\n                display_time_date(x_pos, y_pos, ((unsigned char)value));\n                break;\n            }\n        }\n        delay_ms(90);\n\n        if(GPIO_getInputPinValue(GPIO_PORT_P2,\n                                 GPIO_PIN1) == false)\n        {\n            while(GPIO_getInputPinValue(GPIO_PORT_P2,\n                                        GPIO_PIN1) == false);\n\n            delay_ms(200);\n            return value;\n        }\n    };\n}\n\nvoid set_RTC(void)\n{\n    if(GPIO_getInputPinValue(GPIO_PORT_P2,\n                             GPIO_PIN1) == false)\n    {\n        GPIO_setOutputHighOnPin(GPIO_PORT_P1,\n                                GPIO_PIN0);\n\n        while(GPIO_getInputPinValue(GPIO_PORT_P2,\n                                    GPIO_PIN1) == false);\n\n        RTC_A_disableInterrupt(RTC_A_BASE,\n                               (RTCRDYIE | RTCTEVIE | RTCAIE));\n\n        RTC_A_holdClock(RTC_A_BASE);\n\n        __disable_interrupt();\n\n        update_time = false;\n\n        current_Time.Hours = change_value(4, 0, current_Time.Hours, 0, 23, 0);\n\n        current_Time.Minutes = change_value(7, 0, current_Time.Minutes, 0, 59, 0);\n\n        current_Time.Seconds = change_value(10, 0, current_Time.Seconds, 0, 59, 0);\n\n        current_Time.DayOfMonth = change_value(3, 1, current_Time.DayOfMonth, 1, 31, 0);\n\n        current_Time.Month = change_value(6, 1, current_Time.Month, 1, 12, 0);\n\n        current_Time.Year = change_value(9, 1, current_Time.Year, 1970, 2099, 1);\n\n        GPIO_setOutputLowOnPin(GPIO_PORT_P1,\n                               GPIO_PIN0);\n\n        RTC_A_initCalendar(RTC_A_BASE,\n                           &amp;current_Time,\n                           RTC_A_FORMAT_BINARY);\n\n        RTC_A_clearInterrupt(RTC_A_BASE,\n                             (RTCRDYIFG | RTCTEVIFG | RTCAIFG));\n\n        RTC_A_enableInterrupt(RTC_A_BASE,\n                              (RTCRDYIE | RTCTEVIE | RTCAIE));\n\n        RTC_A_startClock(RTC_A_BASE);\n\n        __enable_interrupt();\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"590\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/RTC-1024x590.png\" alt=\"\" class=\"wp-image-14619\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/RTC-1024x590.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/RTC-580x334.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/RTC-768x443.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/RTC.png 1343w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"> Earlier I mentioned why we should use ACLK for RTC and so for that ground I used ACLK to drive the RTC_A module. On board external 32.768 kHz crystal is used for ACLK as it is better than any other source. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">UCS_initClockSignal(UCS_ACLK, UCS_XT1CLK_SELECT, UCS_CLOCK_DIVIDER_1);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">On-board LEDs and buttons are also used. P4.7 LED is used as second ticker while P1.0 LED is used as setting mode indicator. P1.1 button is used as a modifier button while P2.1 button acts as a set\/enter button. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1);\nGPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2, GPIO_PIN1);\n\nGPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);\nGPIO_setAsOutputPin(GPIO_PORT_P4, GPIO_PIN7);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now let\u2019s see how the RTC is set up.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void RTC_init(void)\n{\n    current_Time.Seconds = 30;\n    current_Time.Minutes = 10;\n    current_Time.Hours = 10;\n    current_Time.DayOfWeek = 1;\n    current_Time.DayOfMonth = 1;\n    current_Time.Month = 1;\n    current_Time.Year = 2000;\n\n    RTC_A_initCalendar(RTC_A_BASE, &amp;current_Time, RTC_A_FORMAT_BINARY);\n\n    RTC_A_setCalendarEvent(RTC_A_BASE, RTC_A_CALENDAREVENT_MINUTECHANGE);\n\n    RTC_A_clearInterrupt(RTC_A_BASE, (RTCRDYIFG | RTCTEVIFG | RTCAIFG));\n\n    RTC_A_enableInterrupt(RTC_A_BASE, (RTCRDYIE | RTCTEVIE | RTCAIE));\n\n    RTC_A_startClock(RTC_A_BASE);\n\n    __enable_interrupt();\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We start by initializing and loading date-time parameters of our\nchoosing in binary format. We chose binary format because in that way we can\navoid unnecessary BCD-to-binary conversions. Finally, we enable required\ninterrupts after clearing them and start the RTC. &nbsp;&nbsp;&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Inside the interrupt vector, we just check the <em>RTCRDY<\/em> interrupt flag and that\u2019s because from here we will extract current RTC time info. Other interrupts, although enabled, are not needed as we are not using alarm and event features.&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#pragma vector = RTC_VECTOR\n__interrupt void RTC_A_ISR (void)\n{\n    switch(__even_in_range(RTCIV, 16))\n    {\n        case 0: break;  \/\/No interrupts\n        case 2:         \/\/RTCRDYIFG\n        {\n            GPIO_toggleOutputOnPin(GPIO_PORT_P4,\n                                   GPIO_PIN7);\n\n            current_Time = RTC_A_getCalendarTime(RTC_A_BASE);\n\n            update_time = true;\n\n            break;\n        }\n        case 4: break;  \/\/RTCEVIFG\n        case 6: break;  \/\/RTCAIFG\n        case 8: break;  \/\/RT0PSIFG\n        case 10: break; \/\/RT1PSIFG\n        case 12: break; \/\/Reserved\n        case 14: break; \/\/Reserved\n        case 16: break; \/\/Reserved\n        default: break;\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In the main loop, we can do two things, either we can set time or watch it. When setting date-time, the display only shows the date-time parameters we are setting. After setup up, the RTC module is reinitialized with new date and time.&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">set_RTC();\n\nif(update_time)\n{\n   display_time_date(4, 0, current_Time.Hours);\n   display_time_date(7, 0, current_Time.Minutes);\n   display_time_date(10, 0, current_Time.Seconds);\n   display_time_date(3, 1, current_Time.DayOfMonth);\n   display_time_date(6, 1, current_Time.Month);\n   display_year(9, 1, current_Time.Year);\n   update_time = 0;\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"605\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/RTC-1-1024x605.jpg\" alt=\"\" class=\"wp-image-14625\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/RTC-1-1024x605.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/RTC-1-580x343.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/RTC-1-768x454.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/RTC-1.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/TKQeRMbaxKs?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">RTC_A as Counter<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">As with other timers, counter mode is a secondary feature of RTC_A module. In this mode, the calendar feature of RTC_A is not used. Instead of being an RTC, RTC_A in this mode behaves like a regular timer. However, unlike other regular timers, we cannot get timer count. This does not limit us much from using it for time bases as there are two counters that can be cascaded and, individually and independently prescaled. RTC_A is rarely used in this role because it is only used as such when we have run out of regular timers and have no need for RTC.&nbsp; <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n\nvoid clock_init(void);\nvoid GPIO_init(void);\nvoid RTC_init(void);\n\n#pragma vector=RTC_VECTOR\n__interrupt void RTC_A_ISR(void)\n{\n    switch (__even_in_range(RTCIV, 16))\n    {\n        case 0: break;  \/\/No interrupts\n        case 2: break;  \/\/RTCRDYIFG\n        case 4:         \/\/RTCEVIFG\n        {\n            GPIO_toggleOutputOnPin(GPIO_PORT_P1,\n                                   GPIO_PIN0);\n\n            GPIO_toggleOutputOnPin(GPIO_PORT_P4,\n                                   GPIO_PIN7);\n\n            break;\n        }\n        case 6: break;  \/\/RTCAIFG\n        case 8: break;  \/\/RT0PSIFG\n        case 10: break; \/\/RT1PSIFG\n        default: break;\n    }\n}\n\nvoid main(void)\n{\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    GPIO_init();\n    RTC_init();\n\n    while(1)\n    {\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_FLLREF,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initFLLSettle(MCLK_KHZ,\n                      MCLK_FLLREF_RATIO);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsOutputPin(GPIO_PORT_P1,\n                        GPIO_PIN0);\n\n    GPIO_setDriveStrength(GPIO_PORT_P1,\n                          GPIO_PIN0,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n\n    GPIO_setDriveStrength(GPIO_PORT_P4,\n                          GPIO_PIN7,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setOutputLowOnPin(GPIO_PORT_P1,\n                           GPIO_PIN0);\n\n    GPIO_setOutputHighOnPin(GPIO_PORT_P4,\n                            GPIO_PIN7);\n}\n\nvoid RTC_init(void)\n{\n    RTC_A_initCounter(RTC_A_BASE,\n                      RTC_A_CLOCKSELECT_RT1PS,\n                      RTC_A_COUNTERSIZE_16BIT);\n\n    RTC_A_initCounterPrescale(RTC_A_BASE,\n                              RTC_A_PRESCALE_0,\n                              RTC_A_PSCLOCKSELECT_SMCLK,\n                              RTC_A_PSDIVIDER_4);\n\n    RTC_A_initCounterPrescale(RTC_A_BASE,\n                              RTC_A_PRESCALE_1,\n                              RTC_A_PSCLOCKSELECT_RT0PS,\n                              RTC_A_PSDIVIDER_16);\n\n    RTC_A_setCounterValue(RTC_A_BASE,\n                          0);\n\n    RTC_A_clearInterrupt(RTC_A_BASE,\n                         RTC_A_TIME_EVENT_INTERRUPT);\n\n    RTC_A_clearInterrupt(RTC_A_BASE,\n                         RTC_A_PRESCALE_TIMER1_INTERRUPT);\n\n    RTC_A_enableInterrupt(RTC_A_BASE,\n                          RTC_A_TIME_EVENT_INTERRUPT);\n\n    RTC_A_enableInterrupt(RTC_A_BASE,\n                          RTC_A_PRESCALE_TIMER1_INTERRUPT);\n\n    RTC_A_startClock(RTC_A_BASE);\n\n    __enable_interrupt();\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"961\" height=\"685\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Free-Timer-RTC-Counter-WDT-Counter-1.png\" alt=\"\" class=\"wp-image-14627\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Free-Timer-RTC-Counter-WDT-Counter-1.png 961w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Free-Timer-RTC-Counter-WDT-Counter-1-580x413.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Free-Timer-RTC-Counter-WDT-Counter-1-768x547.png 768w\" sizes=\"auto, (max-width: 961px) 100vw, 961px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For simplest-possible demo, we will again make a LED\ntoggler. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Obviously, counter mode is different from regular calendar mode and so we can use different clock settings. Here, we will be using SMCLK and it will be running at 4 MHz. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">UCS_initClockSignal(UCS_SMCLK, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_1);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Both on-board LEDs are used but they are initialized at different logic states. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);\n\nGPIO_setAsOutputPin(GPIO_PORT_P4, GPIO_PIN7);\n\nGPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);\n\nGPIO_setOutputHighOnPin(GPIO_PORT_P4, GPIO_PIN7);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">RTC_A module\u2019s setup this time is obviously different from the last RTC_A example. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void RTC_init(void)\n{\n    RTC_A_initCounter(RTC_A_BASE,\n                      RTC_A_CLOCKSELECT_RT1PS,\n                      RTC_A_COUNTERSIZE_16BIT);\n\n    RTC_A_initCounterPrescale(RTC_A_BASE,\n                              RTC_A_PRESCALE_0,\n                              RTC_A_PSCLOCKSELECT_SMCLK,\n                              RTC_A_PSDIVIDER_4);\n\n    RTC_A_initCounterPrescale(RTC_A_BASE,\n                              RTC_A_PRESCALE_1,\n                              RTC_A_PSCLOCKSELECT_RT0PS,\n                              RTC_A_PSDIVIDER_16);\n\n    RTC_A_setCounterValue(RTC_A_BASE, 0);\n\n    RTC_A_clearInterrupt(RTC_A_BASE, RTC_A_TIME_EVENT_INTERRUPT);\n\n    RTC_A_clearInterrupt(RTC_A_BASE, RTC_A_PRESCALE_TIMER1_INTERRUPT);\n\n    RTC_A_enableInterrupt(RTC_A_BASE, RTC_A_TIME_EVENT_INTERRUPT);\n\n    RTC_A_enableInterrupt(RTC_A_BASE, RTC_A_PRESCALE_TIMER1_INTERRUPT);\n\n    RTC_A_startClock(RTC_A_BASE);\n\n    __enable_interrupt();\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Firstly, the size of the main RTC counter and its clock source are set. Here the clock source is <em>RT1PS<\/em>. <em>RT0PS<\/em> and <em>RT1PS<\/em> are sub-counters. <em>RT0PS<\/em> is clocked with either SMCLK or ACLK while <em>RT1PS<\/em> is clocked with SMCLK, ACLK or prescaled <em>RT0PS<\/em>. Finally, the RTC module\u2019s main counter can be fed with SMCLK, ACLK or prescaled <em>RT1PS<\/em>. Thus, here the latter codes involve setting these parameters. <em>RT0PS <\/em>is fed with 4 MHz SMCLK and then a prescalar of 4 is applied. The resultant frequency is a 1 MHz which is used to feed <em>RT1PS<\/em>. Now <em>RT1PS <\/em>is further prescaled by 16, resulting in 62.5 kHz clock. This is what that feeds the main counter. Only 16 bits of the 32-bit main counter is used. Thus, the main counter overflows roughly about every second. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Every overflow event triggers an interrupt. Inside the interrupt on-board LEDs are toggled. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#pragma vector=RTC_VECTOR\n__interrupt void RTC_A_ISR(void)\n{\n    switch (__even_in_range(RTCIV, 16))\n    {\n        case 0: break;  \/\/No interrupts\n        case 2: break;  \/\/RTCRDYIFG\n        case 4:         \/\/RTCEVIFG\n        {\n            GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);\n\n            GPIO_toggleOutputOnPin(GPIO_PORT_P4, GPIO_PIN7);\n\n            break;\n        }\n        case 6: break;  \/\/RTCAIFG\n        case 8: break;  \/\/RT0PSIFG\n        case 10: break; \/\/RT1PSIFG\n        default: break;\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"956\" height=\"1024\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/RTC-Counter-956x1024.gif\" alt=\"\" class=\"wp-image-14629\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/RTC-Counter-956x1024.gif 956w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/RTC-Counter-580x622.gif 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/RTC-Counter-768x823.gif 768w\" sizes=\"auto, (max-width: 956px) 100vw, 956px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/caOQTGAZXiQ?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Watchdog Timer &#8211; WDTA<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The prime task of a watchdog timer is to reset a microcontroller should there be any software irresponsiveness. MSP430F5529\u2019s watchdog timer, <em>WDTA<\/em> can be used like a regular watchdog timer as well as an interval timer. WDTA is similar to the previously seen WDT+ but it is a bit advanced in some areas like 32-bit counter instead of 16-bit counter. Shown below is the block diagram of WDTA:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"721\" height=\"807\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-2.png\" alt=\"\" class=\"wp-image-14628\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-2.png 721w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-2-580x650.png 580w\" sizes=\"auto, (max-width: 721px) 100vw, 721px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Unlike the watchdogs of many other microcontrollers, WDTA is password protected and it means that to read\/write it, a special code (<em>0x05A<\/em>) needs to be set first. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n\nvoid clock_init(void);\nvoid GPIO_init(void);\nvoid WDTA_init(void);\n\nvoid main(void)\n{\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    GPIO_init();\n    WDTA_init();\n\n    while(1)\n    {\n        GPIO_toggleOutputOnPin(GPIO_PORT_P1,\n                               GPIO_PIN0);\n\n        delay_ms(600);\n\n        WDT_A_resetTimer(WDT_A_BASE);\n\n        if(GPIO_getInputPinValue(GPIO_PORT_P1,\n                                 GPIO_PIN1) == false)\n        {\n            GPIO_setOutputHighOnPin(GPIO_PORT_P4,\n                                    GPIO_PIN7);\n\n            while(1);\n        }\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_FLLREF,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initFLLSettle(MCLK_KHZ,\n                      MCLK_FLLREF_RATIO);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_2);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1,\n                                         GPIO_PIN1);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P1,\n                        GPIO_PIN0);\n\n    GPIO_setDriveStrength(GPIO_PORT_P1,\n                          GPIO_PIN0,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n    GPIO_setDriveStrength(GPIO_PORT_P4,\n                          GPIO_PIN7,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setOutputLowOnPin(GPIO_PORT_P1,\n                           GPIO_PIN0);\n\n    GPIO_setOutputLowOnPin(GPIO_PORT_P4,\n                           GPIO_PIN7);\n}\n\nvoid WDTA_init(void)\n{\n    WDT_A_initWatchdogTimer(WDT_A_BASE,\n                            WDT_A_CLOCKSOURCE_VLOCLK,\n                            WDT_A_CLOCKDIVIDER_32K);\n\n    WDT_A_start(WDT_A_BASE);\n\n    WDT_A_resetTimer(WDT_A_BASE);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"942\" height=\"690\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/EXTILPM-and-WDTA-1.png\" alt=\"\" class=\"wp-image-14630\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/EXTILPM-and-WDTA-1.png 942w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/EXTILPM-and-WDTA-1-580x425.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/EXTILPM-and-WDTA-1-768x563.png 768w\" sizes=\"auto, (max-width: 942px) 100vw, 942px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">After power-on reset, WDTA is configured in watchdog mode with an approximate initial 32 ms reset interval. Unless commanded to stop immediately, it will keep resetting MCU. This is why at the start of every program the following code is placed:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">WDT_A_hold(WDT_A_BASE);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This piece of code disables WDTA until reconfigured and reused. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To setup WDTA in watchdog mode, we need to specify its source of clock signal. In this example, it is VLOCLK. We also need to decide the WDTA clock divider in order to achieve the required amount of period. &nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void WDTA_init(void)\n{\n    WDT_A_initWatchdogTimer(WDT_A_BASE, WDT_A_CLOCKSOURCE_VLOCLK, WDT_A_CLOCKDIVIDER_32K);\n\n    WDT_A_start(WDT_A_BASE);\n\n    WDT_A_resetTimer(WDT_A_BASE);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Here the time period according to the settings is about 3 seconds\n(32000 \/ 10 kHz). If WDTA is not reset within this time window, a reset will be\ntriggered. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the main, P1.0 LED is toggled every 600ms and WDTA is reset. Thus, WDTA counter is reset 5 times earlier than reset interval. This goes on until P1.1 push button is pressed. When the button is pressed, P4.7 LED is lit and a predefined intentional software loop is entered. Since WDTA counter is no longer reset in the loop, WDTA counter keeps ticking and a reset occurs after 3 seconds, starting everything from the beginning. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);\n\ndelay_ms(600);\n\nWDT_A_resetTimer(WDT_A_BASE);\n\nif(GPIO_getInputPinValue(GPIO_PORT_P1, GPIO_PIN1) == false)\n{\n   GPIO_setOutputHighOnPin(GPIO_PORT_P4, GPIO_PIN7);\n\n   while(1);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Note that after reset, RAM data are usually not erased unless modified or reinitialized. However, in real life applications, RAM data may be corrupted because something unusual caused the reset to occur. Therefore, we can use CRC or other means to check RAM data integrity if past data are needed. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"878\" height=\"1024\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/WDTA-1-878x1024.jpg\" alt=\"\" class=\"wp-image-14631\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/WDTA-1-878x1024.jpg 878w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/WDTA-1-557x650.jpg 557w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/WDTA-1-768x896.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/WDTA-1.jpg 1116w\" sizes=\"auto, (max-width: 878px) 100vw, 878px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"878\" height=\"1024\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/WDTA-2-878x1024.jpg\" alt=\"\" class=\"wp-image-14633\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/WDTA-2-878x1024.jpg 878w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/WDTA-2-557x650.jpg 557w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/WDTA-2-768x896.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/WDTA-2.jpg 1116w\" sizes=\"auto, (max-width: 878px) 100vw, 878px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/1EhM42_W_GY?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">WDTA as an Interval TimerWDTA as an Interval TimerWDTA as an Interval Timer<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">As mentioned before, WDTA can be used like an ordinary interval timer if watchdog function is not needed. This is strictly a secondary property of WDTA and there are some limitations of it. Still I would thank TI for this dexterity because sometimes in big projects people tend to run out of timers.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n\nvoid GPIO_init(void);\nvoid WDTA_init(void);\n\n#pragma vector = WDT_VECTOR\n__interrupt void WDT_A_ISR (void)\n{\n    GPIO_toggleOutputOnPin( GPIO_PORT_P1,\n                            GPIO_PIN0);\n\n    GPIO_toggleOutputOnPin( GPIO_PORT_P4,\n                            GPIO_PIN7);\n}\n\nvoid main(void)\n{\n    WDT_A_hold(WDT_A_BASE);\n\n    GPIO_init();\n    WDTA_init();\n\n    while(1)\n    {\n    };\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsOutputPin(GPIO_PORT_P1,\n                        GPIO_PIN0);\n\n    GPIO_setDriveStrength(GPIO_PORT_P1,\n                          GPIO_PIN0,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n\n    GPIO_setDriveStrength(GPIO_PORT_P4,\n                          GPIO_PIN7,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setOutputHighOnPin(GPIO_PORT_P1,\n                            GPIO_PIN0);\n\n    GPIO_setOutputLowOnPin(GPIO_PORT_P4,\n                           GPIO_PIN7);\n}\n\nvoid WDTA_init(void)\n{\n    WDT_A_initIntervalTimer(WDT_A_BASE,\n                            WDT_A_CLOCKSOURCE_SMCLK,\n                            WDT_A_CLOCKDIVIDER_512K);\n\n    SFR_clearInterrupt(SFR_WATCHDOG_INTERVAL_TIMER_INTERRUPT);\n\n    SFR_enableInterrupt(SFR_WATCHDOG_INTERVAL_TIMER_INTERRUPT);\n\n    WDT_A_start(WDT_A_BASE);\n\n    __enable_interrupt();\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"961\" height=\"685\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Free-Timer-RTC-Counter-WDT-Counter-2.png\" alt=\"\" class=\"wp-image-14634\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Free-Timer-RTC-Counter-WDT-Counter-2.png 961w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Free-Timer-RTC-Counter-WDT-Counter-2-580x413.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Free-Timer-RTC-Counter-WDT-Counter-2-768x547.png 768w\" sizes=\"auto, (max-width: 961px) 100vw, 961px\" \/><figcaption><br><\/figcaption><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"> <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The demo here is a simple LED toggler. On-board LEDs are used. UCS clock settings are untouched and so all clocks are in their defaults.  Firstly, WDTA is stopped to prevent a software reset. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">WDT_A_hold(WDT_A_BASE);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Configuration of WDTA in interval mode is nothing different from WDTA in watchdog mode. We have to specify WDTA clock source and its divider. Here the clock source is SMCLK and the divider is 512000. Since we are using default clock setting, SMCLK is running at about 1 MHz speed. Thus, dividing this speed with 512000 results in approximately 500 ms interval. We cannot access WDTA counter and so we will have to use interrupt method when using WDTA in interval mode. Thus, at every 500 ms an interrupt is triggered.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void WDTA_init(void)\n{\n    WDT_A_initIntervalTimer(WDT_A_BASE, WDT_A_CLOCKSOURCE_SMCLK, WDT_A_CLOCKDIVIDER_512K);\n\n    SFR_clearInterrupt(SFR_WATCHDOG_INTERVAL_TIMER_INTERRUPT);\n\n    SFR_enableInterrupt(SFR_WATCHDOG_INTERVAL_TIMER_INTERRUPT);\n\n    WDT_A_start(WDT_A_BASE);\n\n    __enable_interrupt();\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Inside the interrupt, on-board LED states are toggled. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#pragma vector = WDT_VECTOR\n__interrupt void WDT_A_ISR (void)\n{\n    GPIO_toggleOutputOnPin( GPIO_PORT_P1, GPIO_PIN0);\n\n    GPIO_toggleOutputOnPin( GPIO_PORT_P4, GPIO_PIN7);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">There is nothing done in the main loop and so it is empty. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"931\" height=\"1024\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/WDTA-Counter-931x1024.gif\" alt=\"\" class=\"wp-image-14635\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/WDTA-Counter-931x1024.gif 931w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/WDTA-Counter-580x638.gif 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/WDTA-Counter-768x845.gif 768w\" sizes=\"auto, (max-width: 931px) 100vw, 931px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/vfGtHR4QTi0?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Hardware Multiplier Module \u2013 MPY32<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Many high-end microcontrollers consist of internal hardware multiplier. So, what does this hardware do? Well a multiplier performs multiplication and simply that\u2019s it. Why is it important to have a hardware multiplier when we are coding in high-level C language and simple multiplication instruction is enough to do the job? Without hardware multiplier, multiplication is made possible by complex coding, i.e. by hidden software methods. Unlike dedicated hardware, software method takes time and uses resources since it is an emulated task. It is more like hardware rendering vs software rendering. We tend to like good graphics while playing games. A general-purpose computer without a dedicated graphics card may not properly run a game that has good graphical details. A gaming computer, on the other hand, has a dedicated graphics card and it can run the game with best performance. Just like the graphics card, a hardware multiplier is such a necessary hardware renderer that is often needed in time-limited complex computations and digital signal processing (DSP). <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"656\" height=\"675\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-3.png\" alt=\"\" class=\"wp-image-14636\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-3.png 656w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-3-580x597.png 580w\" sizes=\"auto, (max-width: 656px) 100vw, 656px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">MSP430F5529 has a 32-bit hardware multiplier named <strong><em>MPY32<\/em><\/strong>.\nLike DMA, it is not a part of the CPU and so it won\u2019t affect the operations of\nthe CPU when used. However, the CPU is needed to load and extract data from the\nmultiplier. It supports the following multiplications: <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u2022\nUnsigned multiply<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u2022\nSigned multiply<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u2022\nUnsigned multiply accumulate<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u2022\nSigned multiply accumulate<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u2022\n8-bit, 16-bit, 24-bit, and 32-bit operands<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u2022\nSaturation<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u2022\nFractional numbers<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u2022 8-bit\nand 16-bit operation compatible with 16-bit hardware multiplier<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u2022 8-bit and 24-bit multiplications without requiring\na &#8220;sign extend&#8221; instruction<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Software-based multiplication utilizes CPU and keeps it busy. Software multiplication is like repetitive addition. We don\u2019t see it happening because the whole process is done in machine\/assembly language level while we are coding in high-level C language. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"lcd.h\"\n#include \"lcd_print.h\"\n\nvoid clock_init(void);\nvoid timer_T0A5_init(void);\n\nvoid main(void)\n{\n    unsigned int i = 0;\n    unsigned int j = 0;\n\n    signed long res = 0;\n    signed int num1 = 263;\n    signed int num2 = 249;\n    unsigned int timer_count = 0;\n\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    timer_T0A5_init();\n\n    LCD_init();\n    LCD_clear_home();\n\n    LCD_goto(4, 0);\n    LCD_putstr(\"Software\");\n    LCD_goto(1, 1);\n    LCD_putstr(\"Multiplication\");\n\n    delay_ms(2000);\n    LCD_clear_home();\n\n    LCD_goto(0, 0);\n    LCD_putstr(\"263(x)249=\");\n    LCD_goto(0, 1);\n    LCD_putstr(\"T.CNT = \");\n\n    Timer_A_startCounter(__MSP430_BASEADDRESS_T0A5__,\n                         TIMER_A_CONTINUOUS_MODE);\n\n    for(i = 0; i &lt; num1; i++)\n    {\n        for(j = 0; j &lt; num2; j++)\n        {\n            res++;\n        }\n    }\n\n    timer_count = Timer_A_getCounterValue(__MSP430_BASEADDRESS_T0A5__);\n\n    Timer_A_stop(__MSP430_BASEADDRESS_T0A5__);\n\n    print_I(10, 0, res);\n    print_I(10, 1, timer_count);\n\n    delay_ms(4000);\n    LCD_clear_home();\n\n    res = 0;\n    timer_count = 0;\n    Timer_A_clear(__MSP430_BASEADDRESS_T0A5__);\n\n    LCD_goto(4, 0);\n    LCD_putstr(\"Hardware\");\n    LCD_goto(1, 1);\n    LCD_putstr(\"Multiplication\");\n\n    delay_ms(2000);\n    LCD_clear_home();\n\n    LCD_goto(0, 0);\n    LCD_putstr(\"263(x)249=\");\n    LCD_goto(0, 1);\n    LCD_putstr(\"T.CNT = \");\n\n    Timer_A_startCounter(__MSP430_BASEADDRESS_T0A5__,\n                         TIMER_A_CONTINUOUS_MODE);\n\n    MPY32_setOperandOne16Bit(MPY32_MULTIPLY_UNSIGNED,\n                             num1);\n\n    MPY32_setOperandTwo16Bit(num2);\n\n    res = MPY32_getResult();\n\n    timer_count = Timer_A_getCounterValue(__MSP430_BASEADDRESS_T0A5__);\n\n    Timer_A_stop(__MSP430_BASEADDRESS_T0A5__);\n\n    print_I(10, 0, res);\n    print_I(10, 1, timer_count);\n\n    delay_ms(4000);\n\n    num1 = -99;\n    num2 = 660;\n\n    LCD_clear_home();\n\n    LCD_goto(0, 0);\n    LCD_putstr(\"Signed Software\");\n    LCD_goto(1, 1);\n    LCD_putstr(\"Multiplication\");\n\n    delay_ms(2000);\n    LCD_clear_home();\n\n    LCD_goto(0, 0);\n    LCD_putstr(\"-99(x)660=\");\n    LCD_goto(0, 1);\n    LCD_putstr(\"T.CNT = \");\n\n    Timer_A_startCounter(__MSP430_BASEADDRESS_T0A5__,\n                         TIMER_A_CONTINUOUS_MODE);\n\n    res = (((signed long)num1) * ((signed long)num2));\n\n    timer_count = Timer_A_getCounterValue(__MSP430_BASEADDRESS_T0A5__);\n\n    Timer_A_stop(__MSP430_BASEADDRESS_T0A5__);\n\n    print_I(10, 0, res);\n    print_I(10, 1, timer_count);\n\n    delay_ms(4000);\n    LCD_clear_home();\n\n    res = 0;\n    timer_count = 0;\n\n    Timer_A_clear(__MSP430_BASEADDRESS_T0A5__);\n\n    LCD_goto(0, 0);\n    LCD_putstr(\"Signed Hardware\");\n    LCD_goto(1, 1);\n    LCD_putstr(\"Multiplication\");\n\n    delay_ms(2000);\n    LCD_clear_home();\n\n    LCD_goto(0, 0);\n    LCD_putstr(\"-99(x)660=\");\n    LCD_goto(0, 1);\n    LCD_putstr(\"T.CNT = \");\n\n    Timer_A_startCounter(__MSP430_BASEADDRESS_T0A5__,\n                         TIMER_A_CONTINUOUS_MODE);\n\n    MPY32_setOperandOne16Bit(MPY32_MULTIPLY_SIGNED,\n                             num1);\n\n    MPY32_setOperandTwo16Bit(num2);\n\n    res = MPY32_getResult();\n\n    timer_count = Timer_A_getCounterValue(__MSP430_BASEADDRESS_T0A5__);\n\n    Timer_A_stop(__MSP430_BASEADDRESS_T0A5__);\n\n    print_I(10, 0, res);\n    print_I(10, 1, timer_count);\n\n    while(1)\n    {\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_FLLREF,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initFLLSettle(MCLK_KHZ,\n                      MCLK_FLLREF_RATIO);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid timer_T0A5_init(void)\n{\n    Timer_A_initContinuousModeParam ContinuousModeParam =\n    {\n         TIMER_A_CLOCKSOURCE_SMCLK,\n         TIMER_A_CLOCKSOURCE_DIVIDER_1,\n         TIMER_A_TAIE_INTERRUPT_DISABLE,\n         TIMER_A_DO_CLEAR,\n         false\n    };\n\n    Timer_A_stop(__MSP430_BASEADDRESS_T0A5__);\n\n    Timer_A_initContinuousMode(__MSP430_BASEADDRESS_T0A5__,\n                               &amp;ContinuousModeParam);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"577\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/2LCD-MPY32-ADC-1-1024x577.png\" alt=\"\" class=\"wp-image-14637\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/2LCD-MPY32-ADC-1-1024x577.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/2LCD-MPY32-ADC-1-580x327.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/2LCD-MPY32-ADC-1-768x433.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/2LCD-MPY32-ADC-1.png 1358w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Explanation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For demoing the merits of having hardware multiplier, I coded a simple program that simply performs certain calculations and keep record of time count as to determine how long it took to perform the calculations. Two sorts of multiplications are performed both using hardware module and by software means. Same numbers are used in both cases. Timer TA0 is set with SMCLK having XT2_CLK source and no division. Thus, it is running at 4 MHz speed. No interrupt is used to keep things simple. The measure of time is taken as timer ticks and not as actual time in seconds or other units. The larger the value of ticks the longer is the time it took to perform a given calculation. The timer is started right before performing a calculation and stopped immediately after completing it.  <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void timer_T0A5_init(void)\n{\n    Timer_A_initContinuousModeParam ContinuousModeParam =\n    {\n         TIMER_A_CLOCKSOURCE_SMCLK,\n         TIMER_A_CLOCKSOURCE_DIVIDER_1,\n         TIMER_A_TAIE_INTERRUPT_DISABLE,\n         TIMER_A_DO_CLEAR,\n         false\n    };\n\n    Timer_A_stop(__MSP430_BASEADDRESS_T0A5__);\n\n    Timer_A_initContinuousMode(__MSP430_BASEADDRESS_T0A5__,\n                               &amp;ContinuousModeParam);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The first calculation is an unsigned multiplication of numbers <em>263<\/em> and <em>249<\/em>. As I stated before software multiplication is simply repetitive addition and the code below does exactly that:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">for(i = 0; i &lt; num1; i++)\n{\n    for(j = 0; j &lt; num2; j++)\n    {\n        res++;\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The numbers to be multiplied form loops and a variable called <em>res<\/em> is incremented on each loop passes. This, in effect, behaves like a rudimentary multiplication. The result of this multiplication is <em>65487<\/em>. It is revealed that this calculation takes about 13500 counts or about 3 ms.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The timer is cleared and restarted. This time however the hardware multiplier is used to multiply the same numbers again.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">MPY32_setOperandOne16Bit(MPY32_MULTIPLY_UNSIGNED, \n                         num1);\n\nMPY32_setOperandTwo16Bit(num2);\n\nres = MPY32_getResult();<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It is found that this time the same calculation takes just 17 ticks\nor about 4 \u00b5s. This shows that\nhardware multiplication is roughly 750 times faster than software multiplication.\n<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The same is done once more but this time using signed software multiplication of numbers <em>-99 <\/em>and <em>660<\/em>. This time however compiler\u2019s multiplication operator is used. The result of this calculation is <em>-65340<\/em>. It is found that it takes 36 timer ticks or 9 \u00b5s.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">res = (((signed long)num1) * ((signed long)num2));<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Again, the hardware multiplier is used for computing the same calculation and again it took 17 ticks or about 4 \u00b5s. Unlike the first example with unsigned numbers, the time difference is small this time because when the compiler sees multiplication operator, it performs multiplication in assembly\/ machine language level. Thus, time is reduced significantly but still it is not as fast as hardware-based multiplication.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"621\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-1-1024x621.jpg\" alt=\"\" class=\"wp-image-14638\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-1-1024x621.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-1-580x352.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-1-768x466.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-1.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"621\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-2-1024x621.jpg\" alt=\"\" class=\"wp-image-14639\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-2-1024x621.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-2-580x352.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-2-768x466.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-2.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"621\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-3-1024x621.jpg\" alt=\"\" class=\"wp-image-14640\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-3-1024x621.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-3-580x352.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-3-768x466.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-3.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"621\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-4-1024x621.jpg\" alt=\"\" class=\"wp-image-14641\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-4-1024x621.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-4-580x352.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-4-768x466.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/MYP32-4.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/Mjdlla198Q8?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Analogue Hardware Overview<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Except <strong><em>Digital-to-Analog Converter (DAC)<\/em><\/strong>,\nMSP430F5529 microcontroller offers two major analogue hardware peripherals \u2013 <strong><em>ADC12_A<\/em><\/strong>\nand <strong><em>Comp_B+<\/em><\/strong>. Additionally, there is an on-chip reference voltage\ngenerator called <strong><em>REF<\/em><\/strong> module that can generate pretty accurate\nvoltage references &#8211; 1.5V, 2.0V and 2.5V reference voltages.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As the name suggests ADC12_A is a fast 12-bit <strong><em>Analogue-to-Digital Converter (ADC)<\/em><\/strong>. Since it has higher resolution compared to other typical 8-bit and 10-bit ADCs of other microcontrollers, it much more precise when it comes to reading analogue voltages. MSP430s usually pack SAR ADCs and the ADC12_A of MSP430F559 is a 200+ ksps <strong><em>Successive Approximation (SAR)<\/em><\/strong> ADC. ADC12_A has an internal temperature sensor and REF module\u2019s reference voltages can be used with ADC12_A for more precise measurements. It is also possible to use external sources. Positive and negative references can be independently selected. Sample-and-hold circuitry offers programmable sampling periods via timers or software. In MSP430F5529, there are 16 individually configurable input channels &#8211; 12 external input channels and 4 internal input channels. There also 16 buffer registers to store AD conversion data. Since MSP430F5529 hosts a<strong><em> Direct-Memory-Access (DMA)<\/em><\/strong> peripheral, it can be combined with ADC12_A and we can get some more interesting effects. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"794\" height=\"746\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-4.png\" alt=\"\" class=\"wp-image-14642\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-4.png 794w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-4-580x545.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-4-768x722.png 768w\" sizes=\"auto, (max-width: 794px) 100vw, 794px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">A comparator compares two analogue voltage levels. This comparison results in an indication of which signal is at a higher\/lower voltage level than the other. In simple terms, it is a one-bit ADC. Though it may look that a comparator is unnecessary when we have a good built-in ADC, it is otherwise. A comparator is a very important analogue building block. It is helpful in places where knowing voltage levels is more important the voltage itself. This makes it faster than an ADC in such cases. Owing to this a whole lot of electronics is based on it. Examples of such electronics include oscillators, level sensing, VU meters, capacitive touch sensing, measurement devices, etc. A LC meter is a perfect example. A LC meter is usually based on an oscillator. This oscillator uses a comparator. Its frequency varies with the L and C components, oscillating at a fixed frequency with known L and C values. Measuring frequency shifts as a result of changing L\/C values leads us to measure unknown L\/C effectively. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1005\" height=\"656\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-5.png\" alt=\"\" class=\"wp-image-14643\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-5.png 1005w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-5-580x379.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/block-5-768x501.png 768w\" sizes=\"auto, (max-width: 1005px) 100vw, 1005px\" \/><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">REF Module and ADC12 in Polling Mode<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Good ADC performance and accurate readings depend on good reference sources. The stable these reference sources are with respect to changes in temperature and input voltage fluctuations, the better the ADC readings. &nbsp;MSP430F5529 is equipped with a built-in reference source generator module called <strong><em>REF<\/em><\/strong> module that is able to generate 1.5V, 2.0V and 2.5V with good precision. REF module has good temperature coefficients and power-saving features. REF module doesn\u2019t restrict us from using external reference sources but since they are available internally and factory trimmed, it is better to use them to reduce external parts count and avoid unnecessary hassle. The highlighted region in ADC12\u2019s block diagram shown below shows the components of MSP430F5529\u2019s REF module. A quick view reveals how they are connected with the ADC.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"794\" height=\"746\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ref.png\" alt=\"\" class=\"wp-image-14645\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ref.png 794w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ref-580x545.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ref-768x722.png 768w\" sizes=\"auto, (max-width: 794px) 100vw, 794px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"> ADC12 is perhaps simply understood without the use of DMA and interrupts. ADC12 is configured and started. Readings of ADC channels are stored in ADC memory locations after conversions. Reading ADC memories give out last conversion results. In this example, we will see exactly that and we will be reading MSP430\u2019s internal temperature sensor with the ADC. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"lcd.h\"\n#include \"lcd_print.h\"\n\nvoid clock_init(void);\nvoid GPIO_init(void);\nvoid ADC12_init(void);\nvoid REF_init(void);\n\nvoid main(void)\n{\n    signed int ADC_Count = 0;\n    signed long temp = 0;\n\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    GPIO_init();\n    REF_init();\n    ADC12_init();\n\n    LCD_init();\n    LCD_clear_home();\n    load_custom_symbol();\n\n    LCD_goto(0, 0);\n    LCD_putstr(\"ADC :\");\n\n    LCD_goto(0, 1);\n    LCD_putstr(\"T\/ C:\");\n    print_symbol(2, 1, 0);\n\n    while(1)\n    {\n        ADC_Count = ADC12_A_getResults(ADC12_A_BASE,\n                                       ADC12_A_MEMORY_0);\n\n        temp = ((((signed long)ADC_Count - 1855) * 667) \/ 4096);\n\n        print_I(11, 0, ADC_Count);\n        print_I(13, 1, temp);\n\n        delay_ms(200);\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_FLLREF,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initFLLSettle(MCLK_KHZ,\n                      MCLK_FLLREF_RATIO);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_2);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n}\n\n\nvoid ADC12_init(void)\n{\n    ADC12_A_configureMemoryParam configureMemoryParam = {0};\n\n    ADC12_A_init(ADC12_A_BASE,\n                 ADC12_A_SAMPLEHOLDSOURCE_SC,\n                 ADC12_A_CLOCKSOURCE_ACLK,\n                 ADC12_A_CLOCKDIVIDER_1);\n\n    ADC12_A_setupSamplingTimer(ADC12_A_BASE,\n                               ADC12_A_CYCLEHOLD_768_CYCLES,\n                               ADC12_A_CYCLEHOLD_4_CYCLES,\n                               ADC12_A_MULTIPLESAMPLESENABLE);\n\n    ADC12_A_setResolution(ADC12_A_BASE,\n                          ADC12_A_RESOLUTION_12BIT);\n\n    configureMemoryParam.memoryBufferControlIndex = ADC12_A_MEMORY_0;\n    configureMemoryParam.inputSourceSelect = ADC12_A_INPUT_TEMPSENSOR;\n    configureMemoryParam.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_INT;\n    configureMemoryParam.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;\n    configureMemoryParam.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;\n\n    ADC12_A_configureMemory(ADC12_A_BASE,\n                            &amp;configureMemoryParam);\n\n    ADC12_A_enable(ADC12_A_BASE);\n\n    ADC12_A_startConversion(ADC12_A_BASE,\n                            ADC12_A_MEMORY_0,\n                            ADC12_A_REPEATED_SINGLECHANNEL);\n}\n\nvoid REF_init(void)\n{\n    while(REF_ACTIVE == Ref_isRefGenBusy(REF_BASE));\n\n    Ref_setReferenceVoltage(REF_BASE,\n                            REF_VREF1_5V);\n\n    Ref_enableReferenceVoltage(REF_BASE);\n\n    __delay_cycles(100);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"577\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/2LCD-MPY32-ADC-2-1024x577.png\" alt=\"\" class=\"wp-image-14646\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/2LCD-MPY32-ADC-2-1024x577.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/2LCD-MPY32-ADC-2-580x327.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/2LCD-MPY32-ADC-2-768x433.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/2LCD-MPY32-ADC-2.png 1358w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s see first how the REF module is configured. REF module is not clock dependent as like other hardware and doesn\u2019t require use of any external pin.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void REF_init(void)\n{\n    while(REF_ACTIVE == Ref_isRefGenBusy(REF_BASE));\n    Ref_setReferenceVoltage(REF_BASE, REF_VREF1_5V);\n    Ref_enableReferenceVoltage(REF_BASE);\n    __delay_cycles(100);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Using REF module is very easy. We first check its state. We set our desired reference voltage. Here we need the 1.5V reference. After selection, we enable it and wait for some time to get it settled.&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void ADC12_init(void)\n{\n    ADC12_A_configureMemoryParam configureMemoryParam = {0};\n\n    ADC12_A_init(ADC12_A_BASE,\n                 ADC12_A_SAMPLEHOLDSOURCE_SC,\n                 ADC12_A_CLOCKSOURCE_ACLK,\n                 ADC12_A_CLOCKDIVIDER_1);\n\n    ADC12_A_setupSamplingTimer(ADC12_A_BASE,\n                               ADC12_A_CYCLEHOLD_768_CYCLES,\n                               ADC12_A_CYCLEHOLD_4_CYCLES,\n                               ADC12_A_MULTIPLESAMPLESENABLE);\n\n    ADC12_A_setResolution(ADC12_A_BASE, ADC12_A_RESOLUTION_12BIT);\n\n    configureMemoryParam.memoryBufferControlIndex = ADC12_A_MEMORY_0;\n    configureMemoryParam.inputSourceSelect = ADC12_A_INPUT_TEMPSENSOR;\n    configureMemoryParam.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_INT;\n    configureMemoryParam.negativeRefVoltageSourceSelect =                                      ADC12_A_VREFNEG_AVSS;\n    configureMemoryParam.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;\n\n    ADC12_A_configureMemory(ADC12_A_BASE, &amp;configureMemoryParam);\n\n    ADC12_A_enable(ADC12_A_BASE);\n\n    ADC12_A_startConversion(ADC12_A_BASE,\n                            ADC12_A_MEMORY_0,\n                            ADC12_A_REPEATED_SINGLECHANNEL);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We are not using any external channel and so there is no special pin setup for ADC12. As with any hardware, the source of ADC12\u2019s clock is set first. Here the clock source is unscaled ACLK.  <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">UCS_initClockSignal(UCS_ACLK, UCS_XT1CLK_SELECT, UCS_CLOCK_DIVIDER_1);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">ACLK is fed with an external 32.768 kHz XT1 crystal running at\n32.768 kHz.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next, we set the sampling timer by defining the sample-hold times.\nWe also set the ADC\u2019s resolution to 12 bits. We can also set 8 and 10\nresolution if required. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We also have to let the ADC know which ADC channel to read, where to\nstore the readings and what the reference voltages are for the ADC block. Note\nthat the reference voltage source is the 1.5V source.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We, finally, start the ADC and leave it in repeated single channel conversion mode. In this way, the ADC will continuously measure our desired channel and store readings in an ADC memory location (here Memory 0).<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"386\" height=\"319\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/temp.png\" alt=\"\" class=\"wp-image-14647\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">From the graph shown above, we can see that the voltage (ultimately\nADC count) vs temperature relationship of the internal temperature sensor is a\nperfect straight-line and so a linear equation will be needed to describe this\nrelationship. Now if we know the ADC count of the internal temperature sensor,\nwe can determine MSP430\u2019s core temperature. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the main loop, as I stated earlier, ADC memory 0 location is read and the reading is converted to temperature. The ADC count and the temperature are then shown on an LCD display. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ADC_Count = ADC12_A_getResults(ADC12_A_BASE, ADC12_A_MEMORY_0);\n\ntemp = ((((signed long)ADC_Count - 1855) * 667) \/ 4096);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"620\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-Polling-1024x620.jpg\" alt=\"\" class=\"wp-image-14648\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-Polling-1024x620.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-Polling-580x351.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-Polling-768x465.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-Polling.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/yJVYkq0gBxI?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h3 class=\"wp-block-heading\">ADC12 Interrupt<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">ADC interrupt is as important as timer and communication interrupts. We can do other tasks while ADC is performing a conversion. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"lcd.h\"\n#include \"lcd_print.h\"\n\nunsigned long cnt = 0;\n\nvoid clock_init(void);\nvoid GPIO_init(void);\nvoid ADC12_init(void);\n\n#pragma vector = ADC12_VECTOR\n__interrupt void ADC12ISR (void)\n{\n    switch (__even_in_range(ADC12IV, 34))\n    {\n        case  0: break;   \/\/Vector  0:  No interrupt\n        case  2: break;   \/\/Vector  2:  ADC overflow\n        case  4: break;   \/\/Vector  4:  ADC timing overflow\n        case  6:          \/\/Vector  6:  ADC12IFG0\n        {\n            cnt = ADC12_A_getResults(ADC12_A_BASE,\n                                     ADC12_A_MEMORY_0);\n            break;\n        }\n        case  8: break;   \/\/Vector  8:  ADC12IFG1\n        case 10: break;   \/\/Vector 10:  ADC12IFG2\n        case 12: break;   \/\/Vector 12:  ADC12IFG3\n        case 14: break;   \/\/Vector 14:  ADC12IFG4\n        case 16: break;   \/\/Vector 16:  ADC12IFG5\n        case 18: break;   \/\/Vector 18:  ADC12IFG6\n        case 20: break;   \/\/Vector 20:  ADC12IFG7\n        case 22: break;   \/\/Vector 22:  ADC12IFG8\n        case 24: break;   \/\/Vector 24:  ADC12IFG9\n        case 26: break;   \/\/Vector 26:  ADC12IFG10\n        case 28: break;   \/\/Vector 28:  ADC12IFG11\n        case 30: break;   \/\/Vector 30:  ADC12IFG12\n        case 32: break;   \/\/Vector 32:  ADC12IFG13\n        case 34: break;   \/\/Vector 34:  ADC12IFG14\n        default: break;\n    }\n}\n\nvoid main(void)\n{\n    unsigned long volts = 0;\n\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    GPIO_init();\n    ADC12_init();\n\n    LCD_init();\n    LCD_clear_home();\n\n    LCD_goto(0, 0);\n    LCD_putstr(\"ADC Count:\");\n\n    LCD_goto(0, 1);\n    LCD_putstr(\"Volts\/mV :\");\n\n    while(1)\n    {\n        volts = ((cnt * 3300) \/ 4095);\n        print_I(11, 0, cnt);\n        print_I(11, 1, volts);\n        delay_ms(100);\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_FLLREF,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initFLLSettle(MCLK_KHZ,\n                      MCLK_FLLREF_RATIO);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_2);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P6,\n                                               GPIO_PIN0);\n}\n\n\nvoid ADC12_init(void)\n{\n    ADC12_A_configureMemoryParam configureMemoryParam = {0};\n\n    ADC12_A_init(ADC12_A_BASE,\n                 ADC12_A_SAMPLEHOLDSOURCE_SC,\n                 ADC12_A_CLOCKSOURCE_ACLK,\n                 ADC12_A_CLOCKDIVIDER_1);\n\n    ADC12_A_setupSamplingTimer(ADC12_A_BASE,\n                               ADC12_A_CYCLEHOLD_768_CYCLES,\n                               ADC12_A_CYCLEHOLD_4_CYCLES,\n                               ADC12_A_MULTIPLESAMPLESENABLE);\n\n    ADC12_A_setResolution(ADC12_A_BASE,\n                          ADC12_A_RESOLUTION_12BIT);\n\n    configureMemoryParam.memoryBufferControlIndex = ADC12_A_MEMORY_0;\n    configureMemoryParam.inputSourceSelect = ADC12_A_INPUT_A0;\n    configureMemoryParam.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;\n    configureMemoryParam.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;\n    configureMemoryParam.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;\n\n    ADC12_A_configureMemory(ADC12_A_BASE,\n                            &amp;configureMemoryParam);\n\n    ADC12_A_clearInterrupt(ADC12_A_BASE,\n                           ADC12IFG0);\n\n    ADC12_A_enableInterrupt(ADC12_A_BASE,\n                            ADC12IE0);\n\n    __enable_interrupt();\n\n    ADC12_A_enable(ADC12_A_BASE);\n\n    ADC12_A_startConversion(ADC12_A_BASE,\n                            ADC12_A_MEMORY_0,\n                            ADC12_A_REPEATED_SINGLECHANNEL);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"643\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-ISR-1024x643.png\" alt=\"\" class=\"wp-image-14649\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-ISR-1024x643.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-ISR-580x364.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-ISR-768x482.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-ISR.png 1218w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This example is similar to the last one in many\naspects. I won\u2019t be going through all settings. I\u2019ll only highlight the key\ndifferences. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This time an external ADC channel is used and so we have to initialize the alternative role of its pin.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P6, GPIO_PIN0);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In the ADC12 initialization, the external input pin or the ADC channel\u2019s physical pin is set after its GPIO initialization. Unlike the last ADC example in which we used internal 1.5V reference source, the positive reference source for ADC this time is set to <em>AVCC<\/em>. <em>AVSS<\/em> is the negative voltage source for both examples. <em>AVCC<\/em> is same as the system bus voltage, i.e. 3.3V.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">configureMemoryParam.inputSourceSelect = ADC12_A_INPUT_A0;\nconfigureMemoryParam.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;\nconfigureMemoryParam.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Since we are using interrupt method, relevant interrupt flag is cleared first and then enabled.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ADC12_A_clearInterrupt(ADC12_A_BASE, ADC12IFG0);\nADC12_A_enableInterrupt(ADC12_A_BASE, ADC12IE0);    \n__enable_interrupt();<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In this case the 0<sup>th<\/sup> ADC interrupt flag is used since the channel to be read is the 0<sup>th<\/sup> channel of the ADC. Don\u2019t confuse interrupt vector number with interrupt flag number. Interrupt vector number for 0<sup>th<\/sup> ADC interrupt flag is 6.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#pragma vector = ADC12_VECTOR\n__interrupt void ADC12ISR (void)\n{\n    switch (__even_in_range(ADC12IV, 34))\n    {\n        case  0: break;   \/\/Vector  0:  No interrupt\n        case  2: break;   \/\/Vector  2:  ADC overflow\n        case  4: break;   \/\/Vector  4:  ADC timing overflow\n        case  6:          \/\/Vector  6:  ADC12IFG0\n        {\n            cnt = ADC12_A_getResults(ADC12_A_BASE,\n                                     ADC12_A_MEMORY_0);\n            break;\n        }\n        case  8: break;   \/\/Vector  8:  ADC12IFG1\n        case 10: break;   \/\/Vector 10:  ADC12IFG2\n        case 12: break;   \/\/Vector 12:  ADC12IFG3\n        case 14: break;   \/\/Vector 14:  ADC12IFG4\n        case 16: break;   \/\/Vector 16:  ADC12IFG5\n        case 18: break;   \/\/Vector 18:  ADC12IFG6\n        case 20: break;   \/\/Vector 20:  ADC12IFG7\n        case 22: break;   \/\/Vector 22:  ADC12IFG8\n        case 24: break;   \/\/Vector 24:  ADC12IFG9\n        case 26: break;   \/\/Vector 26:  ADC12IFG10\n        case 28: break;   \/\/Vector 28:  ADC12IFG11\n        case 30: break;   \/\/Vector 30:  ADC12IFG12\n        case 32: break;   \/\/Vector 32:  ADC12IFG13\n        case 34: break;   \/\/Vector 34:  ADC12IFG14\n        default: break;\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">ADC interrupt triggers when a new result is loaded in ADC memory location. Inside the interrupt ADC memory location 0 is read to get the conversion result, i.e. ADC count. When the ADC memory is accessed, its interrupt flag is automatically cleared.&nbsp; <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the main loop, the ADC count derived from the ADC interrupt is converted to voltage. Both the voltage and ADC count are displayed on an alphanumerical LCD.  <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">volts = ((cnt * 3300) \/ 4095);\nprint_I(11, 0, cnt);\nprint_I(11, 1, volts);\ndelay_ms(100);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"713\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-ISR-1024x713.jpg\" alt=\"\" class=\"wp-image-14651\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-ISR-1024x713.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-ISR-580x404.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-ISR-768x535.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-ISR.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/iAb3Fth1dXM?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">ADC12 Sampling Multiple Input<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Till now, we have seen only one ADC channel in action. We have seen examples of single internal and external channels only. However, in real-life and in many occasions, we may need the use of more than one ADC channel. For example, we will need multiple ADC channels when crafting an Uninterrupted Power Supply (UPS). In an UPS, we will be needing to measure battery voltage, battery charging and discharging current, AC output voltage and current, internal temperature and so on. In such cases, multiple ADC channels are musts. This example demonstrates how to use multiple ADC channels of a MSP430F5529 microcontroller.&nbsp; <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"lcd.h\"\n#include \"lcd_print.h\"\n\nunsigned long res[2] = {0, 0};\n\nvoid clock_init(void);\nvoid GPIO_init(void);\nvoid ADC12_init(void);\n\n#pragma vector = ADC12_VECTOR\n__interrupt void ADC12ISR (void)\n{\n    switch (__even_in_range(ADC12IV, 34))\n    {\n        case  0: break;   \/\/Vector  0:  No interrupt\n        case  2: break;   \/\/Vector  2:  ADC overflow\n        case  4: break;   \/\/Vector  4:  ADC timing overflow\n        case  6: break;   \n  {\n\t\tres[0] = ADC12_A_getResults(ADC12_A_BASE,\n                                        ADC12_A_MEMORY_0);\n            break;\n  }\t\t \t \/\/Vector  6:  ADC12IFG0\n        case  8:\n        {\n            res[1] = ADC12_A_getResults(ADC12_A_BASE,\n                                        ADC12_A_MEMORY_1);\n            break;\n        }                 \/\/Vector  8:  ADC12IFG1\n        case 10: break;   \/\/Vector 10:  ADC12IFG2\n        case 12: break;   \/\/Vector 12:  ADC12IFG3\n        case 14: break;   \/\/Vector 14:  ADC12IFG4\n        case 16: break;   \/\/Vector 16:  ADC12IFG5\n        case 18: break;   \/\/Vector 18:  ADC12IFG6\n        case 20: break;   \/\/Vector 20:  ADC12IFG7\n        case 22: break;   \/\/Vector 22:  ADC12IFG8\n        case 24: break;   \/\/Vector 24:  ADC12IFG9\n        case 26: break;   \/\/Vector 26:  ADC12IFG10\n        case 28: break;   \/\/Vector 28:  ADC12IFG11\n        case 30: break;   \/\/Vector 30:  ADC12IFG12\n        case 32: break;   \/\/Vector 32:  ADC12IFG13\n        case 34: break;   \/\/Vector 34:  ADC12IFG14\n        default: break;\n    }\n}\n\nvoid main(void)\n{\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    GPIO_init();\n    ADC12_init();\n\n    LCD_init();\n    LCD_clear_home();\n\n    LCD_goto(0, 0);\n    LCD_putstr(\"CH0:\");\n\n    LCD_goto(0, 1);\n    LCD_putstr(\"CH1:\");\n\n    while(1)\n    {\n\n        print_I(11, 0, res[0]);\n        print_I(11, 1, res[1]);\n        delay_ms(100);\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_FLLREF,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initFLLSettle(MCLK_KHZ,\n                      MCLK_FLLREF_RATIO);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_2);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P6,\n                                               (GPIO_PIN0 | GPIO_PIN1));\n}\n\nvoid ADC12_init(void)\n{\n    ADC12_A_configureMemoryParam CH0_configureMemoryParam = {0};\n    ADC12_A_configureMemoryParam CH1_configureMemoryParam = {0};\n\n    CH0_configureMemoryParam.memoryBufferControlIndex = ADC12_A_MEMORY_0;\n    CH0_configureMemoryParam.inputSourceSelect = ADC12_A_INPUT_A0;\n    CH0_configureMemoryParam.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;\n    CH0_configureMemoryParam.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;\n    CH0_configureMemoryParam.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;\n\n    CH1_configureMemoryParam.memoryBufferControlIndex = ADC12_A_MEMORY_1;\n    CH1_configureMemoryParam.inputSourceSelect = ADC12_A_INPUT_A1;\n    CH1_configureMemoryParam.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;\n    CH1_configureMemoryParam.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;\n    CH1_configureMemoryParam.endOfSequence = ADC12_A_ENDOFSEQUENCE;\n\n    ADC12_A_init(ADC12_A_BASE,\n                 ADC12_A_SAMPLEHOLDSOURCE_SC,\n                 ADC12_A_CLOCKSOURCE_ACLK,\n                 ADC12_A_CLOCKDIVIDER_1);\n\n    ADC12_A_setupSamplingTimer(ADC12_A_BASE,\n                               ADC12_A_CYCLEHOLD_256_CYCLES,\n                               ADC12_A_CYCLEHOLD_4_CYCLES,\n                               ADC12_A_MULTIPLESAMPLESENABLE);\n\n    ADC12_A_setResolution(ADC12_A_BASE,\n                          ADC12_A_RESOLUTION_12BIT);\n\n    ADC12_A_configureMemory(ADC12_A_BASE,\n                            &amp;CH0_configureMemoryParam);\n\n    ADC12_A_configureMemory(ADC12_A_BASE,\n                            &amp;CH1_configureMemoryParam);\n\n    ADC12_A_clearInterrupt(ADC12_A_BASE,\n                           ADC12IFG0);\n\n    ADC12_A_enableInterrupt(ADC12_A_BASE,\n                            ADC12IE0);\t\n\n    ADC12_A_clearInterrupt(ADC12_A_BASE,\n                           ADC12IFG1);\n\n    ADC12_A_enableInterrupt(ADC12_A_BASE,\n                            ADC12IE1);\n\n    __enable_interrupt();\n\n    ADC12_A_enable(ADC12_A_BASE);\n\n    ADC12_A_startConversion(ADC12_A_BASE,\n                            ADC12_A_MEMORY_0,\n                            ADC12_A_REPEATED_SEQOFCHANNELS);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"644\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-2ch-1024x644.png\" alt=\"\" class=\"wp-image-14652\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-2ch-1024x644.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-2ch-580x364.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-2ch-768x483.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-2ch.png 1273w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">ADC12\u2019s settings have two sections. One is common and the other is\nchannel dependent. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Common settings include ADC\u2019s clock setup, resolution and sample-hold timer settings. These will be applicable for all channels. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ADC12_A_init(ADC12_A_BASE,\n             ADC12_A_SAMPLEHOLDSOURCE_SC,\n             ADC12_A_CLOCKSOURCE_ACLK,\n             ADC12_A_CLOCKDIVIDER_1);\n\nADC12_A_setupSamplingTimer(ADC12_A_BASE,\n                           ADC12_A_CYCLEHOLD_256_CYCLES,\n                           ADC12_A_CYCLEHOLD_4_CYCLES,\n                           ADC12_A_MULTIPLESAMPLESENABLE);\n\nADC12_A_setResolution(ADC12_A_BASE, ADC12_A_RESOLUTION_12BIT);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Channel parameters define ADC memory location, references and sequence info. Additionally, if interrupts are used, they need to applied separately. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">CH0_configureMemoryParam.memoryBufferControlIndex = ADC12_A_MEMORY_0;\nCH0_configureMemoryParam.inputSourceSelect = ADC12_A_INPUT_A0;\nCH0_configureMemoryParam.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;\nCH0_configureMemoryParam.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;\nCH0_configureMemoryParam.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;\n\nCH1_configureMemoryParam.memoryBufferControlIndex = ADC12_A_MEMORY_1;\nCH1_configureMemoryParam.inputSourceSelect = ADC12_A_INPUT_A1;\nCH1_configureMemoryParam.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;\nCH1_configureMemoryParam.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;\nCH1_configureMemoryParam.endOfSequence = ADC12_A_ENDOFSEQUENCE;\n\n....\n\nADC12_A_clearInterrupt(ADC12_A_BASE, ADC12IFG0);\nADC12_A_enableInterrupt(ADC12_A_BASE, ADC12IE0);\n\nADC12_A_configureMemory(ADC12_A_BASE, &amp;CH0_configureMemoryParam);\n\t\nADC12_A_clearInterrupt(ADC12_A_BASE, ADC12IFG1);\nADC12_A_enableInterrupt(ADC12_A_BASE, ADC12IE1);\n\nADC12_A_configureMemory(ADC12_A_BASE, &amp;CH1_configureMemoryParam);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">At this point, I would like to highlight the concept of sequence. When\nmultiple ADC channels are used, ADC conversions are done sequentially, i.e. one\nafter another. In our code, we have to specify one channel as the end of\nsequence while denoting other channels as no end of sequence. In this way,\nchannels are systematically queued. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">ADC reading process is same as the one we saw in the ADC interrupt example. The only exception is the usage of two vectors as two channels are in different memory planes.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#pragma vector = ADC12_VECTOR\n__interrupt void ADC12ISR (void)\n{\n    switch (__even_in_range(ADC12IV, 34))\n    {\n        case  0: break;   \/\/Vector  0:  No interrupt\n        case  2: break;   \/\/Vector  2:  ADC overflow\n        case  4: break;   \/\/Vector  4:  ADC timing overflow\n        case  6: break;   \n  {\n\t\tres[0] = ADC12_A_getResults(ADC12_A_BASE,\n                                        ADC12_A_MEMORY_0);\n            break;\n  }\t\t \t \/\/Vector  6:  ADC12IFG0\n        case  8:\n        {\n            res[1] = ADC12_A_getResults(ADC12_A_BASE,\n                                        ADC12_A_MEMORY_1);\n            break;\n        }                 \/\/Vector  8:  ADC12IFG1\n        case 10: break;   \/\/Vector 10:  ADC12IFG2\n        case 12: break;   \/\/Vector 12:  ADC12IFG3\n        case 14: break;   \/\/Vector 14:  ADC12IFG4\n        case 16: break;   \/\/Vector 16:  ADC12IFG5\n        case 18: break;   \/\/Vector 18:  ADC12IFG6\n        case 20: break;   \/\/Vector 20:  ADC12IFG7\n        case 22: break;   \/\/Vector 22:  ADC12IFG8\n        case 24: break;   \/\/Vector 24:  ADC12IFG9\n        case 26: break;   \/\/Vector 26:  ADC12IFG10\n        case 28: break;   \/\/Vector 28:  ADC12IFG11\n        case 30: break;   \/\/Vector 30:  ADC12IFG12\n        case 32: break;   \/\/Vector 32:  ADC12IFG13\n        case 34: break;   \/\/Vector 34:  ADC12IFG14\n        default: break;\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"819\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-Multi-1024x819.jpg\" alt=\"\" class=\"wp-image-14653\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-Multi-1024x819.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-Multi-580x464.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-Multi-768x614.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-Multi.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/03TEEj95lM8?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">ADC12 and Direct Memory Access (DMA) Module <\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Apart from interrupt method, there is another way to doing AD conversions without polling\/waiting. This involves DMA-backed AD conversion. DMA hardware is not a part of the ADC. In simple terms, it is rather more like a separate data pipeline bus that can be used without much interaction from the CPU. DMA-based AD conversions are in that way very silent. DMA can send AD conversion readings directly to user-defined memory locations automatically without any intervention. DMA can also be used for other hardware like SPI and UART. Shown below is the DMA block diagram of MSP430F5529:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"604\" height=\"781\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DMA-Block.png\" alt=\"\" class=\"wp-image-14655\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DMA-Block.png 604w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DMA-Block-503x650.png 503w\" sizes=\"auto, (max-width: 604px) 100vw, 604px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"lcd.h\"\n#include \"lcd_print.h\"\n\nvoid clock_init(void);\nvoid GPIO_init(void);\nvoid ADC12_init(void);\nvoid DMA_HW_init(void);\n\nuint16_t memory_location = 0x0000;\n\n#pragma vector = DMA_VECTOR\n__interrupt void DMA_ISR (void)\n{\n    switch (__even_in_range(DMAIV, 16))\n    {\n        case 0: break;  \/\/None\n        case 2:         \/\/DMA0IFG = DMA Channel 0\n        {\n            GPIO_toggleOutputOnPin(GPIO_PORT_P1,\n                                   GPIO_PIN0);\n\n            break;\n        }\n        case 4: break;  \/\/DMA1IFG = DMA Channel 1\n        case 6: break;  \/\/DMA2IFG = DMA Channel 2\n        case 8: break;  \/\/DMA3IFG = DMA Channel 3\n        case 10: break; \/\/DMA4IFG = DMA Channel 4\n        case 12: break; \/\/DMA5IFG = DMA Channel 5\n        case 14: break; \/\/DMA6IFG = DMA Channel 6\n        case 16: break; \/\/DMA7IFG = DMA Channel 7\n        default: break;\n    }\n}\n\nvoid main(void)\n{\n    unsigned int volt = 0;\n\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    GPIO_init();\n    ADC12_init();\n    DMA_HW_init();\n\n    LCD_init();\n    LCD_clear_home();\n\n    LCD_goto(0, 0);\n    LCD_putstr(\"ADC :\");\n\n    LCD_goto(0, 1);\n    LCD_putstr(\"V\/mV:\");\n\n    while(1)\n    {\n        volt = ((memory_location * 3300.0) \/ 4095.0);\n\n        print_I(11, 0, memory_location);\n        print_I(11, 1, volt);\n\n        GPIO_toggleOutputOnPin(GPIO_PORT_P4,\n                               GPIO_PIN7);\n        delay_ms(200);\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_FLLREF,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initFLLSettle(MCLK_KHZ,\n                      MCLK_FLLREF_RATIO);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_2);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P6,\n                                               GPIO_PIN0);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P1,\n                        GPIO_PIN0);\n\n    GPIO_setDriveStrength(GPIO_PORT_P1,\n                          GPIO_PIN0,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n\n    GPIO_setDriveStrength(GPIO_PORT_P4,\n                          GPIO_PIN7,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n}\n\n\nvoid ADC12_init(void)\n{\n    ADC12_A_configureMemoryParam configureMemoryParam = {0};\n\n    ADC12_A_init(ADC12_A_BASE,\n                 ADC12_A_SAMPLEHOLDSOURCE_SC,\n                 ADC12_A_CLOCKSOURCE_ACLK,\n                 ADC12_A_CLOCKDIVIDER_1);\n\n    ADC12_A_setupSamplingTimer(ADC12_A_BASE,\n                               ADC12_A_CYCLEHOLD_768_CYCLES,\n                               ADC12_A_CYCLEHOLD_4_CYCLES,\n                               ADC12_A_MULTIPLESAMPLESENABLE);\n\n    ADC12_A_setResolution(ADC12_A_BASE,\n                          ADC12_A_RESOLUTION_12BIT);\n\n    configureMemoryParam.memoryBufferControlIndex = ADC12_A_MEMORY_0;\n    configureMemoryParam.inputSourceSelect = ADC12_A_INPUT_A0;\n    configureMemoryParam.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;\n    configureMemoryParam.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;\n    configureMemoryParam.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;\n\n    ADC12_A_configureMemory(ADC12_A_BASE,\n                            &amp;configureMemoryParam);\n\n    ADC12_A_enable(ADC12_A_BASE);\n\n    ADC12_A_startConversion(ADC12_A_BASE,\n                            ADC12_A_MEMORY_0,\n                            ADC12_A_REPEATED_SINGLECHANNEL);\n}\n\nvoid DMA_HW_init(void)\n{\n    DMA_initParam DMA_init_Param = {0};\n\n    DMA_disableTransferDuringReadModifyWrite();\n\n    DMA_init_Param.channelSelect = DMA_CHANNEL_0;\n    DMA_init_Param.transferModeSelect = DMA_TRANSFER_REPEATED_SINGLE;\n    DMA_init_Param.transferSize = 1;\n    DMA_init_Param.triggerSourceSelect = DMA_TRIGGERSOURCE_24;\n    DMA_init_Param.transferUnitSelect = DMA_SIZE_SRCWORD_DSTWORD;\n    DMA_init_Param.triggerTypeSelect = DMA_TRIGGER_RISINGEDGE;\n\n    DMA_init(&amp;DMA_init_Param);\n\n    DMA_setSrcAddress(DMA_CHANNEL_0,\n                      ADC12_A_getMemoryAddressForDMA(ADC12_A_BASE,ADC12_A_MEMORY_0),\n                      DMA_DIRECTION_UNCHANGED);\n\n    DMA_setDstAddress(DMA_CHANNEL_0,\n                      (uint32_t)(uintptr_t)&amp;memory_location,\n                      DMA_DIRECTION_INCREMENT);\n\n    DMA_clearInterrupt(DMA_CHANNEL_0);\n\n    DMA_enableInterrupt(DMA_CHANNEL_0);\n\n    DMA_enableTransfers(DMA_CHANNEL_0);\n\n    __enable_interrupt();\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"649\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADCDMA-1024x649.png\" alt=\"\" class=\"wp-image-14656\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADCDMA-1024x649.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADCDMA-580x368.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADCDMA-768x487.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADCDMA.png 1298w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">ADC12 is configured just as we already did in past examples but no ADC12 interrupt is used. The new changes are related to DMA configuration.  We wish to transfer ADC data to our designated memory location with DMA hardware. Thus, we have to declare a word-sized global variable. We chose word size, i.e. 16-bit because ADC12 readings are typically 12-bit in size. This memory location will be used with DMA and that makes it important.  <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">uint16_t memory_location = 0x0000;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">DMA initialization requires a few parameters to be set in order to define the its characteristics. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void DMA_HW_init(void)\n{\n    DMA_initParam DMA_init_Param = {0};\n\n    DMA_disableTransferDuringReadModifyWrite();\n\n    DMA_init_Param.channelSelect = DMA_CHANNEL_0;\n    DMA_init_Param.transferModeSelect = DMA_TRANSFER_REPEATED_SINGLE;\n    DMA_init_Param.transferSize = 1;\n    DMA_init_Param.triggerSourceSelect = DMA_TRIGGERSOURCE_24;\n    DMA_init_Param.transferUnitSelect = DMA_SIZE_SRCWORD_DSTWORD;\n    DMA_init_Param.triggerTypeSelect = DMA_TRIGGER_RISINGEDGE;\n\n    DMA_init(&amp;DMA_init_Param);\n\n    DMA_setSrcAddress(DMA_CHANNEL_0,\n                      ADC12_A_getMemoryAddressForDMA(ADC12_A_BASE, ADC12_A_MEMORY_0),\n                      DMA_DIRECTION_UNCHANGED);\n\n    DMA_setDstAddress(DMA_CHANNEL_0,\n                      (uint32_t)(uintptr_t)&amp;memory_location,\n                      DMA_DIRECTION_INCREMENT);\n\n    DMA_clearInterrupt(DMA_CHANNEL_0);\n\n    DMA_enableInterrupt(DMA_CHANNEL_0);\n\n    DMA_enableTransfers(DMA_CHANNEL_0);\n\n    __enable_interrupt();\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The operation of DMA peripheral is similar to that of a water pipeline. In a water pipeline, we have to define source of water and its destination along with flow direction and frequency of flow. We also have to define the pipe size (diameter) in order to avoid unwanted fluid pressure, back-flow and water loss.&nbsp; <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In similar terms, for a DMA peripheral, we have to define source and\ndestination of data and the size of data. The source of data in this case is\nADC12\u2019s 0<sup>th<\/sup> memory location and the destination is the word-sized\nglobal variable we declared in the beginning of the code. We have to let the\ncompiler know the physical addresses, i.e. pointer of the source and the\ndestination.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">MSP430\u2019s DMA can support the following transfer modes:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"729\" height=\"204\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DMA-Transfer-Modes.png\" alt=\"\" class=\"wp-image-14657\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DMA-Transfer-Modes.png 729w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DMA-Transfer-Modes-580x162.png 580w\" sizes=\"auto, (max-width: 729px) 100vw, 729px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">We will be using 0<sup>th<\/sup> DMA channel in repeated single\ntransfer mode since the ADC will be converting data repeatedly. The transfers\nwill be in words and why it is so has already been explained.&nbsp; <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Since we are using repeated single transfer mode, a trigger source is needed that will initiate the transfer. In this code, the DMA trigger source is numbered 24. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"620\" height=\"727\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DMA-Trigger-Sources.png\" alt=\"\" class=\"wp-image-14658\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DMA-Trigger-Sources.png 620w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DMA-Trigger-Sources-554x650.png 554w\" sizes=\"auto, (max-width: 620px) 100vw, 620px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The 24<sup>th<\/sup> DMA trigger source is selected because we want\nthe transfer to occur when an AD conversion is ready to be read. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Though DMA interrupt has been used in the code, it does nothing rather than toggling P1.0 LED. This is merely an indicator of data transfer completion.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#pragma vector = DMA_VECTOR\n__interrupt void DMA_ISR (void)\n{\n    switch (__even_in_range(DMAIV, 16))\n    {\n        case 0: break;  \/\/None\n        case 2:         \/\/DMA0IFG = DMA Channel 0\n        {\n            GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);\n\n            break;\n        }\n        case 4: break;  \/\/DMA1IFG = DMA Channel 1\n        case 6: break;  \/\/DMA2IFG = DMA Channel 2\n        case 8: break;  \/\/DMA3IFG = DMA Channel 3\n        case 10: break; \/\/DMA4IFG = DMA Channel 4\n        case 12: break; \/\/DMA5IFG = DMA Channel 5\n        case 14: break; \/\/DMA6IFG = DMA Channel 6\n        case 16: break; \/\/DMA7IFG = DMA Channel 7\n        default: break;\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In the main loop, the destination memory location is read. Both voltage and ADC count are displayed on an LCD. P4.7 LED is toggled to indicated that LCD data update and memory read have been done.&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">volt = ((memory_location * 3300.0) \/ 4095.0);\n\nprint_I(11, 0, memory_location);\nprint_I(11, 1, volt);\n\nGPIO_toggleOutputOnPin(GPIO_PORT_P4, GPIO_PIN7);\ndelay_ms(200);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Note that in the code, we didn\u2019t use any ADC12 function like the one shown below for reading the ADC.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ADC12_A_getResults(ADC12_A_BASE, ADC12_A_MEMORY_0);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We read the ADC indirectly using the DMA peripheral.&nbsp; <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"709\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-DMA-1024x709.jpg\" alt=\"\" class=\"wp-image-14659\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-DMA-1024x709.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-DMA-580x402.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-DMA-768x532.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ADC-DMA.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/ardoI3NE3H8?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Analogue Comparator &#8211; Comp_B+ Module<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Although MSP430F5529 sports a good 12-bit ADC, it\nalso packs a sophisticated analogue comparator called <strong><em>COMP_B+<\/em><\/strong>\nthat can be employed in a number of ways. As with any other embedded analogue\ncomparator, it can be feed with external inputs as well as internal reference\nvoltage generator \u2013 REF module. Additionally, this comparator has certain\nadvanced features like software selectable RC filter, voltage hysteresis\ngenerator and timer input capture interlink. Positive and negative inputs can\nbe shorted internally to remove any stray charge accumulation. Lastly, another\nattractive feature of COMP_B+ is its ultra-low power consumption. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Analogue comparators can be used in many cases. Some\ntypical uses include<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>voltage level monitor, <\/li><li>measurement of capacitance, <\/li><li>measurement of inductance, <\/li><li>measurement of resistance,<\/li><li>RC oscillators,<\/li><li>noise remover,<\/li><li>waveform converter,<\/li><li>RC-based ADC, etc.<\/li><li><\/li><\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n\nvoid clock_init(void);\nvoid GPIO_init(void);\nvoid Comp_B_Plus(void);\n\n#pragma vector = COMP_B_VECTOR\n__interrupt void Comp_B_ISR(void)\n{\n    if(Comp_B_getInterruptStatus(COMP_B_BASE,\n                                 COMP_B_OUTPUT_FLAG))\n    {\n        GPIO_toggleOutputOnPin(GPIO_PORT_P4,\n                               GPIO_PIN7);\n\n        Comp_B_clearInterrupt(COMP_B_BASE,\n                              COMP_B_OUTPUT_FLAG);\n    }\n}\n\nvoid main(void)\n{\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    GPIO_init();\n    Comp_B_Plus();\n\n    while(true)\n    {\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_MCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P6,\n                                               (GPIO_PIN0 + GPIO_PIN1));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P1,\n                                                GPIO_PIN6);\n}\n\nvoid Comp_B_Plus(void)\n{\n    Comp_B_initParam Comp_B_Param = {0};\n\n    Comp_B_Param.invertedOutputPolarity = COMP_B_NORMALOUTPUTPOLARITY;\n    Comp_B_Param.positiveTerminalInput = COMP_B_INPUT0;\n    Comp_B_Param.negativeTerminalInput = COMP_B_INPUT1;\n    Comp_B_Param.outputFilterEnableAndDelayLevel = COMP_B_FILTEROUTPUT_DLYLVL3;\n    Comp_B_Param.powerModeSelect = COMP_B_POWERMODE_NORMALMODE;\n\n    Comp_B_init(COMP_B_BASE,\n                &amp;Comp_B_Param);\n\n    Comp_B_enableInterrupt(COMP_B_BASE,\n                           COMP_B_OUTPUT_INT);\n\n    Comp_B_setInterruptEdgeDirection(COMP_B_BASE,\n                                     COMP_B_RISINGEDGE);\n\n    Comp_B_enable(COMP_B_BASE);\n\n    __enable_interrupt();\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"631\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Comp-1024x631.png\" alt=\"\" class=\"wp-image-14660\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Comp-1024x631.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Comp-580x358.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Comp-768x474.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Comp.png 1132w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Here two voltage levels are compared and the result of comparison is\nvisually displayed with a LED.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As with other cases, comparator pins are secondary functions of some GPIO pins and are needed to be declared before using COMP_B+.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P6, (GPIO_PIN0 + GPIO_PIN1));\n\nGPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P1, GPIO_PIN6);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now we are ready to setup the comparator module. Comparator parameters state output polarity, inputs to comparator inputs, RC filter level and power consumption mode. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void Comp_B_Plus(void)\n{\n  Comp_B_initParam Comp_B_Param = {0};\n\n  Comp_B_Param.invertedOutputPolarity = COMP_B_NORMALOUTPUTPOLARITY;\n  Comp_B_Param.positiveTerminalInput = COMP_B_INPUT0;\n  Comp_B_Param.negativeTerminalInput = COMP_B_INPUT1;\n  Comp_B_Param.outputFilterEnableAndDelayLevel = COMP_B_FILTEROUTPUT_DLYLVL3;\n  Comp_B_Param.powerModeSelect = COMP_B_POWERMODE_NORMALMODE;\n\n  Comp_B_init(COMP_B_BASE, &amp;Comp_B_Param);\n\n  Comp_B_enableInterrupt(COMP_B_BASE, COMP_B_OUTPUT_INT);\n\n  Comp_B_setInterruptEdgeDirection(COMP_B_BASE, COMP_B_RISINGEDGE);\n\n  Comp_B_enable(COMP_B_BASE);\n\n  __enable_interrupt();\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It is my advice to use comparator interrupt because a comparator\nevent occurs to signify a major event. This is why rising edge interrupt is\nused here. This type of interrupt will occur only when positive input is\ngreater than negative input. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There is no code inside the main loop but inside the interrupt subroutine P4.7 LED is toggled when rising edge comparator interrupt occurs. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#pragma vector = COMP_B_VECTOR\n__interrupt void Comp_B_ISR(void)\n{\n    if(Comp_B_getInterruptStatus(COMP_B_BASE, COMP_B_OUTPUT_FLAG))\n    {\n        GPIO_toggleOutputOnPin(GPIO_PORT_P4, GPIO_PIN7);\n\n        Comp_B_clearInterrupt(COMP_B_BASE, COMP_B_OUTPUT_FLAG);\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When interrupt occurs, we need to check relevant interrupt flag and clear it after processing the interrupt. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"658\" height=\"398\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/compb.png\" alt=\"\" class=\"wp-image-14661\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/compb.png 658w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/compb-580x351.png 580w\" sizes=\"auto, (max-width: 658px) 100vw, 658px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/G7bc9IN55GM?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Communication Hardware Overview<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The charm of MSP430F5529 microcontroller is its USB hardware. This is typically not found in most 8-bit and 16-bit general purpose microcontrollers. Apart from USB hardware module, MSP430F5529 has other communication modules that are must-haves in any modern-era microcontroller. Except CAN, MSP430F5529 supports all sorts of communications listed below. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"623\" height=\"433\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Table.png\" alt=\"\" class=\"wp-image-14663\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Table.png 623w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Table-580x403.png 580w\" sizes=\"auto, (max-width: 623px) 100vw, 623px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">In my <a href=\"http:\/\/embedded-lab.com\/blog\/category\/msp430-launchpad\/\">previous MSP430\ntutorial<\/a>, I elaborated the difference between <strong><em>Universal Serial Interface (USI) <\/em><\/strong>and<strong><em>\nUniversal Serial Communication Interface (USCI) <\/em><\/strong>modules. In MSP430F5529\nmicro, there is no USI module as USCI is more robust and advanced than USI. There\nare 2 USCI_Ax &#8211; USCI_A0 and USCI_A1 and 2 USCI_Bx &#8211; USCI_B0 and USCI_B1 modules\nin MSP430F5529. Thus, the total USCI module count in MSP430F5529 is four.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">&nbsp;USCI_As are\nbetter-suited for asynchronous communications like SPI, UART, LIN and IrDA\ncommunications while USCI_Bs are optimized for synchronous communications like\nfor I2C and SPI communications. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With USCI we can expand communication and connectivity.\nWe can then use CAN controllers like MCP2515, ethernet controllers like W5100,\nWiFi modules like ESP8266 and many others that are not typically available in\nany microcontroller.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Apart from these hardware interfaces, we can emulate software-based communications like software I2C, software SPI and software UART. One-wire or other non-standard format of communications like that of WS2812 neopixel LEDs, DHT11 relative-humidity &amp; temperature sensor, etc can be created easily using software delays, timers, GPIOs or other hardware by deciphering communication protocols and replicating them.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"802\" height=\"462\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Saleae.png\" alt=\"\" class=\"wp-image-14664\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Saleae.png 802w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Saleae-580x334.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Saleae-768x442.png 768w\" sizes=\"auto, (max-width: 802px) 100vw, 802px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">It is my recommendation that we must invest in good signal\/logic analysers and oscilloscopes to fully understand and appreciate the workings of different communication protocols. Timing diagrams and protocol rules are other areas that we must study deeply. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"700\" height=\"720\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/saleae-logic-pro-16-logic-analyzer-sal-00115-2cb.jpg\" alt=\"\" class=\"wp-image-14665\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/saleae-logic-pro-16-logic-analyzer-sal-00115-2cb.jpg 700w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/saleae-logic-pro-16-logic-analyzer-sal-00115-2cb-580x597.jpg 580w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">One-Wire Communication with DHT11<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">DHT11 relative humidity &amp; temperature sensor can be interfaced with a microcontroller via one wire. However, one-wire communication is not standard format of communication like UART, I2C and SPI. Every device has its own protocol that differs a lot with others. However, the basic trick in one-wire protocol is time-slotting mechanism. Ones and zeros are represented by pulses of different pulse widths or duty cycle. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"698\" height=\"591\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DH11.png\" alt=\"\" class=\"wp-image-14668\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DH11.png 698w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DH11-580x491.png 580w\" sizes=\"auto, (max-width: 698px) 100vw, 698px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">DHT11 can be used to measure temperatures nominally\nfrom 0\u00b0C to 50\u00b0C and relative humidity from 20% to 95%. Though it is not very\nprecise, it can be used for general uses. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A big advantage of this sensor is its ability to operate at 3.3V although it is recommended to apply supply voltages between 3.5V \u2013 5.5V.&nbsp; <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>DHT11.h<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n\n#define HIGH                    1\n#define LOW                     0\n\n#define DHT11_PORT              GPIO_PORT_P3\n\n#define DHT11_pin               GPIO_PIN7\n\n#define DHT11_DIR_OUT()         GPIO_setAsOutputPin(DHT11_PORT, DHT11_pin)\n#define DHT11_DIR_IN()          GPIO_setAsInputPin(DHT11_PORT, DHT11_pin)\n\n#define DHT11_pin_HIGH()        GPIO_setOutputHighOnPin(DHT11_PORT, DHT11_pin)\n#define DHT11_pin_LOW()         GPIO_setOutputLowOnPin(DHT11_PORT, DHT11_pin)\n\n#define DHT11_pin_IN()          GPIO_getInputPinValue(DHT11_PORT, DHT11_pin)\n\nvoid DHT11_init(void);\nunsigned char get_byte(void);\nunsigned char get_data(void);<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>DHT11.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"DHT11.h\"\n\nunsigned char values[0x05];\n\nvoid DHT11_init(void)\n{\n   DHT11_DIR_IN();\n   delay_ms(1000);\n}\n\nunsigned char get_byte(void)\n{\n   unsigned char s = 0;\n   unsigned char value = 0;\n\n   DHT11_DIR_IN();\n\n   for(s = 0; s &lt; 8; s++) \n   {\n      value &lt;&lt;= 1;\n      while(DHT11_pin_IN() == LOW);\n      delay_us(30);\n\n      if(DHT11_pin_IN() == HIGH)\n      {\n          value |= 1;\n      }\n      \n      while(DHT11_pin_IN() == HIGH);\n   }\n   return value;\n}\n\nunsigned char get_data(void)\n{\n   short chk = 0;\n   unsigned char s = 0;\n   unsigned char check_sum = 0;\n\n   DHT11_DIR_OUT();\n\n   DHT11_pin_HIGH();\n   DHT11_pin_LOW();\n   delay_ms(18);\n   DHT11_pin_HIGH();\n   delay_us(26);\n   \n   DHT11_DIR_IN();\n\n   chk = DHT11_pin_IN();\n   \n   if(chk)\n   {\n      return 1;\n   }\n   delay_us(80);\n   \n   chk = DHT11_pin_IN();\n\n   if(!chk)\n   {\n      return 2;\n   }\n   delay_us(80);\n\n   for(s = 0; s &lt;= 4; s += 1)\n   {\n       values[s] = get_byte();\n   }\n\n   DHT11_DIR_OUT();\n  \n   DHT11_pin_HIGH(); \n   \n   DHT11_DIR_IN();\n\n   for(s = 0; s &lt; 4; s += 1)\n   {\n       check_sum += values[s];\n   }\n   \n   if(check_sum != values[4])\n   {\n      return 3;\n   }\n   else\n   {\n      return 0;\n   }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>main.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"DHT11.h\"\n#include \"lcd.h\"\n#include \"lcd_print.h\"\n\nextern unsigned char values[0x05];\n\nvoid clock_init(void);\n\nvoid main(void)\n{\n    unsigned char state = 0;\n\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n\n    LCD_init();\n    load_custom_symbol();\n\n    DHT11_init();\n\n    while(1)\n    {\n        state = get_data();\n\n        switch(state)\n        {\n            case 1:\n            {\n            }\n            case 2:\n            {\n                 LCD_clear_home();\n                 LCD_putstr(\"No Sensor Found!\");\n                 break;\n            }\n            case 3:\n            {\n                 LCD_clear_home();\n                 LCD_putstr(\"Checksum Error!\");\n                 break;\n            }\n            default:\n            {\n                 LCD_goto(0, 0);\n                 LCD_putstr(\"R.H\/ %:       \");\n\n                 print_C(13, 0, values[0]);\n\n                 LCD_goto(0, 1);\n                 LCD_putstr(\"Tmp\/\");\n                 print_symbol(4, 1, 0);\n                 LCD_goto(5, 1);\n                 LCD_putstr(\"C:\");\n\n                 if((values[2] &amp; 0x80) == 1)\n                 {\n                     LCD_goto(13, 1);\n                     LCD_putstr(\"-\");\n                 }\n                 else\n                 {\n                     LCD_goto(13, 1);\n                     LCD_putstr(\" \");\n                 }\n\n                 print_C(13, 1, values[2]);\n                 break;\n            }\n        }\n\n        delay_ms(1000);\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_MCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_REFOCLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"570\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DHT11-1024x570.png\" alt=\"\" class=\"wp-image-14669\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DHT11-1024x570.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DHT11-580x323.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DHT11-768x427.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DHT11.png 1307w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">One-wire sensors and devices use time-slotting mechanism to\ncommunicate with host micro. Time-slotting and communication methodology differ\nfrom device-to-device and have no standards like I2C, SPI, UART, etc. Despite\nthis fact, communicating with one-wire devices is not very difficult. All we\nhave to do is to generate timed pulse or read pulse transitions.&nbsp; <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Shown below is the timing diagram for DHT11 relative humidity &amp; temperature sensor. We have to keep the one-wire data line floating unless there is any communication. A floating pin is basically an externally pulled-up input pin unless used otherwise. The pull-up is achieved using an external resistor connected between the host micro\u2019s pin and power supply\u2019s positive line. &nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"569\" height=\"185\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/dht11-timing.png\" alt=\"\" class=\"wp-image-14670\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">A host micro has to pull-down the floating communication low for about 18ms and then keep it high for about 30\u00b5s to command DHT11 to send out its temperature and humidity readings. This is done as follows in the code below. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">DHT11_pin_HIGH();\nDHT11_pin_LOW();\ndelay_ms(18);\nDHT11_pin_HIGH();\ndelay_us(26);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It is very straight forward. DHT11 upon receiving these logic-level transitions starts to serially send out its data readings one-by-one. During reads, we have to check timings in order to determine if the sent pulse is denoting a one or zero. If an incoming pulse is high for more than 30\u00b5s, it is treated as a one or else it is treated otherwise. Again, it is pretty simple.&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">value &lt;&lt;= 1;\nwhile(DHT11_pin_IN() == LOW);\ndelay_us(30);\n\nif(DHT11_pin_IN() == HIGH)\n{\n   value |= 1;\n}\n      \nwhile(DHT11_pin_IN() == HIGH);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/OW-DHT11-1024x768.jpg\" alt=\"\" class=\"wp-image-14671\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/OW-DHT11-1024x768.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/OW-DHT11-580x435.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/OW-DHT11-768x576.jpg 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/p8dCG94tzxo?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">One-Wire Communication with DS18B20<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Dallas DS18B20 is another one-wire device but as said earlier, it is different from DHT11 or other one-wire devices. DS18B20 is a high-resolution digital temperature sensor. This sensor also uses time-slotting mechanism to send and receive data from a host micro. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"612\" height=\"810\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DS18B20.png\" alt=\"\" class=\"wp-image-14673\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DS18B20.png 612w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DS18B20-491x650.png 491w\" sizes=\"auto, (max-width: 612px) 100vw, 612px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">One advantage of time-slotting mechanism is the fact that no special hardware and therefore no dedicated pin of a host microcontroller is needed. Any physical pin can be used and only software delays along with polling methodology are what required. It is also possible to use internal timers instead of wasteful software delays. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"767\" height=\"745\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Time-Slotting.png\" alt=\"\" class=\"wp-image-14674\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Time-Slotting.png 767w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Time-Slotting-580x563.png 580w\" sizes=\"auto, (max-width: 767px) 100vw, 767px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Time-slotting technique is also used in infrared remote controllers.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>one_wire.h<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n\n#define DS18B20_PORT        GPIO_PORT_P3\n\n#define DS18B20_PIN         GPIO_PIN7\n\n#define DS18B20_OUTPUT()    GPIO_setAsOutputPin(DS18B20_PORT, DS18B20_PIN)\n#define DS18B20_INPUT()     GPIO_setAsInputPin(DS18B20_PORT, DS18B20_PIN)\n\n#define DS18B20_IN()        GPIO_getInputPinValue(DS18B20_PORT, DS18B20_PIN)\n\n#define DS18B20_OUT_HIGH()  GPIO_setOutputHighOnPin(DS18B20_PORT, DS18B20_PIN)\n#define DS18B20_OUT_LOW()   GPIO_setOutputLowOnPin(DS18B20_PORT, DS18B20_PIN)\n\n#define TRUE                1\n#define FALSE               0\n\nunsigned char onewire_reset(void) ;\nvoid onewire_write_bit(unsigned char bit_value);\nunsigned char onewire_read_bit(void);\nvoid onewire_write(unsigned char value);    \nunsigned char onewire_read(void);<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>one_wire.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"one_wire.h\"\n    \n\nunsigned char onewire_reset(void)  \n{                                         \n     unsigned char res = FALSE; \n     \n     DS18B20_OUTPUT();                 \n     DS18B20_OUT_LOW();\n     delay_us(480);        \n     DS18B20_OUT_HIGH();\n     delay_us(60);        \n\n     DS18B20_INPUT();\n     res = DS18B20_IN();\n     delay_us(480);       \n     \n     return res; \n} \n\nvoid onewire_write_bit(unsigned char bit_value)\n{\n    DS18B20_OUTPUT();\n    DS18B20_OUT_LOW(); \n    \n    if(bit_value)\n    {       \n        delay_us(104);\n        DS18B20_OUT_HIGH();   \n    }              \n}     \n\nunsigned char onewire_read_bit(void)        \n{     \n    DS18B20_OUTPUT();\n    DS18B20_OUT_LOW();  \n    DS18B20_OUT_HIGH();  \n    delay_us(15);      \n    DS18B20_INPUT();\n\n    return(DS18B20_IN());    \n}\n\nvoid onewire_write(unsigned char value) \n{                    \n     unsigned char s = 0; \n     \n     DS18B20_OUTPUT();\n\n     while(s &lt; 8)    \n     {                              \n          if((value &amp; (1 &lt;&lt; s)))\n          {\n              DS18B20_OUT_LOW(); \n              _delay_cycles(1);\n              DS18B20_OUT_HIGH();  \n              delay_us(60);   \n          }       \n                              \n          else\n          {\n              DS18B20_OUT_LOW();           \n              delay_us(60);           \n              DS18B20_OUT_HIGH();   \n              _delay_cycles(1);\n          }\n\n          s++;\n     }\n}                                      \n\nunsigned char onewire_read(void)\n{\n     unsigned char s = 0x00;\n     unsigned char value = 0x00;\n    \n     while(s &lt; 8) \n     {\n          DS18B20_OUTPUT();\n\n          DS18B20_OUT_LOW();\n          _delay_cycles(1);\n          DS18B20_OUT_HIGH();  \n          \n          DS18B20_INPUT();\n          if(DS18B20_IN())  \n          {                                      \n              value |=  (1 &lt;&lt; s);                         \n          }        \n           \n          delay_us(60);\n\n          s++;\n     }     \n     \n     return value;\n}  <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>DS18B20.h<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"one_wire.h\"  \n\n#define convert_T                       0x44\n#define read_scratchpad                 0xBE            \n#define write_scratchpad                0x4E \n#define copy_scratchpad                 0x48   \n#define recall_E2                       0xB8 \n#define read_power_supply               0xB4    \n#define skip_ROM                        0xCC\n\n#define resolution                      12\n\nvoid DS18B20_init(void);\nfloat DS18B20_get_temperature(void);  <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>DS18B20.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"DS18B20.h\"\n\nvoid DS18B20_init(void)                             \n{                                       \n    onewire_reset();\n    delay_ms(100);\n}              \n\nfloat DS18B20_get_temperature(void)\n{                                               \n    unsigned char msb = 0x00;\n    unsigned char lsb = 0x00;\n    register float temp = 0.0;  \n                           \n    onewire_reset();     \n    onewire_write(skip_ROM);        \n    onewire_write(convert_T); \n    \n    switch(resolution)   \n    {                                                  \n        case 12:\n        {                                            \n            delay_ms(750);\n            break;\n        }                \n        case 11:                                     \n        {              \n            delay_ms(375);\n            break;\n        }           \n        case 10:                             \n        {                                 \n            delay_ms(188);   \n            break;\n        }                                        \n        case 9:                                   \n        {                                                \n            delay_ms(94);                 \n            break;                            \n        }                        \n    }                  \n\n    onewire_reset(); \n\n    onewire_write(skip_ROM);                 \n    onewire_write(read_scratchpad);\n\n    lsb = onewire_read();\n    msb = onewire_read();\n\n    temp = msb;                           \n    temp *= 256.0;\n    temp += lsb;\n    \n    \n    switch(resolution)   \n    {                                  \n        case 12:            \n        {                                                \n            temp *= 0.0625;                 \n            break;                            \n        }       \n        case 11: \n        {           \n            temp *= 0.125;      \n            break;\n        }                \n        case 10:\n        {            \n            temp *= 0.25;       \n            break;\n        }  \n        case 9:                                 \n        {                                 \n            temp *= 0.5;        \n            break;      \n        }                          \n    }  \n    \n    delay_ms(40);       \n    \n    return (temp);       \n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">main.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"one_wire.h\"\n#include \"DS18B20.h\"\n#include \"lcd.h\"\n#include \"lcd_print.h\"\n\nvoid clock_init(void);\n\nvoid main(void)\n{\n    float t = 0.0;\n\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n\n    DS18B20_init();\n\n    LCD_init();\n    load_custom_symbol();\n\n    LCD_goto(1, 0);\n    LCD_putstr(\"MSP430 DS18B20\");\n\n    LCD_goto(0, 1);\n    LCD_putstr(\"T\/ C\");\n    print_symbol(2, 1, 0);\n\n    while(1)\n    {\n        t = DS18B20_get_temperature();\n        print_F(9, 1, t, 3);\n        delay_ms(1000);\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_MCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_REFOCLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"566\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DS18B20-1-1024x566.png\" alt=\"\" class=\"wp-image-14676\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DS18B20-1-1024x566.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DS18B20-1-580x321.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DS18B20-1-768x425.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/DS18B20-1.png 1277w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">One\nwire communication is detailed in these application notes from Maxim: <\/p>\n\n\n\n<figure class=\"wp-block-embed\"><div class=\"wp-block-embed__wrapper\">\nhttps:\/\/www.maximintegrated.com\/en\/app-notes\/index.mvp\/id\/126\n<\/div><\/figure>\n\n\n\n<figure class=\"wp-block-embed\"><div class=\"wp-block-embed__wrapper\">\nhttps:\/\/www.maximintegrated.com\/en\/app-notes\/index.mvp\/id\/162\n<\/div><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">These notes are all that are needed for implementing the one wire communication interface for DS18B20. Please go through these notes for details. The codes are self-explanatory and are implemented from the code examples in these app notes.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/OW-DS18B20-1024x768.jpg\" alt=\"\" class=\"wp-image-14677\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/OW-DS18B20-1024x768.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/OW-DS18B20-580x435.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/OW-DS18B20-768x576.jpg 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/dih8Zm6u9j0?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">USCI \u2013 SPI \u2013 I2C Example 1<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In this first USCI example, we will see how we can use USCI modules to read a MMA7455L accelerometer in I2C mode and project its readings on a SPI-based ST7735 TFT display. This is an over simplified example and a rudimentary one although it may appear that lot of coding has been done here. Here, the accelerometer\u2019s axes readings are plotted on the TFT display.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>MMA7455L.h<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n\n#define I2C_port                             GPIO_PORT_P4\n\n#define I2C_SDA_pin                          GPIO_PIN1\n#define I2C_SCL_pin                          GPIO_PIN2\n\n#define MMA7455L_address                     0x1D\n                                                \n#define MMA7455L_X_out_L                     0x00  \n#define MMA7455L_X_out_H                     0x01  \n#define MMA7455L_Y_out_L                     0x02  \n#define MMA7455L_Y_out_H                     0x03    \n#define MMA7455L_Z_out_L                     0x04  \n#define MMA7455L_Z_out_H                     0x05    \n#define MMA7455L_X_out                       0x06    \n#define MMA7455L_Y_out                       0x07  \n#define MMA7455L_Z_out                       0x08      \n#define MMA7455L_STATUS                      0x09  \n#define MMA7455L_DETSRC                      0x0A  \n#define MMA7455L_TOUT                        0x0B\n#define MMA7455L_RSV1                        0x0C\n#define MMA7455L_I2C_Address                 0x0D\n#define MMA7455L_User_Info                   0x0E\n#define MMA7455L_Who_Am_I                    0x0F\n#define MMA7455L_X_offset_L                  0x10  \n#define MMA7455L_X_offset_H                  0x11  \n#define MMA7455L_Y_offset_L                  0x12  \n#define MMA7455L_Y_offset_H                  0x13    \n#define MMA7455L_Z_offset_L                  0x14  \n#define MMA7455L_Z_offset_H                  0x15 \n#define MMA7455L_MCTL                        0x16\n#define MMA7455L_INTRST                      0x17\n#define MMA7455L_CTL1                        0x18\n#define MMA7455L_CTL2                        0x19\n#define MMA7455L_LDTH                        0x1A\n#define MMA7455L_PDTH                        0x1B\n#define MMA7455L_PW                          0x1C\n#define MMA7455L_LT                          0x1D\n#define MMA7455L_TW                          0x1E\n#define MMA7455L_RSV2                        0x1F    \n\n#define MMA_7455_2G_MODE                     0x05 \n#define MMA_7455_4G_MODE                     0x09     \n#define MMA_7455_8G_MODE                     0x01\n\nvoid I2C_DIO_init(void);\nvoid USCI_I2C_init(void);\nvoid MMA7455L_init(void);\nvoid MMA7455L_write_byte(unsigned char address, unsigned char value);\nvoid MMA7455L_write_word(unsigned char address, unsigned int value);\nunsigned char MMA7455L_read_byte(unsigned char address);\nunsigned int MMA7455L_read_word(unsigned char address);\nsigned char MMA7455L_read_axis_8(unsigned char axis);\nsigned int MMA7455L_read_axis_10(unsigned char axis);<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>MMA7455L.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"MMA7455L.h\"\n\nvoid I2C_DIO_init(void)\n{\n    GPIO_setAsPeripheralModuleFunctionOutputPin(I2C_port, (I2C_SDA_pin | I2C_SCL_pin));\n}\n\nvoid USCI_I2C_init(void)\n{\n    USCI_B_I2C_initMasterParam I2C_param = {0};\n\n    I2C_DIO_init();\n\n    I2C_param.selectClockSource = USCI_B_I2C_CLOCKSOURCE_SMCLK;\n    I2C_param.i2cClk = UCS_getSMCLK();\n    I2C_param.dataRate = USCI_B_I2C_SET_DATA_RATE_100KBPS;\n\n    USCI_B_I2C_initMaster(USCI_B1_BASE, &amp;I2C_param);\n\n    USCI_B_I2C_enable(USCI_B1_BASE);\n}\n\nvoid MMA7455L_init(void)\n{\n    USCI_I2C_init();  \n    MMA7455L_write_byte(MMA7455L_CTL1, 0x80);\n    MMA7455L_write_byte(MMA7455L_MCTL, MMA_7455_2G_MODE);\n}\n\nvoid MMA7455L_write_byte(unsigned char address, unsigned char value)\n{\n    USCI_B_I2C_setSlaveAddress(USCI_B1_BASE, MMA7455L_address);\n    USCI_B_I2C_setMode(USCI_B1_BASE, USCI_B_I2C_TRANSMIT_MODE);\n\n    USCI_B_I2C_masterSendMultiByteStart(USCI_B1_BASE, address);\n    while(!USCI_B_I2C_masterIsStartSent(USCI_B1_BASE));\n    USCI_B_I2C_masterSendMultiByteFinish(USCI_B1_BASE, value);\n\n    while(USCI_B_I2C_isBusBusy(USCI_B1_BASE));\n}\n\nvoid MMA7455L_write_word(unsigned char address, unsigned int value)\n{\n    unsigned char lb = 0x00;\n    unsigned char hb = 0x00;\n\n    lb = ((unsigned char)value);\n    value &gt;&gt;= 8;\n    hb = ((unsigned char)value);\n\n    MMA7455L_write_byte(address, lb);\n    MMA7455L_write_byte((address + 1), hb);\n}\n\nunsigned char MMA7455L_read_byte(unsigned char address)\n{\n    unsigned char value = 0x00;\n\n    USCI_B_I2C_setSlaveAddress(USCI_B1_BASE, MMA7455L_address);\n    USCI_B_I2C_setMode(USCI_B1_BASE, USCI_B_I2C_TRANSMIT_MODE);\n\n    USCI_B_I2C_masterSendStart(USCI_B1_BASE);\n    USCI_B_I2C_masterSendSingleByte(USCI_B1_BASE, address);\n\n    USCI_B_I2C_setSlaveAddress(USCI_B1_BASE, MMA7455L_address);\n    USCI_B_I2C_setMode(USCI_B1_BASE, USCI_B_I2C_RECEIVE_MODE);\n\n    USCI_B_I2C_masterReceiveSingleStart(USCI_B1_BASE);\n    value = USCI_B_I2C_masterReceiveSingle(USCI_B1_BASE);\n\n    while(USCI_B_I2C_isBusBusy(USCI_B1_BASE));\n\n    return value;\n}\n\nunsigned int MMA7455L_read_word(unsigned char address)\n{\n    unsigned char lb = 0x00;\n    unsigned int hb = 0x0000;\n\n    USCI_B_I2C_setSlaveAddress(USCI_B1_BASE, MMA7455L_address);\n    USCI_B_I2C_setMode(USCI_B1_BASE, USCI_B_I2C_TRANSMIT_MODE);\n\n    USCI_B_I2C_masterSendStart(USCI_B1_BASE);\n    USCI_B_I2C_masterSendSingleByte(USCI_B1_BASE, address);\n\n    USCI_B_I2C_setSlaveAddress(USCI_B1_BASE, MMA7455L_address);\n    USCI_B_I2C_setMode(USCI_B1_BASE, USCI_B_I2C_RECEIVE_MODE);\n\n    USCI_B_I2C_masterReceiveMultiByteStart(USCI_B1_BASE);\n    lb = USCI_B_I2C_masterReceiveMultiByteNext(USCI_B1_BASE);\n    hb = USCI_B_I2C_masterReceiveMultiByteFinish(USCI_B1_BASE);\n\n    USCI_B_I2C_masterReceiveMultiByteStop(USCI_B1_BASE);\n\n    while(USCI_B_I2C_isBusBusy(USCI_B1_BASE));\n\n    hb &lt;&lt;= 8;\n    hb |= lb;\n\n    return hb;\n}\n\nsigned char MMA7455L_read_axis_8(unsigned char axis)\n{\n    return ((signed char)MMA7455L_read_byte(axis));\n}\n\nsigned int MMA7455L_read_axis_10(unsigned char axis)\n{\n    return ((signed int)MMA7455L_read_word(axis) &amp; 0x03FF);\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>ST7735.h<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n\n#define MOSI_port                               GPIO_PORT_P3\n#define MISO_port                               GPIO_PORT_P3\n#define CLK_port                                GPIO_PORT_P3\n#define RST_port                                GPIO_PORT_P3\n#define RS_port                                 GPIO_PORT_P3\n#define CS_port                                 GPIO_PORT_P3\n\n#define MOSI_pin                                GPIO_PIN0\n#define MISO_pin                                GPIO_PIN1\n#define CLK_pin                                 GPIO_PIN2\n#define RST_pin                                 GPIO_PIN3\n#define RS_pin                                  GPIO_PIN4\n#define CS_pin                                  GPIO_PIN5\n\n#define MOSI_pin_high() GPIO_setOutputHighOnPin(MOSI_port, MOSI_pin)\n#define MOSI_pin_low()  GPIO_setOutputLowOnPin(MOSI_port, MOSI_pin)\n\n#define get_MISO_pin()  GPIO_getInputPinValue(MISO_port, MISO_pin)\n\n#define CLK_pin_high()  GPIO_setOutputHighOnPin(CLK_port, CLK_pin)\n#define CLK_pin_low()   GPIO_setOutputLowOnPin(CLK_port, CLK_pin)\n\n#define RST_pin_high()  GPIO_setOutputHighOnPin(RST_port, RST_pin)\n#define RST_pin_low()   GPIO_setOutputLowOnPin(RST_port, RST_pin)\n\n#define RS_pin_high()   GPIO_setOutputHighOnPin(RS_port, RS_pin)\n#define RS_pin_low()    GPIO_setOutputLowOnPin(RS_port, RS_pin)\n\n#define CS_pin_high()   GPIO_setOutputHighOnPin(CS_port, CS_pin)\n#define CS_pin_low()    GPIO_setOutputLowOnPin(CS_port, CS_pin)\n\n#define ST7735_NOP                              0x00\n#define ST7735_SWRESET                          0x01\n#define ST7735_RDDID                            0x04\n#define ST7735_RDDST                            0x09\n#define ST7735_RDDPM                            0x0A\n#define ST7735_RDD_MADCTL                       0x0B\n#define STT7735_RDD_COLMOD                      0x0C\n#define ST7735_RDDIM                            0x0D\n#define ST7735_RDDSM                            0x0E\n\n#define ST7735_SLPIN                            0x10\n#define ST7735_SLPOUT                           0x11\n#define ST7735_PTLON                            0x12\n#define ST7735_NORON                            0x13\n\n#define ST7735_INVOFF                           0x20\n#define ST7735_INVON                            0x21\n#define ST7735_GAMSET                           0x26\n#define ST7735_DISPOFF                          0x28\n#define ST7735_DISPON                           0x29\n#define ST7735_CASET                            0x2A\n#define ST7735_RASET                            0x2B\n#define ST7735_RAMWR                            0x2C\n#define ST7735_RAMRD                            0x2E\n\n#define ST7735_PTLAR                            0x30\n#define ST7735_TEOFF                            0x34\n#define ST7735_TEON                             0x35\n#define ST7735_MADCTL                           0x36\n#define ST7735_IDMOFF                           0x38\n#define ST7735_IDMON                            0x39\n#define ST7735_COLMOD                           0x3A\n\n#define ST7735_RDID1                            0xDA\n#define ST7735_RDID2                            0xDB\n#define ST7735_RDID3                            0xDC\n#define ST7735_RDID4                            0xDD\n\n#define ST7735_FRMCTR1                          0xB1\n#define ST7735_FRMCTR2                          0xB2\n#define ST7735_FRMCTR3                          0xB3\n#define ST7735_INVCTR                           0xB4\n#define ST7735_DISSET5                          0xB6\n\n#define ST7735_PWCTR1                           0xC0\n#define ST7735_PWCTR2                           0xC1\n#define ST7735_PWCTR3                           0xC2\n#define ST7735_PWCTR4                           0xC3\n#define ST7735_PWCTR5                           0xC4\n#define ST7735_VMCTR1                           0xC5\n\n#define ST7735_RDID1                            0xDA\n#define ST7735_RDID2                            0xDB\n#define ST7735_RDID3                            0xDC\n#define ST7735_RDID4                            0xDD\n\n#define ST7735_PWCTR6                           0xFC\n\n#define ST7735_GMCTRP1                          0xE0\n#define ST7735_GMCTRN1                          0xE1\n\n#define BLACK                                   0x0000\n#define BLUE                                    0x001F\n#define RED                                     0xF800\n#define GREEN                                   0x07E0\n#define CYAN                                    0x07FF\n#define MAGENTA                                 0xF81F\n#define YELLOW                                  0xFFE0\n#define WHITE                                   0xFFFF\n\n#define MADCTL_MY                               0x80\n#define MADCTL_MX                               0x40\n#define MADCTL_MV                               0x20\n#define MADCTL_ML                               0x10\n#define MADCTL_RGB                              0x08\n#define MADCTL_MH                               0x04\n\n#define ST7735_TFTWIDTH                         128\n#define ST7735_TFTLENGTH                        160\n\n#define CMD                                     0\n#define DAT                                     1\n\n#define SQUARE                                  0\n#define ROUND                                   1\n\n#define NO                                      0\n#define YES                                     1\n\nvoid SPI_DIO_init(void);\nvoid USCI_SPI_init(void);\nvoid ST7735_init(void);\nvoid ST7735_Write(unsigned char value, unsigned char mode);\nvoid ST7735_Reset(void);\nvoid ST7735_Word_Write(unsigned int value);\nvoid ST7735_Data_Write(unsigned char DataH, unsigned char DataL);\nvoid ST7735_Data_Write_4k(unsigned char DataH, unsigned char DataM, unsigned char DataL);\nvoid ST7735_Set_Addr_Window(unsigned char xs, unsigned char ys, unsigned char xe, unsigned char ye);\nvoid ST7735_RAM_Address_Set(void);\nvoid ST7735_Invert_Display(unsigned char i);\nunsigned int ST7735_Swap_Colour(unsigned int colour);\nunsigned int ST7735_Color565(unsigned char r, unsigned char g, unsigned char b);\nvoid ST7735_Set_Rotation(unsigned char m);\nvoid TFT_fill(unsigned int colour);\nvoid Draw_Pixel(unsigned char x_pos, unsigned char y_pos, unsigned int colour);\nvoid Draw_Line(signed int x1, signed int y1, signed int x2, signed int y2, unsigned int colour);\nvoid Draw_Rectangle(signed int x1, signed int y1, signed int x2, signed int y2, unsigned char fill, unsigned char type, unsigned int colour, unsigned int back_colour);\nvoid Draw_Circle(signed int xc, signed int yc, signed int radius, unsigned char fill, unsigned int colour);\nvoid Draw_Font_Pixel(unsigned char x_pos, unsigned char y_pos, unsigned int colour, unsigned char pixel_size);\nvoid print_char(unsigned char x_pos, unsigned char y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, unsigned char ch);\nvoid print_str(unsigned char x_pos, unsigned char y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, unsigned char *ch);\nvoid print_C(unsigned char x_pos, unsigned char y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, signed int value);\nvoid print_I(unsigned char x_pos, unsigned char y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, signed int value);\nvoid print_D(unsigned char x_pos, unsigned char y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, unsigned int value, unsigned char points);\nvoid print_F(unsigned char x_pos, unsigned char y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, float value, unsigned char points);<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>ST7735.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"ST7735.h\"\n\nstatic const unsigned char fonts[96][5] =\n{\n     {0x00, 0x00, 0x00, 0x00, 0x00} \/\/ 20\n    ,{0x00, 0x00, 0x5f, 0x00, 0x00} \/\/ 21 !\n    ,{0x00, 0x07, 0x00, 0x07, 0x00} \/\/ 22 \"\n    ,{0x14, 0x7f, 0x14, 0x7f, 0x14} \/\/ 23 #\n    ,{0x24, 0x2a, 0x7f, 0x2a, 0x12} \/\/ 24 $\n    ,{0x23, 0x13, 0x08, 0x64, 0x62} \/\/ 25 %\n    ,{0x36, 0x49, 0x55, 0x22, 0x50} \/\/ 26 &amp;\n    ,{0x00, 0x05, 0x03, 0x00, 0x00} \/\/ 27 '\n    ,{0x00, 0x1c, 0x22, 0x41, 0x00} \/\/ 28 (\n    ,{0x00, 0x41, 0x22, 0x1c, 0x00} \/\/ 29 )\n    ,{0x14, 0x08, 0x3e, 0x08, 0x14} \/\/ 2a *\n    ,{0x08, 0x08, 0x3e, 0x08, 0x08} \/\/ 2b +\n    ,{0x00, 0x50, 0x30, 0x00, 0x00} \/\/ 2c ,\n    ,{0x08, 0x08, 0x08, 0x08, 0x08} \/\/ 2d -\n    ,{0x00, 0x60, 0x60, 0x00, 0x00} \/\/ 2e .\n    ,{0x20, 0x10, 0x08, 0x04, 0x02} \/\/ 2f \/\n    ,{0x3e, 0x51, 0x49, 0x45, 0x3e} \/\/ 30 0\n    ,{0x00, 0x42, 0x7f, 0x40, 0x00} \/\/ 31 1\n    ,{0x42, 0x61, 0x51, 0x49, 0x46} \/\/ 32 2\n    ,{0x21, 0x41, 0x45, 0x4b, 0x31} \/\/ 33 3\n    ,{0x18, 0x14, 0x12, 0x7f, 0x10} \/\/ 34 4\n    ,{0x27, 0x45, 0x45, 0x45, 0x39} \/\/ 35 5\n    ,{0x3c, 0x4a, 0x49, 0x49, 0x30} \/\/ 36 6\n    ,{0x01, 0x71, 0x09, 0x05, 0x03} \/\/ 37 7\n    ,{0x36, 0x49, 0x49, 0x49, 0x36} \/\/ 38 8\n    ,{0x06, 0x49, 0x49, 0x29, 0x1e} \/\/ 39 9\n    ,{0x00, 0x36, 0x36, 0x00, 0x00} \/\/ 3a :\n    ,{0x00, 0x56, 0x36, 0x00, 0x00} \/\/ 3b ;\n    ,{0x08, 0x14, 0x22, 0x41, 0x00} \/\/ 3c \n    ,{0x02, 0x01, 0x51, 0x09, 0x06} \/\/ 3f ?\n    ,{0x32, 0x49, 0x79, 0x41, 0x3e} \/\/ 40 @\n    ,{0x7e, 0x11, 0x11, 0x11, 0x7e} \/\/ 41 A\n    ,{0x7f, 0x49, 0x49, 0x49, 0x36} \/\/ 42 B\n    ,{0x3e, 0x41, 0x41, 0x41, 0x22} \/\/ 43 C\n    ,{0x7f, 0x41, 0x41, 0x22, 0x1c} \/\/ 44 D\n    ,{0x7f, 0x49, 0x49, 0x49, 0x41} \/\/ 45 E\n    ,{0x7f, 0x09, 0x09, 0x09, 0x01} \/\/ 46 F\n    ,{0x3e, 0x41, 0x49, 0x49, 0x7a} \/\/ 47 G\n    ,{0x7f, 0x08, 0x08, 0x08, 0x7f} \/\/ 48 H\n    ,{0x00, 0x41, 0x7f, 0x41, 0x00} \/\/ 49 I\n    ,{0x20, 0x40, 0x41, 0x3f, 0x01} \/\/ 4a J\n    ,{0x7f, 0x08, 0x14, 0x22, 0x41} \/\/ 4b K\n    ,{0x7f, 0x40, 0x40, 0x40, 0x40} \/\/ 4c L\n    ,{0x7f, 0x02, 0x0c, 0x02, 0x7f} \/\/ 4d M\n    ,{0x7f, 0x04, 0x08, 0x10, 0x7f} \/\/ 4e N\n    ,{0x3e, 0x41, 0x41, 0x41, 0x3e} \/\/ 4f O\n    ,{0x7f, 0x09, 0x09, 0x09, 0x06} \/\/ 50 P\n    ,{0x3e, 0x41, 0x51, 0x21, 0x5e} \/\/ 51 Q\n    ,{0x7f, 0x09, 0x19, 0x29, 0x46} \/\/ 52 R\n    ,{0x46, 0x49, 0x49, 0x49, 0x31} \/\/ 53 S\n    ,{0x01, 0x01, 0x7f, 0x01, 0x01} \/\/ 54 T\n    ,{0x3f, 0x40, 0x40, 0x40, 0x3f} \/\/ 55 U\n    ,{0x1f, 0x20, 0x40, 0x20, 0x1f} \/\/ 56 V\n    ,{0x3f, 0x40, 0x38, 0x40, 0x3f} \/\/ 57 W\n    ,{0x63, 0x14, 0x08, 0x14, 0x63} \/\/ 58 X\n    ,{0x07, 0x08, 0x70, 0x08, 0x07} \/\/ 59 Y\n    ,{0x61, 0x51, 0x49, 0x45, 0x43} \/\/ 5a Z\n    ,{0x00, 0x7f, 0x41, 0x41, 0x00} \/\/ 5b [\n    ,{0x02, 0x04, 0x08, 0x10, 0x20} \/\/ 5c ?\n    ,{0x00, 0x41, 0x41, 0x7f, 0x00} \/\/ 5d ]\n    ,{0x04, 0x02, 0x01, 0x02, 0x04} \/\/ 5e ^\n    ,{0x40, 0x40, 0x40, 0x40, 0x40} \/\/ 5f _\n    ,{0x00, 0x01, 0x02, 0x04, 0x00} \/\/ 60 `\n    ,{0x20, 0x54, 0x54, 0x54, 0x78} \/\/ 61 a\n    ,{0x7f, 0x48, 0x44, 0x44, 0x38} \/\/ 62 b\n    ,{0x38, 0x44, 0x44, 0x44, 0x20} \/\/ 63 c\n    ,{0x38, 0x44, 0x44, 0x48, 0x7f} \/\/ 64 d\n    ,{0x38, 0x54, 0x54, 0x54, 0x18} \/\/ 65 e\n    ,{0x08, 0x7e, 0x09, 0x01, 0x02} \/\/ 66 f\n    ,{0x0c, 0x52, 0x52, 0x52, 0x3e} \/\/ 67 g\n    ,{0x7f, 0x08, 0x04, 0x04, 0x78} \/\/ 68 h\n    ,{0x00, 0x44, 0x7d, 0x40, 0x00} \/\/ 69 i\n    ,{0x20, 0x40, 0x44, 0x3d, 0x00} \/\/ 6a j\n    ,{0x7f, 0x10, 0x28, 0x44, 0x00} \/\/ 6b k\n    ,{0x00, 0x41, 0x7f, 0x40, 0x00} \/\/ 6c l\n    ,{0x7c, 0x04, 0x18, 0x04, 0x78} \/\/ 6d m\n    ,{0x7c, 0x08, 0x04, 0x04, 0x78} \/\/ 6e n\n    ,{0x38, 0x44, 0x44, 0x44, 0x38} \/\/ 6f o\n    ,{0x7c, 0x14, 0x14, 0x14, 0x08} \/\/ 70 p\n    ,{0x08, 0x14, 0x14, 0x18, 0x7c} \/\/ 71 q\n    ,{0x7c, 0x08, 0x04, 0x04, 0x08} \/\/ 72 r\n    ,{0x48, 0x54, 0x54, 0x54, 0x20} \/\/ 73 s\n    ,{0x04, 0x3f, 0x44, 0x40, 0x20} \/\/ 74 t\n    ,{0x3c, 0x40, 0x40, 0x20, 0x7c} \/\/ 75 u\n    ,{0x1c, 0x20, 0x40, 0x20, 0x1c} \/\/ 76 v\n    ,{0x3c, 0x40, 0x30, 0x40, 0x3c} \/\/ 77 w\n    ,{0x44, 0x28, 0x10, 0x28, 0x44} \/\/ 78 x\n    ,{0x0c, 0x50, 0x50, 0x50, 0x3c} \/\/ 79 y\n    ,{0x44, 0x64, 0x54, 0x4c, 0x44} \/\/ 7a z\n    ,{0x00, 0x08, 0x36, 0x41, 0x00} \/\/ 7b {\n    ,{0x00, 0x00, 0x7f, 0x00, 0x00} \/\/ 7c |\n    ,{0x00, 0x41, 0x36, 0x08, 0x00} \/\/ 7d }\n    ,{0x10, 0x08, 0x08, 0x10, 0x08} \/\/ 7e ?\n    ,{0x78, 0x46, 0x41, 0x46, 0x78} \/\/ 7f ?\n};\n\nstatic unsigned char width = ST7735_TFTWIDTH;\nstatic unsigned char length = ST7735_TFTLENGTH;\n\n\nvoid SPI_DIO_init(void)\n{\n    GPIO_setAsPeripheralModuleFunctionInputPin(MISO_port, MISO_pin);\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(MOSI_port, MOSI_pin);\n    GPIO_setAsPeripheralModuleFunctionOutputPin(CLK_port, CLK_pin);\n\n    GPIO_setAsOutputPin(RST_port, RST_pin);\n    GPIO_setDriveStrength(RST_port, RST_pin, GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(RS_port, RS_pin);\n    GPIO_setDriveStrength(RS_port, RS_pin, GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(CS_port, CS_pin);\n    GPIO_setDriveStrength(CS_port, CS_pin, GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n}\n\nvoid USCI_SPI_init(void)\n{\n    USCI_B_SPI_initMasterParam SPI_param = {0};\n\n    SPI_DIO_init();\n\n    SPI_param.selectClockSource = USCI_B_SPI_CLOCKSOURCE_SMCLK;\n    SPI_param.clockSourceFrequency = UCS_getSMCLK();\n    SPI_param.desiredSpiClock = 2000000;\n    SPI_param.msbFirst = USCI_B_SPI_MSB_FIRST;\n    SPI_param.clockPhase = USCI_B_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT;\n    SPI_param.clockPolarity = USCI_B_SPI_CLOCKPOLARITY_INACTIVITY_HIGH;\n    \n    USCI_B_SPI_initMaster(USCI_B0_BASE, &amp;SPI_param);\n\n    USCI_B_SPI_enable(USCI_B0_BASE);\n}\n\nvoid ST7735_init(void)\n{\n    USCI_SPI_init();\n    \n    ST7735_Reset();\n    \n    ST7735_Write(ST7735_SWRESET, CMD);\n    delay_us(150);\n    ST7735_Write(ST7735_SLPOUT, CMD);\n    delay_us(150);\n\n    ST7735_Write(ST7735_FRMCTR1, CMD);\n    ST7735_Write(0x01, DAT);\n    ST7735_Write(0x2C, DAT);\n    ST7735_Write(0x2D, DAT);\n    \n    ST7735_Write(ST7735_FRMCTR2, CMD);\n    ST7735_Write(0x01, DAT);\n    ST7735_Write(0x2C, DAT);\n    ST7735_Write(0x2D, DAT);\n    \n    ST7735_Write(ST7735_FRMCTR3, CMD);\n    ST7735_Write(0x01, DAT);\n    ST7735_Write(0x2C, DAT); \n    ST7735_Write(0x2D, DAT);\n    ST7735_Write(0x01, DAT);\n    ST7735_Write(0x2C, DAT);\n    ST7735_Write(0x2D, DAT);\n\n    ST7735_Write(ST7735_INVCTR, CMD);\n    ST7735_Write(0x07, DAT);\n\n    ST7735_Write(ST7735_PWCTR1, CMD);\n    ST7735_Write(0xA2, DAT); \n    ST7735_Write(0x02, DAT); \n    ST7735_Write(0x84, DAT);\n\n    ST7735_Write(ST7735_PWCTR1, CMD);\n    ST7735_Write(0xC5, DAT);\n\n    ST7735_Write(ST7735_PWCTR2, CMD);\n    ST7735_Write(0x0A, DAT);\n    ST7735_Write(0x00, DAT);\n\n    ST7735_Write(ST7735_PWCTR3, CMD);\n    ST7735_Write(0x8A, DAT);\n    ST7735_Write(0x2A, DAT);\n\n    ST7735_Write(ST7735_PWCTR4, CMD);\n    ST7735_Write(0x8A, DAT);\n    ST7735_Write(0xEE, DAT);\n\n    ST7735_Write(ST7735_PWCTR5, CMD);\n    ST7735_Write(0x0E, DAT);\n\n    ST7735_Write(ST7735_VMCTR1, CMD);\n    ST7735_Write(0x00, DAT);\n\n    ST7735_Write(ST7735_COLMOD, CMD);\n    ST7735_Write(0x05, DAT);\n\n    ST7735_Write(ST7735_MADCTL, CMD);\n    ST7735_Write(0xC8, DAT);\n    \n    ST7735_RAM_Address_Set();\n    \n    ST7735_Write(ST7735_GMCTRP1, CMD);\n    ST7735_Write(0x02, DAT);\n    ST7735_Write(0x1C, DAT);\n    ST7735_Write(0x07, DAT);\n    ST7735_Write(0x12, DAT);\n    ST7735_Write(0x37, DAT);\n    ST7735_Write(0x32, DAT);\n    ST7735_Write(0x29, DAT);\n    ST7735_Write(0x2D, DAT);\n    ST7735_Write(0x29, DAT);\n    ST7735_Write(0x25, DAT);\n    ST7735_Write(0x2B, DAT);\n    ST7735_Write(0x39, DAT);\n    ST7735_Write(0x00, DAT);\n    ST7735_Write(0x01, DAT);\n    ST7735_Write(0x03, DAT);\n    ST7735_Write(0x10, DAT);\n    \n    ST7735_Write(ST7735_GMCTRN1, CMD);\n    ST7735_Write(0x03, DAT);\n    ST7735_Write(0x1D, DAT);\n    ST7735_Write(0x07, DAT);\n    ST7735_Write(0x06, DAT);\n    ST7735_Write(0x2E, DAT);\n    ST7735_Write(0x2C, DAT);\n    ST7735_Write(0x29, DAT);\n    ST7735_Write(0x2D, DAT);\n    ST7735_Write(0x2E, DAT);\n    ST7735_Write(0x2E, DAT);\n    ST7735_Write(0x37, DAT);\n    ST7735_Write(0x3F, DAT);\n    ST7735_Write(0x00, DAT);\n    ST7735_Write(0x00, DAT);\n    ST7735_Write(0x02, DAT);\n    ST7735_Write(0x10, DAT);\n\n    ST7735_Write(ST7735_NORON, CMD);\n    delay_ms(10);\n\n    ST7735_Write(ST7735_DISPON, CMD);\n    delay_ms(100);\n    \n    ST7735_Write(ST7735_RAMWR, CMD);\n    delay_ms(100);\n}\n\nvoid ST7735_Write(unsigned char value, unsigned char mode)\n{\n    CS_pin_low();\n    \n    if(mode != 0)\n    {\n        RS_pin_high();\n    }\n    else\n    {\n        RS_pin_low();\n    }\n\n    USCI_B_SPI_transmitData(USCI_B0_BASE, value);\n    while(USCI_B_SPI_isBusy(USCI_B0_BASE));\n    \n    CS_pin_high();\n}\n\nvoid ST7735_Reset(void)\n{\n    RST_pin_low();\n    delay_ms(2);\n    RST_pin_high();\n    delay_ms(2);\n}\n\nvoid ST7735_Word_Write(unsigned int value)\n{\n    ST7735_Write(((value &amp; 0xFF00) &gt;&gt; 0x08), DAT);\n    ST7735_Write((value &amp; 0x00FF), DAT);\n}\n\nvoid ST7735_Data_Write(unsigned char DataH, unsigned char DataL)\n{\n    ST7735_Write(DataH, DAT);\n    ST7735_Write(DataL, DAT);\n}\n\nvoid ST7735_Data_Write_4k(unsigned char DataH, unsigned char DataM, unsigned char DataL)\n{\n    ST7735_Write(DataH, DAT);\n    ST7735_Write(DataM, DAT);\n    ST7735_Write(DataL, DAT);\n}\n\nvoid ST7735_Set_Addr_Window(unsigned char xs, unsigned char ys, unsigned char xe, unsigned char ye)\n{\n    ST7735_Write(ST7735_CASET, CMD);\n    ST7735_Write(0x00, DAT);\n    ST7735_Write(xs, DAT);\n    ST7735_Write(0x00, DAT);\n    ST7735_Write(xe, DAT);\n\n    ST7735_Write(ST7735_RASET, CMD);\n    ST7735_Write(0x00, DAT);\n    ST7735_Write(ys, DAT);\n    ST7735_Write(0x00, DAT);\n    ST7735_Write(ye, DAT);\n\n    ST7735_Write(ST7735_RAMWR, CMD);\n}\n\nvoid ST7735_RAM_Address_Set(void)\n{\n    ST7735_Set_Addr_Window(0x00, 0x00, 0x7F, 0x9F);\n}\n\nvoid ST7735_Invert_Display(unsigned char i)\n{\n     if(i == ST7735_INVON)\n     {\n         ST7735_Write(ST7735_INVON, CMD);\n     }\n     else\n     {\n         ST7735_Write(ST7735_INVOFF, CMD);\n     }\n}\n\nunsigned int ST7735_Swap_Colour(unsigned int colour)\n{\n    return ((colour &lt;&gt; 0x000B));\n}\n\nunsigned int ST7735_Color565(unsigned char r, unsigned char g, unsigned char b)\n{\n    return (((r &amp; 0xF8) &lt;&lt; 0x08) | ((g &amp; 0xFC) &lt;&gt; 0x03));\n}\n\nvoid ST7735_Set_Rotation(unsigned char m)\n{\n    unsigned char rotation = 0x00;\n\n    ST7735_Write(ST7735_MADCTL, CMD);\n    rotation = (m % 4);\n    \n    switch(rotation)\n    {\n        case 0:\n        {\n            ST7735_Write((MADCTL_MX | MADCTL_MY | MADCTL_RGB), DAT);\n            width = ST7735_TFTWIDTH;\n            length = ST7735_TFTLENGTH;\n            break;\n        }\n        case 1:\n        {\n            ST7735_Write((MADCTL_MY | MADCTL_MV | MADCTL_RGB), DAT);\n            width = ST7735_TFTLENGTH;\n            length = ST7735_TFTWIDTH;\n            break;\n        }\n        case 2:\n        {\n            ST7735_Write((MADCTL_RGB), DAT);\n            width = ST7735_TFTWIDTH;\n            length = ST7735_TFTLENGTH;\n            break;\n        }\n        case 3:\n        {\n            ST7735_Write((MADCTL_MX | MADCTL_MV | MADCTL_RGB), DAT);\n            width = ST7735_TFTLENGTH;\n            length = ST7735_TFTWIDTH;\n            break;\n        }\n    }\n}\n\nvoid TFT_fill(unsigned int colour)\n{\n    unsigned char i = 0x00;\n    unsigned char j = 0x00;\n\n    ST7735_Set_Addr_Window(0, 0, (width - 1), (length - 1));\n\n    for(j = length; j &gt; 0; j--)\n    {\n        for(i = width; i &gt; 0; i--)\n        {\n            ST7735_Word_Write(colour);\n        }\n    }\n}\n\nvoid Draw_Pixel(unsigned char x_pos, unsigned char y_pos, unsigned int colour)\n{\n    ST7735_Set_Addr_Window(x_pos, y_pos, (1 + x_pos), (1 + y_pos));\n     ST7735_Word_Write(colour);\n}\n\nvoid Draw_Line(signed int x1, signed int y1, signed int x2, signed int y2, unsigned int colour)\n{\n    signed int dx = 0x0000;\n    signed int dy = 0x0000;\n    signed int stepx = 0x0000;\n    signed int stepy = 0x0000;\n    signed int fraction = 0x0000;\n\n    dy = (y2 - y1);\n    dx = (x2 - x1);\n\n    if (dy &lt; 0)\n    {\n        dy = -dy;\n        stepy = -1;\n    }\n    else\n    {\n        stepy = 1;\n    }\n\n    if (dx &lt; 0)\n    {\n        dx = -dx;\n        stepx = -1;\n    }\n    else\n    {\n        stepx = 1;\n    }\n\n    dx &lt;&lt;= 0x01;\n    dy &lt; dy)\n    {\n        fraction = (dy - (dx &gt;&gt; 1));\n        while (x1 != x2)\n        {\n            if (fraction &gt;= 0)\n            {\n                y1 += stepy;\n                fraction -= dx;\n            }\n            x1 += stepx;\n            fraction += dy;\n\n            Draw_Pixel(x1, y1, colour);\n        }\n    }\n    else\n    {\n        fraction = (dx - (dy &gt;&gt; 1));\n\n        while (y1 != y2)\n        {\n            if (fraction &gt;= 0)\n            {\n                x1 += stepx;\n                fraction -= dy;\n            }\n            y1 += stepy;\n            fraction += dx;\n            Draw_Pixel(x1, y1, colour);\n        }\n    }\n}\n\nvoid Draw_Rectangle(signed int x1, signed int y1, signed int x2, signed int y2, unsigned char fill, unsigned char type, unsigned int colour, unsigned int back_colour)\n{\n     unsigned char i = 0x00;\n     unsigned char xmin = 0x00;\n     unsigned char xmax = 0x00;\n     unsigned char ymin = 0x00;\n     unsigned char ymax = 0x00;\n\n     if(fill != NO)\n     {\n        if(x1 &lt; x2)\n        {\n           xmin = x1;\n           xmax = x2;\n        }\n        else\n        {\n           xmin = x2;\n           xmax = x1;\n        }\n\n        if(y1 &lt; y2)\n        {\n           ymin = y1;\n           ymax = y2;\n        }\n        else\n        {\n           ymin = y2;\n           ymax = y1;\n        }\n\n        for(; xmin &lt;= xmax; ++xmin)\n        {\n             for(i = ymin; i &lt;= ymax; ++i)\n             {\n                 Draw_Pixel(xmin, i, colour);\n             }\n         }\n     }\n\n     else\n     {\n        Draw_Line(x1, y1, x2, y1, colour);\n        Draw_Line(x1, y2, x2, y2, colour);\n        Draw_Line(x1, y1, x1, y2, colour);\n        Draw_Line(x2, y1, x2, y2, colour);\n     }\n\n     if(type != SQUARE)\n     {\n         Draw_Pixel(x1, y1, back_colour);\n         Draw_Pixel(x1, y2, back_colour);\n         Draw_Pixel(x2, y1, back_colour);\n         Draw_Pixel(x2, y2, back_colour);\n     }\n}\n\nvoid Draw_Circle(signed int xc, signed int yc, signed int radius, unsigned char fill, unsigned int colour)\n{\n   signed int a = 0x0000;\n   signed int b = 0x0000;\n   signed int p = 0x0000;\n\n   b = radius;\n   p = (1 - b);\n\n   do\n   {\n        if(fill != NO)\n        {\n            Draw_Line((xc - a), (yc + b), (xc + a), (yc + b), colour);\n            Draw_Line((xc - a), (yc - b), (xc + a), (yc - b), colour);\n            Draw_Line((xc - b), (yc + a), (xc + b), (yc + a), colour);\n            Draw_Line((xc - b), (yc - a), (xc + b), (yc - a), colour);\n        }\n        else\n        {\n            Draw_Pixel((xc + a), (yc + b), colour);\n            Draw_Pixel((xc + b), (yc + a), colour);\n            Draw_Pixel((xc - a), (yc + b), colour);\n            Draw_Pixel((xc - b), (yc + a), colour);\n            Draw_Pixel((xc + b), (yc - a), colour);\n            Draw_Pixel((xc + a), (yc - b), colour);\n            Draw_Pixel((xc - a), (yc - b), colour);\n            Draw_Pixel((xc - b), (yc - a), colour);\n        }\n\n        if(p &lt; 0)\n        {\n            p += (0x03 + (0x02 * a++));\n        }\n        else\n        {\n            p += (0x05 + (0x02 * ((a++) - (b--))));\n        }\n    }while(a &lt;= b);\n}\n\nvoid Draw_Font_Pixel(unsigned char x_pos, unsigned char y_pos, unsigned int colour, unsigned char pixel_size)\n{\n     unsigned char i = 0x00;\n\n     ST7735_Set_Addr_Window(x_pos, y_pos, (x_pos + pixel_size - 1), (y_pos + pixel_size - 1));\n\n     for(i = 0x00; i &lt; (pixel_size * pixel_size); i++)\n     {\n         ST7735_Word_Write(colour);\n     }\n}\n\nvoid print_char(unsigned char x_pos, unsigned char y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, unsigned char ch)\n{\n     unsigned char i = 0x00;\n     unsigned char j = 0x00;\n\n     unsigned char value = 0x00;\n\n     if(font_size &lt; 1)\n     {\n         font_size = 1;\n     }\n\n     if(x_pos &lt; font_size)\n     {\n         x_pos = font_size;\n     }\n\n     for (i = 0x00; i &lt; 0x05; i++)\n     {\n         for (j = 0x00; j &gt; j)  &amp; 0x01)\n             {\n                 Draw_Font_Pixel(x_pos, y_pos, colour, font_size);\n             }\n             else\n             {\n                 Draw_Font_Pixel(x_pos, y_pos, back_colour, font_size);\n             }\n\n             y_pos = y_pos + font_size;\n          }\n          y_pos -= (font_size &lt; width)\n      {\n          x_pos = (font_size + 0x01);\n          y_pos += (font_size &lt;= 0x20) &amp;&amp; (*ch &lt;= 0x7F));\n}\n\nvoid print_C(unsigned char x_pos, unsigned char y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, signed int value)\n{\n    unsigned char ch[5] = {0x20, 0x20, 0x20, 0x20, 0x20};\n\n     if(value  99) &amp;&amp; (value  9) &amp;&amp; (value = 0) &amp;&amp; (value &lt;= 9))\n     {\n         ch[1] = ((value % 10) + 0x30);\n         ch[2] = 0x20;\n         ch[3] = 0x20;\n     }\n\n     print_str(x_pos, y_pos, font_size, colour, back_colour, ch);\n}\n\nvoid print_I(unsigned char x_pos, unsigned char y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, signed int value)\n{\n    unsigned char ch[7] = {0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};\n\n    if(value  9999)\n    {\n        ch[1] = ((value \/ 10000) + 0x30);\n        ch[2] = (((value % 10000)\/ 1000) + 0x30);\n        ch[3] = (((value % 1000) \/ 100) + 0x30);\n        ch[4] = (((value % 100) \/ 10) + 0x30);\n        ch[5] = ((value % 10) + 0x30);\n    }\n\n    else if((value &gt; 999) &amp;&amp; (value  99) &amp;&amp; (value  9) &amp;&amp; (value  1)\n    {\n        ch[2] = (((value % 1000) \/ 100) + 0x30);\n\n        if(points &gt; 2)\n        {\n            ch[3] = (((value % 100) \/ 10) + 0x30);\n\n            if(points &gt; 3)\n            {\n                ch[4] = ((value % 10) + 0x30);\n            }\n        }\n    }\n\n    print_str(x_pos, y_pos, font_size, colour, back_colour, ch);\n}\n\nvoid print_F(unsigned char x_pos, unsigned char y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, float value, unsigned char points)\n{\n    signed long tmp = 0x0000;\n\n    tmp = (signed long)value;\n    print_I(x_pos, y_pos, font_size, colour, back_colour, tmp);\n    tmp = ((signed long)((value - (float)tmp) * 10000));\n\n    if(tmp = 10000) &amp;&amp; (value = 1000) &amp;&amp; (value = 100) &amp;&amp; (value = 10) &amp;&amp; (value &lt; 100))\n    {\n        print_D((x_pos + (0x12 * font_size)), y_pos, font_size, colour, back_colour, tmp, points);\n    }\n    else if(value &lt; 10)\n    {\n        print_D((x_pos + (0x0C * font_size)), y_pos, font_size, colour, back_colour, tmp, points);\n\n        if((value) &lt; 0)\n        {\n            print_char(x_pos, y_pos, font_size, colour, back_colour, 0x2D);\n        }\n        else\n        {\n            print_char(x_pos, y_pos, font_size, colour, back_colour, 0x20);\n        }\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>main.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"ST7735.h\"\n#include \"MMA7455L.h\"\n\nvoid clock_init(void);\n\nvoid main(void)\n{\n    signed char x_axis_8 = 0;\n    signed char y_axis_8 = 0;\n    signed char z_axis_8 = 0;\n\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    ST7735_init();\n    MMA7455L_init();\n\n    ST7735_Set_Rotation(0x02);\n    TFT_fill(BLACK);\n\n    print_str(1, 100, 1, GREEN, BLACK, \"X8:\");\n    print_str(1, 110, 1, GREEN, BLACK, \"Y8:\");\n    print_str(1, 120, 1, GREEN, BLACK, \"Z8:\");\n\n\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n\n    GPIO_setDriveStrength(GPIO_PORT_P4,\n                          GPIO_PIN7,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    while(1)\n    {\n        x_axis_8 = MMA7455L_read_axis_8(MMA7455L_X_out);\n        y_axis_8 = MMA7455L_read_axis_8(MMA7455L_Y_out);\n        z_axis_8 = MMA7455L_read_axis_8(MMA7455L_Z_out);\n\n        print_C(45, 100, 1, GREEN, BLACK, x_axis_8);\n        print_C(45, 110, 1, GREEN, BLACK, y_axis_8);\n        print_C(45, 120, 1, GREEN, BLACK, z_axis_8);\n\n        Draw_Circle(x_axis_8, x_axis_8, 2, YES, CYAN);\n\n        GPIO_toggleOutputOnPin(GPIO_PORT_P4,\n                               GPIO_PIN7);\n\n        delay_ms(100);\n\n        Draw_Circle(x_axis_8, x_axis_8, 2, YES, BLACK);\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_FLLREF,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initFLLSettle(MCLK_KHZ,\n                      MCLK_FLLREF_RATIO);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"628\" height=\"627\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI1.png\" alt=\"\" class=\"wp-image-14678\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI1.png 628w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI1-150x150.png 150w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI1-580x579.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI1-90x90.png 90w\" sizes=\"auto, (max-width: 628px) 100vw, 628px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s check the I2C functions of USCI first. USCI B1 is used in I2C mode here. We start by setting alternative roles of I2C GPIO pins as shown below:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">GPIO_setAsPeripheralModuleFunctionOutputPin(I2C_port, (I2C_SDA_pin | I2C_SCL_pin));<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After setting the I2C pins, the I2C hardware is ready to be initialized.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void USCI_I2C_init(void)\n{\n    USCI_B_I2C_initMasterParam I2C_param = {0};\n\n    I2C_DIO_init();\n\n    I2C_param.selectClockSource = USCI_B_I2C_CLOCKSOURCE_SMCLK;\n    I2C_param.i2cClk = UCS_getSMCLK();\n    I2C_param.dataRate = USCI_B_I2C_SET_DATA_RATE_100KBPS;\n\n    USCI_B_I2C_initMaster(USCI_B1_BASE, &amp;I2C_param);\n\n    USCI_B_I2C_enable(USCI_B1_BASE);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For initialization, we need to set I2C module\u2019s clock source first. In this case, the clock source is SMCLK. SMCLK, in this example, is running at 1 MHz as it is being sourced by prescaled XT2 clock source. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">UCS_initClockSignal(UCS_SMCLK, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_4);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We have to let the USCI I2C module know the speed of SMCLK and\ndecide our I2C clock rate. Internal mechanism scales the I2C clock source to\nmatch the desired I2C data clock rate. Here we set the clock rate to 100 kbps. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After setting all these, we enable the USCI I2C module. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Note that no interrupt has been used as polling is good enough for basic\nI2C communication.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now let\u2019s check I2C write operations. Shown below are two types of I2C write operation functions. The first one is coded with driverlib and the other is what we usually do in other microcontrollers and in other software platforms. These are shown to highlight key differences. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void MMA7455L_write_byte(unsigned char address, unsigned char value)\n{\n    USCI_B_I2C_setSlaveAddress(USCI_B1_BASE, MMA7455L_address);\n    USCI_B_I2C_setMode(USCI_B1_BASE, USCI_B_I2C_TRANSMIT_MODE);\n\n    USCI_B_I2C_masterSendMultiByteStart(USCI_B1_BASE, address);\n    while(!USCI_B_I2C_masterIsStartSent(USCI_B1_BASE));\n    USCI_B_I2C_masterSendMultiByteFinish(USCI_B1_BASE, value);\n\n    while(USCI_B_I2C_isBusBusy(USCI_B1_BASE));\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The driverlib-based I2C write operation hides several stuffs in contrast to the operation shown below:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void MMA7455L_write_byte(unsigned char address, unsigned char value)\n{\n    I2C_Start();                \n    I2C_Write(MMA7455L_write_address); \n    I2C_Write(address);              \n    I2C_Write(value);   \n    I2C_Stop();  \n    delay_ms(250);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Firstly, there is no I2C start and stop command in driverlib as\nthese are hidden and done internally under the hood of driverlib functions. Secondly,\nwe have to mention in our code if the I2C mode of data transaction is a\ntransmission or a reception. Lastly, the I2C bus is polled for I2C bus status.\nThe polling loops till the bus is free. I believe these differences are clear\nnow. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now let\u2019s see the I2C read operations. Just like the write operations, we will again check differences between driverlib and conventional I2C bus reading method. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">unsigned char MMA7455L_read_byte(unsigned char address)\n{\n    unsigned char value = 0x00;\n\n    USCI_B_I2C_setSlaveAddress(USCI_B1_BASE, MMA7455L_address);\n    USCI_B_I2C_setMode(USCI_B1_BASE, USCI_B_I2C_TRANSMIT_MODE);\n\n    USCI_B_I2C_masterSendStart(USCI_B1_BASE);\n    USCI_B_I2C_masterSendSingleByte(USCI_B1_BASE, address);\n\n    USCI_B_I2C_setSlaveAddress(USCI_B1_BASE, MMA7455L_address);\n    USCI_B_I2C_setMode(USCI_B1_BASE, USCI_B_I2C_RECEIVE_MODE);\n\n    USCI_B_I2C_masterReceiveSingleStart(USCI_B1_BASE);\n    value = USCI_B_I2C_masterReceiveSingle(USCI_B1_BASE);\n\n    while(USCI_B_I2C_isBusBusy(USCI_B1_BASE));\n\n    return value;\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The code snippet below shows conventional I2C bus read:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">unsigned char MMA7455L_read_byte(unsigned char address)   \n{   \n    unsigned char value = 0;\n   \n    I2C_Start();                                   \n    I2C_Write(MMA7455L_write_address);                                            \n    I2C_Write(address); \n\n    I2C_Restart(); \n    I2C_Write(MMA7455L_read_address); \n    value = I2C_Read(0);                         \n    I2C_Stop(); \n\n    return value;               \n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The key differences between these two code snippets above are\nsimilar as the ones we already noticed in I2C write codes. I stated similar\nbecause there are some new additions to these already existing differences.\nFirstly, note that there is no I2C restart or start function in driverlib as\nsending out slave address incorporates that in secret. Secondly, during an I2C\nread, there is a transmission and a reception session and so there are two USCI\nmodes in a bus read operation. Lastly, note that read acknowledgement\n(ACK\/NACK) is not manually sent in driverlib as again it is done under the\nhood. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I believe, by now, the driverlib concepts for I2C are clear.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Since we are using a TFT display as an external SPI device in this example and not reading it, we will just be focusing on SPI write operation only. Firstly, we declare all necessary GPIO pins.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#define MOSI_port                 GPIO_PORT_P3\n#define MISO_port                 GPIO_PORT_P3\n#define CLK_port                  GPIO_PORT_P3\n#define RST_port                  GPIO_PORT_P3\n#define RS_port                   GPIO_PORT_P3\n#define CS_port                   GPIO_PORT_P3\n\n#define MOSI_pin                  GPIO_PIN0\n#define MISO_pin                  GPIO_PIN1\n#define CLK_pin                   GPIO_PIN2\n#define RST_pin                   GPIO_PIN3\n#define RS_pin                    GPIO_PIN4\n#define CS_pin                    GPIO_PIN5\n\n#define MOSI_pin_high()           GPIO_setOutputHighOnPin(MOSI_port, MOSI_pin)\n#define MOSI_pin_low()            GPIO_setOutputLowOnPin(MOSI_port, MOSI_pin)\n\n#define get_MISO_pin()            GPIO_getInputPinValue(MISO_port, MISO_pin)\n\n#define CLK_pin_high()            GPIO_setOutputHighOnPin(CLK_port, CLK_pin)\n#define CLK_pin_low()             GPIO_setOutputLowOnPin(CLK_port, CLK_pin)\n\n#define RST_pin_high()            GPIO_setOutputHighOnPin(RST_port, RST_pin)\n#define RST_pin_low()             GPIO_setOutputLowOnPin(RST_port, RST_pin)\n\n#define RS_pin_high()             GPIO_setOutputHighOnPin(RS_port, RS_pin) #define RS_pin_low()              GPIO_setOutputLowOnPin(RS_port, RS_pin)\n\n#define CS_pin_high()             GPIO_setOutputHighOnPin(CS_port, CS_pin)\n#define CS_pin_low()              GPIO_setOutputLowOnPin(CS_port, CS_pin)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We, then, initialize the GPIOs as per pin characteristics. SPI pins, just like I2C pins, are initialized as secondary function pins while the rest are initialized as ordinary GPIOs. &nbsp;&nbsp;  <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void SPI_DIO_init(void)\n{\n    GPIO_setAsPeripheralModuleFunctionInputPin(MISO_port, MISO_pin);\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(MOSI_port, MOSI_pin);\n    GPIO_setAsPeripheralModuleFunctionOutputPin(CLK_port, CLK_pin);\n\n    GPIO_setAsOutputPin(RST_port, RST_pin);\n    GPIO_setDriveStrength(RST_port, RST_pin, GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(RS_port, RS_pin);\n    GPIO_setDriveStrength(RS_port, RS_pin, GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(CS_port, CS_pin);\n    GPIO_setDriveStrength(CS_port, CS_pin, GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Next, we initialize the USCI B0 module in SPI mode.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void USCI_SPI_init(void)\n{\n    USCI_B_SPI_initMasterParam SPI_param = {0};\n\n    SPI_DIO_init();\n\n    SPI_param.selectClockSource = USCI_B_SPI_CLOCKSOURCE_SMCLK;\n    SPI_param.clockSourceFrequency = UCS_getSMCLK();\n    SPI_param.desiredSpiClock = 2000000;\n    SPI_param.msbFirst = USCI_B_SPI_MSB_FIRST;\n    SPI_param.clockPhase = USCI_B_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT;\n    SPI_param.clockPolarity = USCI_B_SPI_CLOCKPOLARITY_INACTIVITY_HIGH;\n    \n    USCI_B_SPI_initMaster(USCI_B0_BASE, &amp;SPI_param);\n\n    USCI_B_SPI_enable(USCI_B0_BASE);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The first part SPI module\u2019s initialization is the initialization of\nrequired GPIOs. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Like I2C, we have to declare the source of SPI clock (here SMCLK),\nits frequency and the SPI clock speed. SPI needs additional info like clock\npolarity, clock phase and data orientation. These are also needed to be set. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After setting all these, we have our USCI SPI module ready to rock-&amp;-roll.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">SPI write is very simple and straight forward. We just have to write desired value(s) and wait for the SPI bus to get free. As we all know, for most SPI devices, chip select pin needs to be low prior to a read\/write operation and high after completion of read\/write. This is done here too.&nbsp;&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void ST7735_Write(unsigned char value, unsigned char mode)\n{\n    CS_pin_low();\n    \n    if(mode != 0)\n    {\n        RS_pin_high();\n    }\n    else\n    {\n        RS_pin_low();\n    }\n\n    USCI_B_SPI_transmitData(USCI_B0_BASE, value);\n    while(USCI_B_SPI_isBusy(USCI_B0_BASE));\n    \n    CS_pin_high();\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The demo here reads a MMA7455L accelerometer and plots a circle on a ST7735 TFT display. The coordinates of the circle are based on the X-Y values of the accelerometer. The accelerometer\u2019s axes values are also displayed. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI-EX1-1024x768.jpg\" alt=\"\" class=\"wp-image-14679\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI-EX1-1024x768.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI-EX1-580x435.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI-EX1-768x576.jpg 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/SZvO0WUhLM0?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">USCI \u2013 SPI \u2013 I2C Example 2<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">We covered most of the stuffs that are needed to be understood and applied for using USCI in SPI and I2C modes. However, we didn\u2019t see any SPI read operation in our last example. This example is meant to eliminate that missing stuff while allowing us to explore and practice USCI modules further. It is yet another over-simplified example. A MAX6675 SPI-based thermocouple-digital converter is read using a MSP430\u2019s USCI in SPI mode while an I2C-based SSD1306 OLED display is used to display the temperature read from the thermocouple.  <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>MAX6675.h<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n\n#define MOSI_port                   GPIO_PORT_P3\n#define MISO_port                   GPIO_PORT_P3\n#define CLK_port                    GPIO_PORT_P2\n#define CS_port                     GPIO_PORT_P3\n\n#define MOSI_pin                    GPIO_PIN3\n#define MISO_pin                    GPIO_PIN4\n#define CLK_pin                     GPIO_PIN7\n#define CS_pin                      GPIO_PIN2\n\n#define MOSI_pin_high()             GPIO_setOutputHighOnPin(MOSI_port, MOSI_pin)\n#define MOSI_pin_low()              GPIO_setOutputLowOnPin(MOSI_port, MOSI_pin)\n\n#define get_MISO_pin()              GPIO_getInputPinValue(MISO_port, MISO_pin)\n\n#define CLK_pin_high()              GPIO_setOutputHighOnPin(CLK_port, CLK_pin)\n#define CLK_pin_low()               GPIO_setOutputLowOnPin(CLK_port, CLK_pin)\n\n#define CS_pin_high()               GPIO_setOutputHighOnPin(CS_port, CS_pin)\n#define CS_pin_low()                GPIO_setOutputLowOnPin(CS_port, CS_pin)\n\n#define T_min                       0\n#define T_max                       1024\n\n#define count_max                   4096\n\n#define no_of_pulses                16\n\n#define deg_C                       0\n#define deg_F                       1\n#define tmp_K                       2\n\n#define open_contact                0x04\n#define close_contact               0x00\n\n#define scalar_deg_C                0.25\n#define scalar_deg_F_1              1.8\n#define scalar_deg_F_2              32.0\n#define scalar_tmp_K                273.0\n\n#define no_of_samples               16\n\nvoid SPI_DIO_init(void);\nvoid USCI_SPI_init(void);\nvoid MAX6675_init(void);\nunsigned char MAX6675_get_ADC(unsigned int *ADC_data);\nfloat MAX6675_get_T(unsigned int ADC_value, unsigned char T_unit);\t<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>MAX6675.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"MAX6675.h\"\n\nvoid SPI_DIO_init(void)\n{\n    GPIO_setAsPeripheralModuleFunctionInputPin(MISO_port, MISO_pin);\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(MOSI_port, MOSI_pin);\n    GPIO_setAsPeripheralModuleFunctionOutputPin(CLK_port, CLK_pin);\n\n    GPIO_setAsOutputPin(CS_port, CS_pin);\n    GPIO_setDriveStrength(CS_port, CS_pin, GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n}\n\nvoid USCI_SPI_init(void)\n{\n    USCI_A_SPI_initMasterParam SPI_param = {0};\n\n    SPI_DIO_init();\n\n    SPI_param.selectClockSource = USCI_A_SPI_CLOCKSOURCE_SMCLK;\n    SPI_param.clockSourceFrequency = UCS_getSMCLK();\n    SPI_param.desiredSpiClock = 1000000;\n    SPI_param.msbFirst = USCI_A_SPI_MSB_FIRST;\n    SPI_param.clockPhase = USCI_A_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT;\n    SPI_param.clockPolarity = USCI_A_SPI_CLOCKPOLARITY_INACTIVITY_LOW;\n\n    USCI_A_SPI_initMaster(USCI_A0_BASE, &amp;SPI_param);\n\n    USCI_A_SPI_enable(USCI_A0_BASE);\n}\n\nvoid MAX6675_init(void)\n{\n    USCI_SPI_init();\n}\n\nunsigned char MAX6675_get_ADC(unsigned int *ADC_data)\n{\n    unsigned char lb = 0;\n    unsigned char hb = 0;\n    unsigned char samples = no_of_samples;\n    unsigned int temp_data = 0;\n    unsigned long avg_value = 0;\n\n    while(samples &gt; 0)\n    {\n        CS_pin_low();\n            \n        USCI_A_SPI_transmitData(USCI_A0_BASE, 0x00);\n        while(USCI_A_SPI_isBusy(USCI_A0_BASE));\n        hb = USCI_A_SPI_receiveData(USCI_A0_BASE);\n        while(USCI_A_SPI_isBusy(USCI_A0_BASE));\n\n        USCI_B_SPI_transmitData(USCI_A0_BASE, 0x00);\n        while(USCI_A_SPI_isBusy(USCI_A0_BASE));\n        lb = USCI_A_SPI_receiveData(USCI_A0_BASE);\n        while(USCI_A_SPI_isBusy(USCI_A0_BASE));\n\n         CS_pin_high();\n         \n         temp_data = hb;\n         temp_data &lt;&gt; 4);\n\n    if((temp_data &amp; 0x04) == close_contact)\n    {\n        *ADC_data = (temp_data &gt;&gt; 3);\n        return close_contact;\n    }\n    else\n    {\n        *ADC_data = (count_max + 1);\n        return open_contact;\n    }\n}\n\nfloat MAX6675_get_T(unsigned int ADC_value, unsigned char T_unit)\n{\n    float tmp = 0.0;\n\n    tmp = (((float)ADC_value) * scalar_deg_C);\n\n    switch(T_unit)\n    {\n        case deg_F:\n        {\n             tmp *= scalar_deg_F_1;\n             tmp += scalar_deg_F_2;\n             break;\n        }\n        case tmp_K:\n        {\n            tmp += scalar_tmp_K;\n            break;\n        }\n        default:\n        {\n            break;\n        }\n    }\n\n    return tmp;\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>SSD1306.h<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n\n#define I2C_port                                  GPIO_PORT_P3\n\n#define I2C_SDA_pin                               GPIO_PIN0\n#define I2C_SCL_pin                               GPIO_PIN1\n\n#define SSD1306_I2C_Address                       0x3C\n\n#define DAT                                       0x60\n#define CMD                                       0x00\n\n#define Set_Lower_Column_Start_Address_CMD        0x00\n#define Set_Higher_Column_Start_Address_CMD       0x10\n#define Set_Memory_Addressing_Mode_CMD            0x20\n#define Set_Column_Address_CMD                    0x21\n#define Set_Page_Address_CMD                      0x22\n#define Set_Display_Start_Line_CMD                0x40\n#define Set_Contrast_Control_CMD                  0x81\n#define Set_Charge_Pump_CMD                       0x8D\n#define Set_Segment_Remap_CMD                     0xA0\n#define Set_Entire_Display_ON_CMD                 0xA4\n#define Set_Normal_or_Inverse_Display_CMD         0xA6\n#define Set_Multiplex_Ratio_CMD                   0xA8\n#define Set_Display_ON_or_OFF_CMD                 0xAE\n#define Set_Page_Start_Address_CMD                0xB0\n#define Set_COM_Output_Scan_Direction_CMD         0xC0\n#define Set_Display_Offset_CMD                    0xD3\n#define Set_Display_Clock_CMD                     0xD5\n#define Set_Pre_charge_Period_CMD                 0xD9\n#define Set_Common_HW_Config_CMD                  0xDA\n#define Set_VCOMH_Level_CMD                       0xDB\n#define Set_NOP_CMD                               0xE3\n\n#define Horizontal_Addressing_Mode                0x00\n#define Vertical_Addressing_Mode                  0x01\n#define Page_Addressing_Mode                      0x02\n\n#define Disable_Charge_Pump                       0x00\n#define Enable_Charge_Pump                        0x04\n\n#define Column_Address_0_Mapped_to_SEG0           0x00\n#define Column_Address_0_Mapped_to_SEG127         0x01\n\n#define Normal_Display                            0x00\n#define Entire_Display_ON                         0x01\n\n#define Non_Inverted_Display                      0x00\n#define Inverted_Display                          0x01\n\n#define Display_OFF                               0x00\n#define Display_ON                                0x01\n\n#define Scan_from_COM0_to_63                      0x00\n#define Scan_from_COM63_to_0                      0x08\n\n#define x_size                                    128\n#define x_max                                     x_size\n#define x_min                                     0\n#define y_size                                    32\n#define y_max                                     8\n#define y_min                                     0\n\n#define ON                                        1\n#define OFF                                       0\n\n#define YES                                       1\n#define NO                                        0\n\n#define ROUND                                     1\n#define SQUARE                                    0\n\n#define NUM                                       1\n#define CHR                                       0\n\n#define buffer_size                               512\/\/(x_max * y_max)\n\nunsigned char buffer[buffer_size];\n\nvoid swap(signed int *a, signed int *b);\nvoid I2C_DIO_init(void);\nvoid USCI_I2C_init(void);\nvoid OLED_init(void);\nvoid OLED_write(unsigned char value, unsigned char control_byte);\nvoid OLED_gotoxy(unsigned char x_pos, unsigned char y_pos);\nvoid OLED_fill(unsigned char bmp_data);\nvoid OLED_clear_screen(void);\nvoid OLED_clear_buffer(void);\nvoid OLED_cursor(unsigned char x_pos, unsigned char y_pos);\nvoid print_char(unsigned char x_pos, unsigned char y_pos, unsigned char num_reg_state, unsigned char ch);\nvoid print_string(unsigned char x_pos, unsigned char y_pos, unsigned char num_reg_state, unsigned char *ch);\nvoid print_chr(unsigned char x_pos, unsigned char y_pos, unsigned char num_reg_state, signed int value);\nvoid print_int(unsigned char x_pos, unsigned char y_pos, unsigned char num_reg_state, signed long value);\nvoid print_decimal(unsigned char x_pos, unsigned char y_pos, unsigned char num_reg_state, unsigned int value, unsigned char points);\nvoid print_float(unsigned char x_pos, unsigned char y_pos, unsigned char num_reg_state, float value, unsigned char points);\nvoid draw_bitmap(unsigned char xb, unsigned char yb, unsigned char xe, unsigned char ye, unsigned char *bmp_img);\nvoid draw_pixel(unsigned char x_pos, unsigned char y_pos, unsigned char colour);\nvoid draw_line(signed int x1, signed int y1, signed int x2, signed int y2, unsigned char colour);\nvoid draw_V_line(signed int x1, signed int y1, signed int y2, unsigned colour);\nvoid draw_H_line(signed int x1, signed int x2, signed int y1, unsigned colour);\nvoid draw_triangle(signed int x1, signed int y1, signed int x2, signed int y2, signed int x3, signed int y3, unsigned char fill, unsigned int colour);\nvoid draw_rectangle(signed int x1, signed int y1, signed int x2, signed int y2, unsigned char fill, unsigned char colour, unsigned char type);\nvoid draw_rectangle(signed int x1, signed int y1, signed int x2, signed int y2, unsigned char fill, unsigned char colour, unsigned char type);\nvoid draw_circle(signed int xc, signed int yc, signed int radius, unsigned char fill, unsigned char colour);<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>SSD1306.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"SSD1306.h\"\n\nstatic const unsigned char font_regular[92][6] =\n{\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   \/\/ sp\n    0x00, 0x00, 0x00, 0x2f, 0x00, 0x00,   \/\/ !\n    0x00, 0x00, 0x07, 0x00, 0x07, 0x00,   \/\/ \"\n    0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14,   \/\/ #\n    0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12,   \/\/ $\n    0x00, 0x62, 0x64, 0x08, 0x13, 0x23,   \/\/ %\n    0x00, 0x36, 0x49, 0x55, 0x22, 0x50,   \/\/ &amp;\n    0x00, 0x00, 0x05, 0x03, 0x00, 0x00,   \/\/ '\n    0x00, 0x00, 0x1c, 0x22, 0x41, 0x00,   \/\/ (\n    0x00, 0x00, 0x41, 0x22, 0x1c, 0x00,   \/\/ )\n    0x00, 0x14, 0x08, 0x3E, 0x08, 0x14,   \/\/ *\n    0x00, 0x08, 0x08, 0x3E, 0x08, 0x08,   \/\/ +\n    0x00, 0x00, 0x00, 0xA0, 0x60, 0x00,   \/\/ ,\n    0x00, 0x08, 0x08, 0x08, 0x08, 0x08,   \/\/ -\n    0x00, 0x00, 0x60, 0x60, 0x00, 0x00,   \/\/ .\n    0x00, 0x20, 0x10, 0x08, 0x04, 0x02,   \/\/ \/\n    0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E,   \/\/ 0\n    0x00, 0x00, 0x42, 0x7F, 0x40, 0x00,   \/\/ 1\n    0x00, 0x42, 0x61, 0x51, 0x49, 0x46,   \/\/ 2\n    0x00, 0x21, 0x41, 0x45, 0x4B, 0x31,   \/\/ 3\n    0x00, 0x18, 0x14, 0x12, 0x7F, 0x10,   \/\/ 4\n    0x00, 0x27, 0x45, 0x45, 0x45, 0x39,   \/\/ 5\n    0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30,   \/\/ 6\n    0x00, 0x01, 0x71, 0x09, 0x05, 0x03,   \/\/ 7\n    0x00, 0x36, 0x49, 0x49, 0x49, 0x36,   \/\/ 8\n    0x00, 0x06, 0x49, 0x49, 0x29, 0x1E,   \/\/ 9\n    0x00, 0x00, 0x36, 0x36, 0x00, 0x00,   \/\/ :\n    0x00, 0x00, 0x56, 0x36, 0x00, 0x00,   \/\/ ;\n    0x00, 0x08, 0x14, 0x22, 0x41, 0x00,   \/\/ \n    0x00, 0x02, 0x01, 0x51, 0x09, 0x06,   \/\/ ?\n    0x00, 0x32, 0x49, 0x59, 0x51, 0x3E,   \/\/ @\n    0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C,   \/\/ A\n    0x00, 0x7F, 0x49, 0x49, 0x49, 0x36,   \/\/ B\n    0x00, 0x3E, 0x41, 0x41, 0x41, 0x22,   \/\/ C\n    0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C,   \/\/ D\n    0x00, 0x7F, 0x49, 0x49, 0x49, 0x41,   \/\/ E\n    0x00, 0x7F, 0x09, 0x09, 0x09, 0x01,   \/\/ F\n    0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A,   \/\/ G\n    0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F,   \/\/ H\n    0x00, 0x00, 0x41, 0x7F, 0x41, 0x00,   \/\/ I\n    0x00, 0x20, 0x40, 0x41, 0x3F, 0x01,   \/\/ J\n    0x00, 0x7F, 0x08, 0x14, 0x22, 0x41,   \/\/ K\n    0x00, 0x7F, 0x40, 0x40, 0x40, 0x40,   \/\/ L\n    0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F,   \/\/ M\n    0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F,   \/\/ N\n    0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E,   \/\/ O\n    0x00, 0x7F, 0x09, 0x09, 0x09, 0x06,   \/\/ P\n    0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E,   \/\/ Q\n    0x00, 0x7F, 0x09, 0x19, 0x29, 0x46,   \/\/ R\n    0x00, 0x46, 0x49, 0x49, 0x49, 0x31,   \/\/ S\n    0x00, 0x01, 0x01, 0x7F, 0x01, 0x01,   \/\/ T\n    0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F,   \/\/ U\n    0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F,   \/\/ V\n    0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F,   \/\/ W\n    0x00, 0x63, 0x14, 0x08, 0x14, 0x63,   \/\/ X\n    0x00, 0x07, 0x08, 0x70, 0x08, 0x07,   \/\/ Y\n    0x00, 0x61, 0x51, 0x49, 0x45, 0x43,   \/\/ Z\n    0x00, 0x00, 0x7F, 0x41, 0x41, 0x00,   \/\/ [\n    0x00, 0x02, 0x04, 0x08, 0x10, 0x20,   \/\/ \\92\n    0x00, 0x00, 0x41, 0x41, 0x7F, 0x00,   \/\/ ]\n    0x00, 0x04, 0x02, 0x01, 0x02, 0x04,   \/\/ ^\n    0x00, 0x40, 0x40, 0x40, 0x40, 0x40,   \/\/ _\n    0x00, 0x00, 0x01, 0x02, 0x04, 0x00,   \/\/ '\n    0x00, 0x20, 0x54, 0x54, 0x54, 0x78,   \/\/ a\n    0x00, 0x7F, 0x48, 0x44, 0x44, 0x38,   \/\/ b\n    0x00, 0x38, 0x44, 0x44, 0x44, 0x20,   \/\/ c\n    0x00, 0x38, 0x44, 0x44, 0x48, 0x7F,   \/\/ d\n    0x00, 0x38, 0x54, 0x54, 0x54, 0x18,   \/\/ e\n    0x00, 0x08, 0x7E, 0x09, 0x01, 0x02,   \/\/ f\n    0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C,   \/\/ g\n    0x00, 0x7F, 0x08, 0x04, 0x04, 0x78,   \/\/ h\n    0x00, 0x00, 0x44, 0x7D, 0x40, 0x00,   \/\/ i\n    0x00, 0x40, 0x80, 0x84, 0x7D, 0x00,   \/\/ j\n    0x00, 0x7F, 0x10, 0x28, 0x44, 0x00,   \/\/ k\n    0x00, 0x00, 0x41, 0x7F, 0x40, 0x00,   \/\/ l\n    0x00, 0x7C, 0x04, 0x18, 0x04, 0x78,   \/\/ m\n    0x00, 0x7C, 0x08, 0x04, 0x04, 0x78,   \/\/ n\n    0x00, 0x38, 0x44, 0x44, 0x44, 0x38,   \/\/ o\n    0x00, 0xFC, 0x24, 0x24, 0x24, 0x18,   \/\/ p\n    0x00, 0x18, 0x24, 0x24, 0x18, 0xFC,   \/\/ q\n    0x00, 0x7C, 0x08, 0x04, 0x04, 0x08,   \/\/ r\n    0x00, 0x48, 0x54, 0x54, 0x54, 0x20,   \/\/ s\n    0x00, 0x04, 0x3F, 0x44, 0x40, 0x20,   \/\/ t\n    0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C,   \/\/ u\n    0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C,   \/\/ v\n    0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C,   \/\/ w\n    0x00, 0x44, 0x28, 0x10, 0x28, 0x44,   \/\/ x\n    0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C,   \/\/ y\n    0x00, 0x44, 0x64, 0x54, 0x4C, 0x44,   \/\/ z\n    0x14, 0x14, 0x14, 0x14, 0x14, 0x14    \/\/ horiz lines\n};\n\nstatic const unsigned char Number_Font[11][6] =\n{\n   0x00, 0x7F, 0x41, 0x41, 0x41, 0x7F, \/\/0\n   0x00, 0x00, 0x00, 0x41, 0x7F, 0x40, \/\/1\n   0x00, 0x79, 0x49, 0x49, 0x49, 0x4F, \/\/2\n   0x00, 0x41, 0x49, 0x49, 0x49, 0x7F, \/\/3\n   0x00, 0x0F, 0x08, 0x08, 0x08, 0x7F, \/\/4\n   0x00, 0x4F, 0x49, 0x49, 0x49, 0x79, \/\/5\n   0x00, 0x7F, 0x48, 0x48, 0x48, 0x78, \/\/6\n   0x00, 0x00, 0x01, 0x01, 0x01, 0x7F, \/\/7\n   0x00, 0x7F, 0x49, 0x49, 0x49, 0x7F, \/\/8\n   0x00, 0x0F, 0x09, 0x09, 0x09, 0x7F, \/\/9\n   0x00, 0x00, 0x00, 0x00, 0x00, 0x00  \/\/spc\n};\n\nvoid swap(signed int *a, signed int *b)\n{\n    signed int temp = 0x0000;\n\n    temp = *b;\n    *b = *a;\n    *a = temp;\n}\n\nvoid I2C_DIO_init(void)\n{\n    GPIO_setAsPeripheralModuleFunctionOutputPin(I2C_port, (I2C_SDA_pin | I2C_SCL_pin));\n}\n\nvoid USCI_I2C_init(void)\n{\n    USCI_B_I2C_initMasterParam I2C_param = {0};\n\n    I2C_DIO_init();\n\n    I2C_param.selectClockSource = USCI_B_I2C_CLOCKSOURCE_SMCLK;\n    I2C_param.i2cClk = UCS_getSMCLK();\n    I2C_param.dataRate = USCI_B_I2C_SET_DATA_RATE_400KBPS;\n\n    USCI_B_I2C_initMaster(USCI_B0_BASE, &amp;I2C_param);\n\n    USCI_B_I2C_enable(USCI_B0_BASE);\n}\n\nvoid OLED_init(void)\n{\n     USCI_I2C_init();\n     delay_ms(100);\n\n     OLED_write((Set_Display_ON_or_OFF_CMD | Display_OFF), CMD);\n     OLED_write(Set_Multiplex_Ratio_CMD, CMD);\n     OLED_write(0x1F, CMD);\n     OLED_write(Set_Display_Offset_CMD, CMD);\n     OLED_write(0x00, CMD);\n     OLED_write(Set_Display_Start_Line_CMD, CMD);\n     OLED_write((Set_Segment_Remap_CMD | Column_Address_0_Mapped_to_SEG127), CMD);\n     OLED_write((Set_COM_Output_Scan_Direction_CMD | Scan_from_COM63_to_0), CMD);\n     OLED_write(Set_Common_HW_Config_CMD, CMD);\n     OLED_write(0x02, CMD);\n     OLED_write(Set_Contrast_Control_CMD, CMD);\n     OLED_write(0x8F, CMD);\n     OLED_write(Set_Entire_Display_ON_CMD, CMD);\n     OLED_write(Set_Normal_or_Inverse_Display_CMD, CMD);\n     OLED_write(Set_Display_Clock_CMD, CMD);\n     OLED_write(0x80, CMD);\n     OLED_write(Set_Pre_charge_Period_CMD, CMD);\n     OLED_write(0x25, CMD);\n     OLED_write(Set_VCOMH_Level_CMD, CMD);\n     OLED_write(0x20, CMD);\n     OLED_write(Set_Page_Address_CMD, CMD);\n     OLED_write(0x00, CMD);\n     OLED_write(0x03, CMD);\n     OLED_write(Set_Page_Start_Address_CMD , CMD);\n     OLED_write(Set_Higher_Column_Start_Address_CMD, CMD);\n     OLED_write(Set_Lower_Column_Start_Address_CMD, CMD);\n     OLED_write(Set_Memory_Addressing_Mode_CMD, CMD);\n     OLED_write(0x02, CMD);\n     OLED_write(Set_Charge_Pump_CMD, CMD);\n     OLED_write(0x14, CMD);\n     OLED_write((Set_Display_ON_or_OFF_CMD | Display_ON), CMD);\n\n     delay_ms(100);\n\n     OLED_clear_buffer();\n     OLED_clear_screen();\n}\n\nvoid OLED_write(unsigned char value, unsigned char control_byte)\n{\n    USCI_B_I2C_setSlaveAddress(USCI_B0_BASE, SSD1306_I2C_Address);\n    USCI_B_I2C_setMode(USCI_B0_BASE, USCI_B_I2C_TRANSMIT_MODE);\n\n    USCI_B_I2C_masterSendMultiByteStart(USCI_B0_BASE, control_byte);\n    while(!USCI_B_I2C_masterIsStartSent(USCI_B0_BASE));\n    USCI_B_I2C_masterSendMultiByteFinish(USCI_B0_BASE, value);\n\n    while(USCI_B_I2C_isBusBusy(USCI_B0_BASE));\n}\n\nvoid OLED_gotoxy(unsigned char x_pos, unsigned char y_pos)\n{\n     OLED_write((Set_Page_Start_Address_CMD + y_pos), CMD);\n     OLED_write(((x_pos &amp; 0x0F) | Set_Lower_Column_Start_Address_CMD), CMD);\n     OLED_write((((x_pos &amp; 0xF0) &gt;&gt; 0x04) | Set_Higher_Column_Start_Address_CMD), CMD);\n}\n\nvoid OLED_fill(unsigned char bmp_data)\n{\n    unsigned char x_pos = 0x00;\n    unsigned char page = 0x00;\n\n    for(page = 0; page &lt; y_max; page++)\n    {\n        OLED_gotoxy(x_min, page);\n        \n        USCI_B_I2C_setSlaveAddress(USCI_B0_BASE, SSD1306_I2C_Address);\n        USCI_B_I2C_setMode(USCI_B0_BASE, USCI_B_I2C_TRANSMIT_MODE);\n\n        USCI_B_I2C_masterSendMultiByteStart(USCI_B0_BASE, DAT);\n        while(!USCI_B_I2C_masterIsStartSent(USCI_B0_BASE));\n        \n        for(x_pos = x_min; x_pos &lt; x_max; x_pos++)\n        {\n            USCI_B_I2C_masterSendMultiByteNext(USCI_B0_BASE, bmp_data);\n        }\n        \n        USCI_B_I2C_masterSendMultiByteStop(USCI_B0_BASE);\n\n        while(USCI_B_I2C_isBusBusy(USCI_B0_BASE));\n    }\n}\n\nvoid OLED_clear_screen()\n{\n    OLED_fill(0x00);\n}\n\nvoid OLED_clear_buffer()\n{\n     unsigned int s = 0x0000;\n\n     for(s = 0; s &lt; buffer_size; s++)\n     {\n          buffer[s] = 0x00;\n     }\n}\n\nvoid OLED_cursor(unsigned char x_pos, unsigned char y_pos)\n{\n    unsigned char s = 0x00;\n\n    if(y_pos != 0x00)\n    {\n        if(x_pos == 1)\n        {\n            OLED_gotoxy(0x00, (y_pos + 0x02));\n        }\n        else\n        {\n            OLED_gotoxy((0x50 + ((x_pos - 0x02) * 0x06)), (y_pos + 0x02));\n        }\n\n        for(s = 0x00; s &lt; 0x06; s++)\n        {\n            OLED_write(0xFF, DAT);\n        }\n    }\n}\n\nvoid draw_bitmap(unsigned char xb, unsigned char yb, unsigned char xe, unsigned char ye, unsigned char *bmp_img)\n{\n    unsigned int s = 0x0000;\n    unsigned char x_pos = 0x00;\n    unsigned char y_pos = 0x00;\n\n    for(y_pos = yb; y_pos &lt;= ye; y_pos++)\n    {\n        OLED_gotoxy(xb, y_pos);\n        for(x_pos = xb; x_pos = 48) &amp;&amp; (ch  (x_max - 0x06))\n    {\n        x_pos = 0x00;\n        y_pos++;\n    }\n    OLED_gotoxy(x_pos, y_pos);\n\n    for(s = 0x00; s = 0x20) &amp;&amp; (ch[s] &lt;= 0x7F));\n}\n\nvoid print_chr(unsigned char x_pos, unsigned char y_pos, unsigned char num_reg_state, signed int value)\n{\n    unsigned char ch = 0x00;\n\n    if(value = 100) &amp;&amp; (value = 10) &amp;&amp; (value = 0) &amp;&amp; (value &lt; 10))\n     {\n         ch = (value % 10);\n         print_char((x_pos + 6), y_pos, num_reg_state, (48 + ch));\n         print_char((x_pos + 12), y_pos, num_reg_state, 0x20);\n         print_char((x_pos + 18), y_pos, num_reg_state, 0x20);\n     }\n}\n\nvoid print_int(unsigned char x_pos, unsigned char y_pos, unsigned char num_reg_state, signed long value)\n{\n    unsigned char ch = 0x00;\n\n    if(value = 10000) &amp;&amp; ((value = 1000) &amp;&amp; (value = 100) &amp;&amp; (value = 10) &amp;&amp; (value = 0) &amp;&amp; (value  1)\n    {\n        ch = ((value % 1000) \/ 100);\n        print_char((x_pos + 12), y_pos, num_reg_state, (48 + ch));\n\n        if(points &gt; 2)\n        {\n            ch = ((value % 100) \/ 10);\n            print_char((x_pos + 18), y_pos, num_reg_state, (48 + ch));\n\n            if(points &gt; 3)\n            {\n                ch = (value % 10);\n                print_char((x_pos + 24), y_pos, num_reg_state, (48 + ch));\n            }\n        }\n    }\n}\n\nvoid print_float(unsigned char x_pos, unsigned char y_pos, unsigned char num_reg_state, float value, unsigned char points)\n{\n    signed long tmp = 0x00;\n\n    tmp = value;\n    print_int(x_pos, y_pos, num_reg_state, tmp);\n    tmp = ((value - tmp) * 10000);\n\n    if(tmp = 10000) &amp;&amp; (value = 1000) &amp;&amp; (value = 100) &amp;&amp; (value = 10) &amp;&amp; (value &lt; 100))\n    {\n        print_decimal((x_pos + 18), y_pos, num_reg_state, tmp, points);\n    }\n    else if(value &lt; 10)\n    {\n        print_decimal((x_pos + 12), y_pos, num_reg_state, tmp, points);\n        if((value) &lt; 0)\n        {\n            print_char(x_pos, y_pos, CHR, &#039;-&#039;);\n        }\n        else\n        {\n            print_char(x_pos, y_pos, CHR, &#039; &#039;);\n        }\n    }\n}\n\nvoid draw_pixel(unsigned char x_pos, unsigned char y_pos, unsigned char colour)\n{\n    unsigned char value = 0x00;\n    unsigned char page = 0x00;\n    unsigned char bit_pos = 0x00;\n\n    page = (y_pos \/ y_max);\n    bit_pos = (y_pos - (page * y_max));\n    value = buffer[((page * x_max) + x_pos)];\n\n    if((colour &amp; YES) != NO)\n    {\n        value |= (1 &lt;&lt; bit_pos);\n    }\n    else\n    {\n        value &amp;= (~(1 &lt;&lt; bit_pos));\n    }\n\n    buffer[((page * x_max) + x_pos)] = value;\n    OLED_gotoxy(x_pos, page);\n    OLED_write(value, DAT);\n}\n\nvoid draw_line(signed int x1, signed int y1, signed int x2, signed int y2, unsigned char colour)\n{\n    signed int dx = 0x0000;\n    signed int dy = 0x0000;\n    signed int stepx = 0x0000;\n    signed int stepy = 0x0000;\n    signed int fraction = 0x0000;\n\n    dy = (y2 - y1);\n    dx = (x2 - x1);\n\n    if (dy &lt; 0)\n    {\n        dy = -dy;\n        stepy = -1;\n    }\n    else\n    {\n        stepy = 1;\n    }\n\n    if (dx &lt; 0)\n    {\n        dx = -dx;\n        stepx = -1;\n    }\n    else\n    {\n        stepx = 1;\n    }\n\n    dx &lt;&lt;= 1;\n    dy &lt; dy)\n    {\n        fraction = (dy - (dx &gt;&gt; 1));\n        while (x1 != x2)\n        {\n            if(fraction &gt;= 0)\n            {\n                y1 += stepy;\n                fraction -= dx;\n            }\n\n            x1 += stepx;\n            fraction += dy;\n\n            draw_pixel(x1, y1, colour);\n        }\n    }\n    else\n    {\n        fraction = (dx - (dy &gt;&gt; 1));\n        while (y1 != y2)\n        {\n            if (fraction &gt;= 0)\n            {\n                x1 += stepx;\n                fraction -= dy;\n            }\n\n            y1 += stepy;\n            fraction += dx;\n\n            draw_pixel(x1, y1, colour);\n        }\n    }\n}\n\nvoid draw_V_line(signed int x1, signed int y1, signed int y2, unsigned colour)\n{\n    if(y1 &gt; y2)\n    {\n       swap(&amp;y1, &amp;y2);\n    }\n\n    while(y2 &gt; (y1 - 1))\n    {\n        draw_pixel(x1, y2, colour);\n        y2--;\n    }\n}\n\nvoid draw_H_line(signed int x1, signed int x2, signed int y1, unsigned colour)\n{\n    if(x1 &gt; x2)\n    {\n       swap(&amp;x1, &amp;x2);\n    }\n\n    while(x2 &gt; (x1 - 1))\n    {\n        draw_pixel(x2, y1, colour);\n        x2--;\n    }\n}\n\nvoid draw_triangle(signed int x1, signed int y1, signed int x2, signed int y2, signed int x3, signed int y3, unsigned char fill, unsigned int colour)\n{\n    signed int a = 0;\n    signed int b = 0;\n    signed int sa = 0;\n    signed int sb = 0;\n    signed int yp = 0;\n    signed int last = 0;\n    signed int dx12 = 0;\n    signed int dx23 = 0;\n    signed int dx13 = 0;\n    signed int dy12 = 0;\n    signed int dy23 = 0;\n    signed int dy13 = 0;\n\n    switch(fill)\n    {\n        case YES:\n        {\n            if(y1 &gt; y2)\n            {\n                swap(&amp;y1, &amp;y2);\n                swap(&amp;x1, &amp;x2);\n            }\n            if(y2 &gt; y3)\n            {\n                swap(&amp;y3, &amp;y2);\n                swap(&amp;x3, &amp;x2);\n            }\n            if(y1 &gt; y2)\n            {\n                swap(&amp;y1, &amp;y2);\n                swap(&amp;x1, &amp;x2);\n            }\n\n            if(y1 == y3)\n            {\n                a = b = x1;\n\n                if(x2 <a> b)\n                {\n                    b = x2;\n                }\n                if(x2 <a> b)\n                {\n                    b = x3;\n                }\n\n                draw_H_line(a, (a + (b - (a + 1))), y1, colour);\n                return;\n            }\n\n            dx12 = (x2 - x1);\n            dy12 = (y2 - y1);\n            dx13 = (x3 - x1);\n            dy13 = (y3 - y1);\n            dx23 = (x3 - x2);\n            dy23 = (y3 - y2);\n            sa = 0,\n            sb = 0;\n\n            if(y2 == y3)\n            {\n                last = y2;\n            }\n            else\n            {\n                last = (y2 - 1);\n            }\n\n            for(yp = y1; yp  b)\n                {\n                    swap(&amp;a, &amp;b);\n                }\n                draw_H_line(a, (a + (b - (a + 1))), yp, colour);\n            }\n\n            sa = (dx23 * (yp - y2));\n            sb = (dx13 * (yp - y1));\n            for(; yp  b)\n                {\n                    swap(&amp;a, &amp;b);\n                }\n                draw_H_line(a, (a + (b - (a + 1))), yp, colour);\n            }\n\n            break;\n        }\n        default:\n        {\n            draw_line(x1, y1, x2, y2, colour);\n            draw_line(x2, y2, x3, y3, colour);\n            draw_line(x3, y3, x1, y1, colour);\n            break;\n        }\n    }\n}\n\nvoid draw_rectangle(signed int x1, signed int y1, signed int x2, signed int y2, unsigned char fill, unsigned char colour, unsigned char type)\n{\n     unsigned short i = 0x00;\n     unsigned short xmin = 0x00;\n     unsigned short xmax = 0x00;\n     unsigned short ymin = 0x00;\n     unsigned short ymax = 0x00;\n\n     if(fill != NO)\n     {\n        if(x1 &lt; x2)\n        {\n           xmin = x1;\n           xmax = x2;\n        }\n        else\n        {\n           xmin = x2;\n           xmax = x1;\n        }\n\n        if(y1 &lt; y2)\n        {\n           ymin = y1;\n           ymax = y2;\n        }\n        else\n        {\n           ymin = y2;\n           ymax = y1;\n        }\n\n        for(; xmin &lt;= xmax; ++xmin)\n        {\n           for(i = ymin; i &lt;= ymax; ++i)\n           {\n               draw_pixel(xmin, i, colour);\n           }\n         }\n     }\n\n     else\n     {\n        draw_line(x1, y1, x2, y1, colour);\n        draw_line(x1, y2, x2, y2, colour);\n        draw_line(x1, y1, x1, y2, colour);\n        draw_line(x2, y1, x2, y2, colour);\n     }\n\n     if(type != SQUARE)\n     {\n         draw_pixel(x1, y1, ~colour);\n         draw_pixel(x1, y2, ~colour);\n         draw_pixel(x2, y1, ~colour);\n         draw_pixel(x2, y2, ~colour);\n     }\n}\n\nvoid draw_circle(signed int xc, signed int yc, signed int radius, unsigned char fill, unsigned char colour)\n{\n   signed int a = 0x0000;\n   signed int b = 0x0000;\n   signed int P = 0x0000;\n\n   b = radius;\n   P = (1 - b);\n\n   do\n   {\n        if(fill != NO)\n        {\n           draw_line((xc - a), (yc + b), (xc + a), (yc + b), colour);\n           draw_line((xc - a), (yc - b), (xc + a), (yc - b), colour);\n           draw_line((xc - b), (yc + a), (xc + b), (yc + a), colour);\n           draw_line((xc - b), (yc - a), (xc + b), (yc - a), colour);\n        }\n        else\n        {\n           draw_pixel((xc + a), (yc + b), colour);\n           draw_pixel((xc + b), (yc + a), colour);\n           draw_pixel((xc - a), (yc + b), colour);\n           draw_pixel((xc - b), (yc + a), colour);\n           draw_pixel((xc + b), (yc - a), colour);\n           draw_pixel((xc + a), (yc - b), colour);\n           draw_pixel((xc - a), (yc - b), colour);\n           draw_pixel((xc - b), (yc - a), colour);\n        }\n\n        if(P &lt; 0)\n        {\n           P += (3 + (2 * a++));\n        }\n        else\n        {\n           P += (5 + (2 * ((a++) - (b--))));\n        }\n    }while(a &lt;= b);\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>main.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"SSD1306.h\"\n#include \"MAX6675.h\"\n\nextern unsigned char buffer[buffer_size];\n\nvoid clock_init(void);\n\nvoid main(void)\n{\n    float t = 0;\n    unsigned int ti = 0;\n\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n    OLED_init();\n    MAX6675_init();\n\n    while(1)\n    {\n        MAX6675_get_ADC(&amp;ti);\n        t = MAX6675_get_T(ti, deg_C);\n\n        print_float(40, 10, NUM, t, 1);\n\n        delay_ms(400);\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_FLLREF, UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initFLLSettle(MCLK_KHZ, MCLK_FLLREF_RATIO);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"904\" height=\"894\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI2.png\" alt=\"\" class=\"wp-image-14681\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI2.png 904w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI2-580x574.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI2-768x760.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI2-90x90.png 90w\" sizes=\"auto, (max-width: 904px) 100vw, 904px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">I won\u2019t be going through hardware initialization and other common stuffs that have been covered earlier.&nbsp; The focus here is toward the SPI read operation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the <em>MAX6675_get_ADC<\/em> function, the SPI read operation can be seen. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">CS_pin_low();\n            \nUSCI_A_SPI_transmitData(USCI_A0_BASE, 0x00);\nwhile(USCI_A_SPI_isBusy(USCI_A0_BASE));\nhb = USCI_A_SPI_receiveData(USCI_A0_BASE);\nwhile(USCI_A_SPI_isBusy(USCI_A0_BASE));\n\nUSCI_B_SPI_transmitData(USCI_A0_BASE, 0x00);\nwhile(USCI_A_SPI_isBusy(USCI_A0_BASE));\nlb = USCI_A_SPI_receiveData(USCI_A0_BASE);\nwhile(USCI_A_SPI_isBusy(USCI_A0_BASE));\n\nCS_pin_high();<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Although no SPI write operation is possible for MAX6675 due absence\nof slave-in pin in it, 0s are written prior to every SPI bus read. It is not\nmandatory write 0s and we can use any other value since it has no real use\nother than SPI clock generation. This is so because SPI bus is like a ring\nbuffer. In SPI bus, data is simultaneously read and written with SPI clock\npulses. After every complete transfer, the SPI bus is polled to check if it is\nfree. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The demo here reads temperature with a thermocouple connected to a MAX6675 and displays the read temperature on a SSD1306 OLED display every 400 ms.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"823\" height=\"1024\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI-EX2-823x1024.jpg\" alt=\"\" class=\"wp-image-14682\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI-EX2-823x1024.jpg 823w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI-EX2-522x650.jpg 522w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI-EX2-768x956.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI-EX2.jpg 1369w\" sizes=\"auto, (max-width: 823px) 100vw, 823px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/jsL-HjWkYGA?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">USCI \u2013 SPI \u2013 I2C Example 3<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Two examples SPI-I2C would have been enough but went for this final third one because sometimes it is difficult for grasping I2C\/SPI operations with driverlib alone. This is especially the case when people are migrating from low-end or mid-range MSP430s that have no driverlib support and this is what happened with me at the beginning. It was then I decided what if I can use the good old I2C and SPI libraries that TI supplied for their low and mid-range devices. This example demonstrates exactly that. Here both the SPI and I2C hardware of MSP430F5529 were tested against the older libraries. These libraries do not apply the use of driverlib APIs except for pin declarations. I would also like readers to check my past SPI and I2C tutorials on MSP430G2xxx series for better reference and understanding. Here\u2019s the link: <a href=\"http:\/\/embedded-lab.com\/blog\/more-on-ti-msp430s\/\">http:\/\/embedded-lab.com\/blog\/more-on-ti-msp430s<\/a> for those tutorials. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Note that unlike MSP430G2xxx devices, MSP430F5529\ndoesn\u2019t have any USI hardware and instead of it we will have to stick to USCI\nmodules &#8211; USCI_B modules for I2C and USCI_A or USCI_B modules for SPI communications.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If still things are still messy with USCI, we can use\nsoftware-based I2C\/SPI libraries but those won\u2019t perform like the\nhardware-based USCI ones. In terms of communication speed, software-based\nI2C\/SPI are slow and in terms of coding, software-based solutions are\nresource-consuming. Thus, it is best to learn and use USCI modules.&nbsp; <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here in this demo, an I2C-based BH1750 light sensor is read and its readings are displayed on a SPI-based Nokia GLCD (PCD8544).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>USCI_I2C.h<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include&lt;msp430.h&gt;  #include \"driverlib.h\" #define USCI_B0_I2C_port                                  GPIO_PORT_P3 #define USCI_B0_I2C_SDA_pin                               GPIO_PIN0 #define USCI_B0_I2C_SCL_pin                               GPIO_PIN1 #define USCI_B1_I2C_port                                  GPIO_PORT_P4 #define USCI_B1_I2C_SDA_pin                               GPIO_PIN1 #define USCI_B1_I2C_SCL_pin                               GPIO_PIN2 void I2C_USCI_B0_init(unsigned char address); void I2C_USCI_B0_set_address(unsigned char address); unsigned char I2C_USCI_B0_read_byte(unsigned char address); unsigned char I2C_USCI_B0_read_word(unsigned char address,unsigned char *value, unsigned char length); unsigned char I2C_USCI_B0_write_byte(unsigned char address, unsigned char value); void I2C_USCI_B1_init(unsigned char address); void I2C_USCI_B1_set_address(unsigned char address); unsigned char I2C_USCI_B1_read_byte(unsigned char address); unsigned char I2C_USCI_B1_read_word(unsigned char address,unsigned char *value, unsigned char length); unsigned char I2C_USCI_B1_write_byte(unsigned char address, unsigned char value);<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>USCI_I2C.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"USCI_I2C.h\"\n\nvoid I2C_USCI_B0_init(unsigned char address)\n{\n    GPIO_setAsPeripheralModuleFunctionOutputPin(USCI_B0_I2C_port, \n                                                (USCI_B0_I2C_SDA_pin \n                                                | USCI_B0_I2C_SCL_pin));\n    \n    UCB0CTL1 |= UCSWRST;\n    UCB0CTL0 = (UCMST | UCMODE_3 | UCSYNC);\n    UCB0CTL1 = (UCSSEL_2 | UCSWRST);\n    UCB0BR0 = 50;\n    UCB0I2CSA = address;\n    UCB0CTL1 &amp;= ~UCSWRST;\n}\n\nvoid I2C_USCI_B0_set_address(unsigned char address)\n{\n    UCB0CTL1 |= UCSWRST;\n    UCB0I2CSA = address;\n    UCB0CTL1 &amp;= ~UCSWRST;\n}\n\nunsigned char I2C_USCI_B0_read_byte(unsigned char address)\n{\n    while(UCB0CTL1 &amp; UCTXSTP);\n    UCB0CTL1 |= (UCTR | UCTXSTT);\n\n    while(!(UCB0IFG &amp; UCTXIFG));\n    UCB0TXBUF = address;\n\n    while(!(UCB0IFG &amp; UCTXIFG));\n    UCB0CTL1 &amp;= ~UCTR;\n    UCB0CTL1 |= UCTXSTT;\n    UCB0IFG &amp;= ~UCTXIFG;\n\n    while(UCB0CTL1 &amp; UCTXSTT);\n    UCB0CTL1 |= UCTXSTP;\n\n    return UCB0RXBUF;\n}\n\nunsigned char I2C_USCI_B0_read_word(unsigned char address,unsigned char *value, unsigned char length)\n{\n    unsigned char i = 0;\n\n    while(UCB0CTL1 &amp; UCTXSTP);\n\n    UCB0CTL1 |= (UCTR | UCTXSTT);\n\n    while(!(UCB0IFG &amp; UCTXIFG));\n    \n    UCB0IFG &amp;= ~UCTXIFG;\n    \n    if(UCB0IFG &amp; UCNACKIFG)\n    {\n        return UCB0STAT;\n    }\n\n    UCB0TXBUF = address;\n\n    while(!(UCB0IFG &amp; UCTXIFG));\n    \n    if(UCB0IFG &amp; UCNACKIFG)\n    {\n        return UCB0STAT;\n    }\n\n    UCB0CTL1 &amp;= ~UCTR;\n    UCB0CTL1 |= UCTXSTT;\n    UCB0IFG &amp;= ~UCTXIFG;\n    \n    while(UCB0CTL1 &amp; UCTXSTT);\n\n    do\n    {\n        while (!(UCB0IFG &amp; UCRXIFG));\n        UCB0IFG &amp;= ~UCTXIFG;\n        value[i] = UCB0RXBUF;\n        i++;\n    }while(i &lt; (length - 1));\n\n    while (!(UCB0IFG &amp; UCRXIFG));\n\n    UCB0IFG &amp;= ~UCTXIFG;\n    UCB0CTL1 |= UCTXSTP;\n    value[length - 1] = UCB0RXBUF;\n    UCB0IFG &amp;= ~UCTXIFG;\n\n    return 0;\n}\n\nunsigned char I2C_USCI_B0_write_byte(unsigned char address, unsigned char value)\n{\n    while(UCB0CTL1 &amp; UCTXSTP);\n\n    UCB0CTL1 |= (UCTR | UCTXSTT);\n\n    while(!(UCB0IFG &amp; UCTXIFG));\n    \n    if(UCB0IFG &amp; UCNACKIFG)\n    {\n        return UCB0STAT;\n    }\n\n    UCB0TXBUF = address;\n\n    while(!(UCB0IFG &amp; UCTXIFG));\n\n    if(UCB0IFG &amp; UCNACKIFG)\n    {\n        return UCB0STAT;\n    }\n\n    UCB0TXBUF = value;\n\n    while(!(UCB0IFG &amp; UCTXIFG));\n\n    if(UCB0IFG &amp; UCNACKIFG)\n    {\n        return UCB0STAT;\n    }\n\n    UCB0CTL1 |= UCTXSTP;\n    UCB0IFG &amp;= ~UCTXIFG;\n\n    return 0;\n}\n\nvoid I2C_USCI_B1_init(unsigned char address)\n{\n    GPIO_setAsPeripheralModuleFunctionOutputPin(USCI_B1_I2C_port, \n                                                (USCI_B1_I2C_SDA_pin \n                                                | USCI_B1_I2C_SCL_pin));\n\n    UCB1CTL1 |= UCSWRST;\n    UCB1CTL0 = (UCMST | UCMODE_3 | UCSYNC);\n    UCB1CTL1 = (UCSSEL_2 | UCSWRST);\n    UCB1BR0 = 10;\n    UCB1I2CSA = address;\n    UCB1CTL1 &amp;= ~UCSWRST;\n}\n\nvoid I2C_USCI_B1_set_address(unsigned char address)\n{\n    UCB1CTL1 |= UCSWRST;\n    UCB1I2CSA = address;\n    UCB1CTL1 &amp;= ~UCSWRST;\n}\n\nunsigned char I2C_USCI_B1_read_byte(unsigned char address)\n{\n    while(UCB1CTL1 &amp; UCTXSTP);\n    UCB1CTL1 |= (UCTR | UCTXSTT);\n\n    while(!(UCB1IFG &amp; UCTXIFG));\n    UCB1TXBUF = address;\n\n    while(!(UCB1IFG &amp; UCTXIFG));\n    UCB1CTL1 &amp;= ~UCTR;\n    UCB1CTL1 |= UCTXSTT;\n    UCB1IFG &amp;= ~UCTXIFG;\n\n    while(UCB1CTL1 &amp; UCTXSTT);\n    UCB1CTL1 |= UCTXSTP;\n\n    return UCB1RXBUF;\n}\n\nunsigned char I2C_USCI_B1_read_word(unsigned char address,unsigned char *value, unsigned char length)\n{\n    unsigned char i = 0;\n\n    while(UCB1CTL1 &amp; UCTXSTP);\n\n    UCB1CTL1 |= (UCTR | UCTXSTT);\n\n    while(!(UCB1IFG &amp; UCTXIFG));\n\n    UCB1IFG &amp;= ~UCTXIFG;\n\n    if(UCB1IFG &amp; UCNACKIFG)\n    {\n        return UCB1STAT;\n    }\n\n    UCB1TXBUF = address;\n\n    while(!(UCB1IFG &amp; UCTXIFG));\n\n    if(UCB1IFG &amp; UCNACKIFG)\n    {\n        return UCB1STAT;\n    }\n\n    UCB1CTL1 &amp;= ~UCTR;\n    UCB1CTL1 |= UCTXSTT;\n    UCB1IFG &amp;= ~UCTXIFG;\n\n    while(UCB1CTL1 &amp; UCTXSTT);\n\n    do\n    {\n        while (!(UCB1IFG &amp; UCRXIFG));\n        UCB1IFG &amp;= ~UCTXIFG;\n        value[i] = UCB1RXBUF;\n        i++;\n    }while(i &lt; (length - 1));\n\n    while (!(UCB1IFG &amp; UCRXIFG));\n\n    UCB1IFG &amp;= ~UCTXIFG;\n    UCB1CTL1 |= UCTXSTP;\n    value[length - 1] = UCB1RXBUF;\n    UCB1IFG &amp;= ~UCTXIFG;\n\n    return 0;\n}\n\nunsigned char I2C_USCI_B1_write_byte(unsigned char address, unsigned char value)\n{\n    while(UCB1CTL1 &amp; UCTXSTP);\n\n    UCB1CTL1 |= (UCTR | UCTXSTT);\n\n    while(!(UCB1IFG &amp; UCTXIFG));\n\n    if(UCB1IFG &amp; UCNACKIFG)\n    {\n        return UCB1STAT;\n    }\n\n    UCB1TXBUF = address;\n\n    while(!(UCB1IFG &amp; UCTXIFG));\n\n    if(UCB1IFG &amp; UCNACKIFG)\n    {\n        return UCB1STAT;\n    }\n\n    UCB1TXBUF = value;\n\n    while(!(UCB1IFG &amp; UCTXIFG));\n\n    if(UCB1IFG &amp; UCNACKIFG)\n    {\n        return UCB1STAT;\n    }\n\n    UCB1CTL1 |= UCTXSTP;\n    UCB1IFG &amp;= ~UCTXIFG;\n\n    return 0;\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>BH1750.h<\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include&lt;msp430.h&gt; \"driverlib.h\" #include \"delay.h\" #include \"USCI_I2C.h\" #define  BH1750_addr                     0x23           #define  power_down                      0x00 #define  power_up                        0x01 #define  reset                           0x07  #define  cont_H_res_mode1                0x10  #define  cont_H_res_mode2                0x11   #define  cont_L_res_mode                 0x13     #define  one_time_H_res_mode1            0x20  #define  one_time_H_res_mode2            0x21 #define  one_time_L_res_mode             0x23                            void BH1750_init(void); void BH1750_write(unsigned char cmd);       unsigned int BH1750_read_word(void); unsigned int get_lux_value(unsigned char mode, unsigned int delay_time);<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>BH1750.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"BH1750.h\"\n\nvoid BH1750_init(void)\n{ \n   I2C_USCI_B0_init(BH1750_addr);\n   delay_ms(10);  \n   BH1750_write(power_down);\n}                \n\nvoid BH1750_write(unsigned char cmd)\n{  \n    I2C_USCI_B0_write_byte(BH1750_addr, cmd);\n}\n\nunsigned int BH1750_read_word(void)\n{                      \n  unsigned long value = 0x0000;\n  unsigned char bytes[2] = {0x00, 0x00};\n\n  I2C_USCI_B0_read_word(0x11, bytes, 2);\n\n  value = ((bytes[1] &lt;&lt; 8) | bytes[0]);  \n\n  return value;\n} \n\nunsigned int get_lux_value(unsigned char mode, unsigned int delay_time)\n{\n  unsigned long lux_value = 0x00;  \n  unsigned char dly = 0x00;\n  unsigned char s = 0x08;\n\n  while(s)\n  {\n     BH1750_write(power_up);\n     BH1750_write(mode);\n\n     lux_value += BH1750_read_word();\n\n     for(dly = 0; dly &gt;= 3;\n\n  return ((unsigned int)lux_value);\n}                                <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>USCI_SPI.h<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include&lt;msp430.h&gt;  #include \"driverlib.h\" #define USCI_A0_MOSI_port                   GPIO_PORT_P3 #define USCI_A0_MISO_port                   GPIO_PORT_P3 #define USCI_A0_CLK_port                    GPIO_PORT_P2 #define USCI_A0_MOSI_pin                    GPIO_PIN3 #define USCI_A0_MISO_pin                    GPIO_PIN4 #define USCI_A0_CLK_pin                     GPIO_PIN7 #define USCI_A1_MOSI_port                   GPIO_PORT_P4 #define USCI_A1_MISO_port                   GPIO_PORT_P4 #define USCI_A1_CLK_port                    GPIO_PORT_P4 #define USCI_A1_MOSI_pin                    GPIO_PIN4 #define USCI_A1_MISO_pin                    GPIO_PIN5 #define USCI_A1_CLK_pin                     GPIO_PIN0 #define USCI_B0_MOSI_port                   GPIO_PORT_P3 #define USCI_B0_MISO_port                   GPIO_PORT_P3 #define USCI_B0_CLK_port                    GPIO_PORT_P3 #define USCI_B0_MOSI_pin                    GPIO_PIN0 #define USCI_B0_MISO_pin                    GPIO_PIN1 #define USCI_B0_CLK_pin                     GPIO_PIN2 #define USCI_B1_MOSI_port                   GPIO_PORT_P4 #define USCI_B1_MISO_port                   GPIO_PORT_P4 #define USCI_B1_CLK_port                    GPIO_PORT_P4 #define USCI_B1_MOSI_pin                    GPIO_PIN1 #define USCI_B1_MISO_pin                    GPIO_PIN2 #define USCI_B1_CLK_pin                     GPIO_PIN3 void SPI_USCI_A0_init(void); void SPI_USCI_A0_write(unsigned char tx_data); unsigned char SPI_USCI_A0_read(void); unsigned char SPI_USCI_A0_transfer(unsigned char tx_data); void SPI_USCI_A1_init(void); void SPI_USCI_A1_write(unsigned char tx_data); unsigned char SPI_USCI_A1_read(void); unsigned char SPI_USCI_A1_transfer(unsigned char tx_data); void SPI_USCI_B0_init(void); void SPI_USCI_B0_write(unsigned char tx_data); unsigned char SPI_USCI_B0_read(void); unsigned char SPI_USCI_B0_transfer(unsigned char tx_data); void SPI_USCI_B1_init(void); void SPI_USCI_B1_write(unsigned char tx_data); unsigned char SPI_USCI_B1_read(void); unsigned char SPI_USCI_B1_transfer(unsigned char tx_data);<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>USCI_SPI.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"USCI_SPI.h\"\n\nvoid SPI_USCI_A0_init(void)\n{\n    GPIO_setAsPeripheralModuleFunctionInputPin(USCI_A0_MISO_port, \n                                               USCI_A0_MISO_pin);\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(USCI_A0_MOSI_port, \n                                                USCI_A0_MOSI_pin);\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(USCI_A0_CLK_port, \n                                                USCI_A0_CLK_pin);\n\n    UCA0CTL1 |= UCSWRST;\n    UCA0CTL0 = UCCKPH | UCMSB | UCMST | UCMODE_1 | UCSYNC;\n    UCA0CTL1 = UCSSEL_2;\n    UCA0BR0 = 4;\n    UCA0BR1 = 0;\n    UCA0CTL1 &amp;= ~UCSWRST;\n}\n\nvoid SPI_USCI_A0_write(unsigned char tx_data)\n{\n    while(!(UCA0IFG &amp; UCTXIFG));\n    UCA0TXBUF = tx_data;\n    while(UCA0STAT &amp; UCBUSY);\n}\n\nunsigned char SPI_USCI_A0_read(void)\n{\n    unsigned char rx_data = 0;\n\n    while(!(UCA0IFG &amp; UCRXIFG));\n    rx_data = UCA0RXBUF;\n    while(UCA0STAT &amp; UCBUSY);\n\n    return rx_data;\n}\n\nunsigned char SPI_USCI_A0_transfer(unsigned char tx_data)\n{\n    unsigned char rx_data = 0;\n\n    while(!(UCA0IFG &amp; UCTXIFG));\n    UCA0TXBUF = tx_data;\n    while(UCA0STAT &amp; UCBUSY);\n\n    while(!(UCA0IFG &amp; UCRXIFG));\n    rx_data = UCA0RXBUF;\n    while(UCA0STAT &amp; UCBUSY);\n\n    return rx_data;\n}\n\nvoid SPI_USCI_A1_init(void)\n{\n    GPIO_setAsPeripheralModuleFunctionInputPin(USCI_A1_MISO_port, \n                                               USCI_A1_MISO_pin);\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(USCI_A1_MOSI_port, \n                                                USCI_A1_MOSI_pin);\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(USCI_A1_CLK_port, \n                                                USCI_A1_CLK_pin);\n\n    UCA1CTL1 |= UCSWRST;\n    UCA1CTL0 = UCCKPH | UCMSB | UCMST | UCMODE_1 | UCSYNC;\n    UCA1CTL1 = UCSSEL_2;\n    UCA1BR0 = 8;\n    UCA1BR1 = 0;\n    UCA1CTL1 &amp;= ~UCSWRST;\n}\n\nvoid SPI_USCI_A1_write(unsigned char tx_data)\n{\n    while(!(UCA1IFG &amp; UCTXIFG));\n    UCA1TXBUF = tx_data;\n    while(UCA1STAT &amp; UCBUSY);\n}\n\nunsigned char SPI_USCI_A1_read(void)\n{\n    unsigned char rx_data = 0;\n\n    while(!(UCA1IFG &amp; UCRXIFG));\n    rx_data = UCA1RXBUF;\n    while(UCA1STAT &amp; UCBUSY);\n\n    return rx_data;\n}\n\nunsigned char SPI_USCI_A1_transfer(unsigned char tx_data)\n{\n    unsigned char rx_data = 0;\n\n    while(!(UCA1IFG &amp; UCTXIFG));\n    UCA1TXBUF = tx_data;\n    while(UCA1STAT &amp; UCBUSY);\n\n    while(!(UCA1IFG &amp; UCRXIFG));\n    rx_data = UCA1RXBUF;\n    while(UCA1STAT &amp; UCBUSY);\n\n    return rx_data;\n}\n\nvoid SPI_USCI_B0_init(void)\n{\n    GPIO_setAsPeripheralModuleFunctionInputPin(USCI_B0_MISO_port, \n                                               USCI_B0_MISO_pin);\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(USCI_B0_MOSI_port, \n                                                USCI_B0_MOSI_pin);\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(USCI_B0_CLK_port, \n                                                USCI_B0_CLK_pin);\n\n    UCB0CTL1 |= UCSWRST;\n    UCB0CTL0 = UCCKPH | UCMSB | UCMST | UCMODE_1 | UCSYNC;\n    UCB0CTL1 = UCSSEL_2;\n    UCB0BR0 = 8;\n    UCB0BR1 = 0;\n    UCB0CTL1 &amp;= ~UCSWRST;\n}\n\nvoid SPI_USCI_B0_write(unsigned char tx_data)\n{\n    while(!(UCB0IFG &amp; UCTXIFG));\n    UCB0TXBUF = tx_data;\n    while(UCB0STAT &amp; UCBUSY);\n}\n\nunsigned char SPI_USCI_B0_read(void)\n{\n    unsigned char rx_data = 0;\n\n    while(!(UCB0IFG &amp; UCRXIFG));\n    rx_data = UCB0RXBUF;\n    while(UCB0STAT &amp; UCBUSY);\n\n    return rx_data;\n}\n\nunsigned char SPI_USCI_B0_transfer(unsigned char tx_data)\n{\n    unsigned char rx_data = 0;\n\n    while(!(UCB0IFG &amp; UCTXIFG));\n    UCB0TXBUF = tx_data;\n    while(UCB0STAT &amp; UCBUSY);\n\n    while(!(UCB0IFG &amp; UCRXIFG));\n    rx_data = UCB0RXBUF;\n    while(UCB0STAT &amp; UCBUSY);\n\n    return rx_data;\n}\n\nvoid SPI_USCI_B1_init(void)\n{\n    GPIO_setAsPeripheralModuleFunctionInputPin(USCI_B1_MISO_port, \n                                               USCI_B1_MISO_pin);\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(USCI_B1_MOSI_port, \n                                                USCI_B1_MOSI_pin);\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(USCI_B1_CLK_port, \n                                                USCI_B1_CLK_pin);\n\n    UCB1CTL1 |= UCSWRST;\n    UCB1CTL0 = UCCKPH | UCMSB | UCMST | UCMODE_1 | UCSYNC;\n    UCB1CTL1 = UCSSEL_2;\n    UCB1BR0 = 8;\n    UCB1BR1 = 0;\n    UCB1CTL1 &amp;= ~UCSWRST;\n}\n\nvoid SPI_USCI_B1_write(unsigned char tx_data)\n{\n    while(!(UCB1IFG &amp; UCTXIFG));\n    UCB1TXBUF = tx_data;\n    while(UCB1STAT &amp; UCBUSY);\n}\n\nunsigned char SPI_USCI_B1_read(void)\n{\n    unsigned char rx_data = 0;\n\n    while(!(UCB1IFG &amp; UCRXIFG));\n    rx_data = UCB1RXBUF;\n    while(UCB1STAT &amp; UCBUSY);\n\n    return rx_data;\n}\n\nunsigned char SPI_USCI_B1_transfer(unsigned char tx_data)\n{\n    unsigned char rx_data = 0;\n\n    while(!(UCB1IFG &amp; UCTXIFG));\n    UCB1TXBUF = tx_data;\n    while(UCB1STAT &amp; UCBUSY);\n\n    while(!(UCB1IFG &amp; UCRXIFG));\n    rx_data = UCB1RXBUF;\n    while(UCB1STAT &amp; UCBUSY);\n\n    return rx_data;\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>PCD8544.h<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"USCI_SPI.h\"\n\n#define RST_port                    GPIO_PORT_P6\n#define CS_port                     GPIO_PORT_P6\n#define DC_port                     GPIO_PORT_P6\n\n#define RST_pin                     GPIO_PIN0\n#define CS_pin                      GPIO_PIN1\n#define DC_pin                      GPIO_PIN2\n\n#define RST_pin_high()              GPIO_setOutputHighOnPin(RST_port, RST_pin)\n#define RST_pin_low()               GPIO_setOutputLowOnPin(RST_port, RST_pin)\n\n#define CS_pin_high()               GPIO_setOutputHighOnPin(CS_port, CS_pin)\n#define CS_pin_low()                GPIO_setOutputLowOnPin(CS_port, CS_pin)\n\n#define DC_pin_high()               GPIO_setOutputHighOnPin(DC_port, DC_pin)\n#define DC_pin_low()                GPIO_setOutputLowOnPin(DC_port, DC_pin)\n\n#define PCD8544_set_Y_addr            0x40\n#define PCD8544_set_X_addr            0x80\n\n#define PCD8544_set_temp              0x04\n#define PCD8544_set_bias              0x10\n#define PCD8544_set_VOP              0x80\n\n#define PCD8544_power_down           0x04\n#define PCD8544_entry_mode           0x02\n#define PCD8544_extended_instruction 0x01\n\n#define PCD8544_display_blank        0x00\n#define PCD8544_display_normal       0x04\n#define PCD8544_display_all_on       0x01\n#define PCD8544_display_inverted     0x05\n\n#define PCD8544_function_set         0x20\n#define PCD8544_display_control      0x08\n\n#define CMD                          0\n#define DAT                          1\n\n#define X_max                        84\n#define Y_max                        48\n#define Rows                         6\n\n#define BLACK                        0\n#define WHITE                        1\n#define PIXEL_XOR                    2\n\n#define ON                           1\n#define OFF                          0\n\n#define NO                           0\n#define YES                          1\n\n#define buffer_size                   504\n\nvoid PCD8544_init(void);\nvoid PCD8544_reset(void);\nvoid PCD8544_write(unsigned char type, unsigned char value);\nvoid PCD8544_set_contrast(unsigned char value);\nvoid PCD8544_set_cursor(unsigned char x_pos, unsigned char y_pos);\nvoid PCD8544_print_char(unsigned char ch, unsigned char colour);\nvoid PCD8544_print_custom_char(unsigned char *map);\nvoid PCD8544_fill(unsigned char bufr);\nvoid PCD8544_clear_buffer(unsigned char colour);\nvoid PCD8544_clear_screen(unsigned char colour);\nvoid print_image(const unsigned char *bmp);\nvoid print_char(unsigned char x_pos, unsigned char y_pos, unsigned char ch, unsigned char colour);\nvoid print_string(unsigned char x_pos, unsigned char y_pos, unsigned char *ch, unsigned char colour);\nvoid print_chr(unsigned char x_pos, unsigned char y_pos, signed int value, unsigned char colour);\nvoid print_int(unsigned char x_pos, unsigned char y_pos, signed long value, unsigned char colour);\nvoid print_decimal(unsigned char x_pos, unsigned char y_pos, unsigned int value, unsigned char points, unsigned char colour);\nvoid print_float(unsigned char x_pos, unsigned char y_pos, float value, unsigned char points, unsigned char colour);\nvoid Draw_Pixel(unsigned char x_pos, unsigned char y_pos, unsigned char colour);\nvoid Draw_Line(signed int x1, signed int y1, signed int x2, signed int y2, unsigned char colour);\nvoid Draw_Rectangle(signed int x1, signed int y1, signed int x2, signed int y2, unsigned char fill, unsigned char colour);\nvoid Draw_Circle(signed int xc, signed int yc, signed int radius, unsigned char fill, unsigned char colour);<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>PCD8544.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"PCD8544.h\"\n\nstatic unsigned char PCD8544_buffer[X_max][Rows];\n\nstatic const unsigned char font[96][5] =\n{\n     {0x00, 0x00, 0x00, 0x00, 0x00} \/\/ 20\n    ,{0x00, 0x00, 0x5f, 0x00, 0x00} \/\/ 21 !\n    ,{0x00, 0x07, 0x00, 0x07, 0x00} \/\/ 22 \"\n    ,{0x14, 0x7f, 0x14, 0x7f, 0x14} \/\/ 23 #\n    ,{0x24, 0x2a, 0x7f, 0x2a, 0x12} \/\/ 24 $\n    ,{0x23, 0x13, 0x08, 0x64, 0x62} \/\/ 25 %\n    ,{0x36, 0x49, 0x55, 0x22, 0x50} \/\/ 26 &amp;\n    ,{0x00, 0x05, 0x03, 0x00, 0x00} \/\/ 27 '\n    ,{0x00, 0x1c, 0x22, 0x41, 0x00} \/\/ 28 (\n    ,{0x00, 0x41, 0x22, 0x1c, 0x00} \/\/ 29 )\n    ,{0x14, 0x08, 0x3e, 0x08, 0x14} \/\/ 2a *\n    ,{0x08, 0x08, 0x3e, 0x08, 0x08} \/\/ 2b +\n    ,{0x00, 0x50, 0x30, 0x00, 0x00} \/\/ 2c ,\n    ,{0x08, 0x08, 0x08, 0x08, 0x08} \/\/ 2d -\n    ,{0x00, 0x60, 0x60, 0x00, 0x00} \/\/ 2e .\n    ,{0x20, 0x10, 0x08, 0x04, 0x02} \/\/ 2f \/\n    ,{0x3e, 0x51, 0x49, 0x45, 0x3e} \/\/ 30 0\n    ,{0x00, 0x42, 0x7f, 0x40, 0x00} \/\/ 31 1\n    ,{0x42, 0x61, 0x51, 0x49, 0x46} \/\/ 32 2\n    ,{0x21, 0x41, 0x45, 0x4b, 0x31} \/\/ 33 3\n    ,{0x18, 0x14, 0x12, 0x7f, 0x10} \/\/ 34 4\n    ,{0x27, 0x45, 0x45, 0x45, 0x39} \/\/ 35 5\n    ,{0x3c, 0x4a, 0x49, 0x49, 0x30} \/\/ 36 6\n    ,{0x01, 0x71, 0x09, 0x05, 0x03} \/\/ 37 7\n    ,{0x36, 0x49, 0x49, 0x49, 0x36} \/\/ 38 8\n    ,{0x06, 0x49, 0x49, 0x29, 0x1e} \/\/ 39 9\n    ,{0x00, 0x36, 0x36, 0x00, 0x00} \/\/ 3a :\n    ,{0x00, 0x56, 0x36, 0x00, 0x00} \/\/ 3b ;\n    ,{0x08, 0x14, 0x22, 0x41, 0x00} \/\/ 3c \n    ,{0x02, 0x01, 0x51, 0x09, 0x06} \/\/ 3f ?\n    ,{0x32, 0x49, 0x79, 0x41, 0x3e} \/\/ 40 @\n    ,{0x7e, 0x11, 0x11, 0x11, 0x7e} \/\/ 41 A\n    ,{0x7f, 0x49, 0x49, 0x49, 0x36} \/\/ 42 B\n    ,{0x3e, 0x41, 0x41, 0x41, 0x22} \/\/ 43 C\n    ,{0x7f, 0x41, 0x41, 0x22, 0x1c} \/\/ 44 D\n    ,{0x7f, 0x49, 0x49, 0x49, 0x41} \/\/ 45 E\n    ,{0x7f, 0x09, 0x09, 0x09, 0x01} \/\/ 46 F\n    ,{0x3e, 0x41, 0x49, 0x49, 0x7a} \/\/ 47 G\n    ,{0x7f, 0x08, 0x08, 0x08, 0x7f} \/\/ 48 H\n    ,{0x00, 0x41, 0x7f, 0x41, 0x00} \/\/ 49 I\n    ,{0x20, 0x40, 0x41, 0x3f, 0x01} \/\/ 4a J\n    ,{0x7f, 0x08, 0x14, 0x22, 0x41} \/\/ 4b K\n    ,{0x7f, 0x40, 0x40, 0x40, 0x40} \/\/ 4c L\n    ,{0x7f, 0x02, 0x0c, 0x02, 0x7f} \/\/ 4d M\n    ,{0x7f, 0x04, 0x08, 0x10, 0x7f} \/\/ 4e N\n    ,{0x3e, 0x41, 0x41, 0x41, 0x3e} \/\/ 4f O\n    ,{0x7f, 0x09, 0x09, 0x09, 0x06} \/\/ 50 P\n    ,{0x3e, 0x41, 0x51, 0x21, 0x5e} \/\/ 51 Q\n    ,{0x7f, 0x09, 0x19, 0x29, 0x46} \/\/ 52 R\n    ,{0x46, 0x49, 0x49, 0x49, 0x31} \/\/ 53 S\n    ,{0x01, 0x01, 0x7f, 0x01, 0x01} \/\/ 54 T\n    ,{0x3f, 0x40, 0x40, 0x40, 0x3f} \/\/ 55 U\n    ,{0x1f, 0x20, 0x40, 0x20, 0x1f} \/\/ 56 V\n    ,{0x3f, 0x40, 0x38, 0x40, 0x3f} \/\/ 57 W\n    ,{0x63, 0x14, 0x08, 0x14, 0x63} \/\/ 58 X\n    ,{0x07, 0x08, 0x70, 0x08, 0x07} \/\/ 59 Y\n    ,{0x61, 0x51, 0x49, 0x45, 0x43} \/\/ 5a Z\n    ,{0x00, 0x7f, 0x41, 0x41, 0x00} \/\/ 5b [\n    ,{0x02, 0x04, 0x08, 0x10, 0x20} \/\/ 5c ?\n    ,{0x00, 0x41, 0x41, 0x7f, 0x00} \/\/ 5d ]\n    ,{0x04, 0x02, 0x01, 0x02, 0x04} \/\/ 5e ^\n    ,{0x40, 0x40, 0x40, 0x40, 0x40} \/\/ 5f _\n    ,{0x00, 0x01, 0x02, 0x04, 0x00} \/\/ 60 `\n    ,{0x20, 0x54, 0x54, 0x54, 0x78} \/\/ 61 a\n    ,{0x7f, 0x48, 0x44, 0x44, 0x38} \/\/ 62 b\n    ,{0x38, 0x44, 0x44, 0x44, 0x20} \/\/ 63 c\n    ,{0x38, 0x44, 0x44, 0x48, 0x7f} \/\/ 64 d\n    ,{0x38, 0x54, 0x54, 0x54, 0x18} \/\/ 65 e\n    ,{0x08, 0x7e, 0x09, 0x01, 0x02} \/\/ 66 f\n    ,{0x0c, 0x52, 0x52, 0x52, 0x3e} \/\/ 67 g\n    ,{0x7f, 0x08, 0x04, 0x04, 0x78} \/\/ 68 h\n    ,{0x00, 0x44, 0x7d, 0x40, 0x00} \/\/ 69 i\n    ,{0x20, 0x40, 0x44, 0x3d, 0x00} \/\/ 6a j\n    ,{0x7f, 0x10, 0x28, 0x44, 0x00} \/\/ 6b k\n    ,{0x00, 0x41, 0x7f, 0x40, 0x00} \/\/ 6c l\n    ,{0x7c, 0x04, 0x18, 0x04, 0x78} \/\/ 6d m\n    ,{0x7c, 0x08, 0x04, 0x04, 0x78} \/\/ 6e n\n    ,{0x38, 0x44, 0x44, 0x44, 0x38} \/\/ 6f o\n    ,{0x7c, 0x14, 0x14, 0x14, 0x08} \/\/ 70 p\n    ,{0x08, 0x14, 0x14, 0x18, 0x7c} \/\/ 71 q\n    ,{0x7c, 0x08, 0x04, 0x04, 0x08} \/\/ 72 r\n    ,{0x48, 0x54, 0x54, 0x54, 0x20} \/\/ 73 s\n    ,{0x04, 0x3f, 0x44, 0x40, 0x20} \/\/ 74 t\n    ,{0x3c, 0x40, 0x40, 0x20, 0x7c} \/\/ 75 u\n    ,{0x1c, 0x20, 0x40, 0x20, 0x1c} \/\/ 76 v\n    ,{0x3c, 0x40, 0x30, 0x40, 0x3c} \/\/ 77 w\n    ,{0x44, 0x28, 0x10, 0x28, 0x44} \/\/ 78 x\n    ,{0x0c, 0x50, 0x50, 0x50, 0x3c} \/\/ 79 y\n    ,{0x44, 0x64, 0x54, 0x4c, 0x44} \/\/ 7a z\n    ,{0x00, 0x08, 0x36, 0x41, 0x00} \/\/ 7b {\n    ,{0x00, 0x00, 0x7f, 0x00, 0x00} \/\/ 7c |\n    ,{0x00, 0x41, 0x36, 0x08, 0x00} \/\/ 7d }\n    ,{0x10, 0x08, 0x08, 0x10, 0x08} \/\/ 7e ?\n    ,{0x78, 0x46, 0x41, 0x46, 0x78} \/\/ 7f ?\n};\n\nvoid PCD8544_init()\n{\n    GPIO_setAsOutputPin(RST_port, RST_pin);\n    GPIO_setDriveStrength(RST_port, RST_pin, GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(CS_port, CS_pin);\n    GPIO_setDriveStrength(CS_port, CS_pin, GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(DC_port, DC_pin);\n    GPIO_setDriveStrength(DC_port, DC_pin, GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    SPI_USCI_A0_init();\n\n    PCD8544_reset();\n    PCD8544_write(CMD, (PCD8544_extended_instruction | PCD8544_function_set));\n    PCD8544_write(CMD, (PCD8544_set_bias | 0x02));\n    PCD8544_set_contrast(0x39);\n    PCD8544_write(CMD, PCD8544_set_temp);\n    PCD8544_write(CMD, (PCD8544_display_normal | PCD8544_display_control));\n    PCD8544_write(CMD, PCD8544_function_set);\n    PCD8544_write(CMD, PCD8544_display_all_on);\n    PCD8544_write(CMD, PCD8544_display_normal);\n\n    PCD8544_clear_buffer(OFF);\n    PCD8544_clear_screen(ON);\n}\n\nvoid PCD8544_reset(void)\n{\n     RST_pin_low();\n     delay_us(100);\n     RST_pin_high();\n}\n\nvoid PCD8544_write(unsigned char type, unsigned char value)\n{\n    switch(type)\n    {\n        case 1:\n        {\n            DC_pin_high();\n            break;\n        }\n\n        default:\n        {\n            DC_pin_low();\n            break;\n        }\n    }\n\n    CS_pin_low();\n    SPI_USCI_A0_write(value);\n    CS_pin_high();\n}\n\nvoid PCD8544_set_contrast(unsigned char value) \n{\n    if(value &gt;= 0x7F)\n    {\n       value = 0x7F;\n    }\n\n    PCD8544_write(CMD, (PCD8544_extended_instruction | PCD8544_function_set));\n    PCD8544_write(CMD, (PCD8544_set_VOP | value));\n    PCD8544_write(CMD, PCD8544_function_set);\n}\n\nvoid PCD8544_set_cursor(unsigned char x_pos, unsigned char y_pos)\n{\n    PCD8544_write(CMD, (PCD8544_set_X_addr | x_pos));\n    PCD8544_write(CMD, (PCD8544_set_Y_addr | y_pos));\n}\n\nvoid PCD8544_print_char(unsigned char ch, unsigned char colour)\n{\n     unsigned char s = 0;\n     unsigned char chr = 0;\n     \n     for(s = 0; s &lt;= 4; s++)\n     {\n           chr = font[(ch - 0x20)][s];\n           if(colour == BLACK)\n           {\n               chr = ~chr;\n           }\n           PCD8544_write(DAT, chr);\n     }\n}\n\nvoid PCD8544_print_custom_char(unsigned char *map)\n{\n    unsigned char s = 0;\n\n    for(s = 0; s &lt;= 4; s++)\n    {\n        PCD8544_write(DAT, *map++);\n    }\n}\n\nvoid PCD8544_fill(unsigned char bufr)\n{\n    unsigned int s = 0;\n\n    PCD8544_set_cursor(0, 0);\n\n    for(s = 0; s  -1)\n    {\n        while(y_pos &gt; -1)\n        {\n            PCD8544_buffer[x_pos][y_pos] = colour;\n            y_pos--;\n        }\n\n        x_pos--;\n    }\n}\n\nvoid PCD8544_clear_screen(unsigned char colour)\n{\n    unsigned char x_pos = 0;\n    unsigned char y_pos = 0;\n    \n    for(y_pos = 0; y_pos &lt; Rows; y_pos++)\n    {\n        for(x_pos = 0; x_pos &lt; X_max; x_pos++)\n        {\n            print_string(x_pos, y_pos, \" \", colour);\n        }\n    }\n}\n\nvoid print_image(const unsigned char *bmp)\n{\n    unsigned int s = 0;\n    \n    PCD8544_set_cursor(0, 0);\n    \n    for(s = 0; s = 0x20) &amp;&amp; (*ch &lt;= 0x7F));\n}\n\nvoid print_chr(unsigned char x_pos, unsigned char y_pos, signed int value, unsigned char colour)\n{\n    unsigned char ch = 0x00;\n\n    if(value  99) &amp;&amp; (value  9) &amp;&amp; (value = 0) &amp;&amp; (value &lt;= 9))\n     {\n         ch = (value % 10);\n         PCD8544_set_cursor((x_pos + 6), y_pos);\n         PCD8544_print_char((48 + ch), colour);\n         \n         PCD8544_set_cursor((x_pos + 12), y_pos);\n         PCD8544_print_char(0x20, colour);\n         \n         PCD8544_set_cursor((x_pos + 18), y_pos);\n         PCD8544_print_char(0x20, colour);\n     }\n}\n\nvoid print_int(unsigned char x_pos, unsigned char y_pos, signed long value, unsigned char colour)\n{\n    unsigned char ch = 0x00;\n\n    if(value  9999)\n    {\n        ch = (value \/ 10000);\n        PCD8544_set_cursor((x_pos + 6), y_pos);\n        PCD8544_print_char((48 + ch), colour);\n\n        ch = ((value % 10000)\/ 1000);\n        PCD8544_set_cursor((x_pos + 12), y_pos);\n        PCD8544_print_char((48 + ch), colour);\n\n        ch = ((value % 1000) \/ 100);\n        PCD8544_set_cursor((x_pos + 18), y_pos);\n        PCD8544_print_char((48 + ch), colour);\n\n        ch = ((value % 100) \/ 10);\n        PCD8544_set_cursor((x_pos + 24), y_pos);\n        PCD8544_print_char((48 + ch), colour);\n\n        ch = (value % 10);\n        PCD8544_set_cursor((x_pos + 30), y_pos);\n        PCD8544_print_char((48 + ch), colour);\n    }\n\n    else if((value &gt; 999) &amp;&amp; (value  99) &amp;&amp; (value  9) &amp;&amp; (value  1)\n    {\n        ch = ((value % 1000) \/ 100);\n        PCD8544_set_cursor((x_pos + 12), y_pos);\n        PCD8544_print_char((48 + ch), colour);\n\n        if(points &gt; 2)\n        {\n            ch = ((value % 100) \/ 10);\n            PCD8544_set_cursor((x_pos + 18), y_pos);\n            PCD8544_print_char((48 + ch), colour);\n\n            if(points &gt; 3)\n            {\n                ch = (value % 10);\n                PCD8544_set_cursor((x_pos + 24), y_pos);\n                PCD8544_print_char((48 + ch), colour);;\n            }\n        }\n    }\n}\n\nvoid print_float(unsigned char x_pos, unsigned char y_pos, float value, unsigned char points, unsigned char colour)\n{\n    signed long tmp = 0x00;\n\n    tmp = ((signed long)value);\n    print_int(x_pos, y_pos, tmp, colour);\n    tmp = ((value - tmp) * 10000);\n\n    if(tmp = 9999) &amp;&amp; (value = 999) &amp;&amp; (value = 99) &amp;&amp; (value = 9) &amp;&amp; (value &lt; 99))\n    {\n        print_decimal((x_pos + 18), y_pos, tmp, points, colour);\n    }\n    else if(value &lt; 9)\n    {\n        print_decimal((x_pos + 12), y_pos, tmp, points, colour);\n        if((value) = X_max) || (y_pos &gt;= Y_max))\n    {\n        return;\n    }\n\n    row = (y_pos &gt;&gt; 3);\n\n    value = PCD8544_buffer[x_pos][row];\n    \n    if(colour == BLACK)\n    {\n        value |= (1 &lt;&lt; (y_pos % 8));\n    } \n    else if(colour == WHITE)\n    {\n        value &amp;= (~(1 &lt;&lt; (y_pos % 8)));\n    }\n    else if(colour == PIXEL_XOR)\n    {\n        value ^= (1 &lt;&lt; (y_pos % 8));\n    } \n\n    PCD8544_buffer[x_pos][row] = value;\n\n    PCD8544_set_cursor(x_pos, row);\n    PCD8544_write(DAT, value);\n}\n\nvoid Draw_Line(signed int x1, signed int y1, signed int x2, signed int y2, unsigned char colour)\n{\n    signed int dx = 0x0000;\n    signed int dy = 0x0000;\n    signed int stepx = 0x0000;\n    signed int stepy = 0x0000;\n    signed int fraction = 0x0000;\n\n    dy = (y2 - y1);\n    dx = (x2 - x1);\n\n    if (dy &lt; 0)\n    {\n        dy = -dy;\n        stepy = -1;\n    }\n    else\n    {\n        stepy = 1;\n    }\n\n    if (dx &lt; 0)\n    {\n        dx = -dx;\n        stepx = -1;\n    }\n    else\n    {\n        stepx = 1;\n    }\n\n    dx &lt;&lt;= 0x01;\n    dy &lt; dy)\n    {\n        fraction = (dy - (dx &gt;&gt; 1));\n        while (x1 != x2)\n        {\n            if (fraction &gt;= 0)\n            {\n                y1 += stepy;\n                fraction -= dx;\n            }\n            x1 += stepx;\n            fraction += dy;\n\n            Draw_Pixel(x1, y1, colour);\n        }\n    }\n    else\n    {\n        fraction = (dx - (dy &gt;&gt; 1));\n\n        while (y1 != y2)\n        {\n            if (fraction &gt;= 0)\n            {\n                x1 += stepx;\n                fraction -= dy;\n            }\n            y1 += stepy;\n            fraction += dx;\n            Draw_Pixel(x1, y1, colour);\n        }\n    }\n}\n\nvoid Draw_Rectangle(signed int x1, signed int y1, signed int x2, signed int y2, unsigned char fill, unsigned char colour)\n{\n     unsigned char i = 0x00;\n     unsigned char xmin = 0x00;\n     unsigned char xmax = 0x00;\n     unsigned char ymin = 0x00;\n     unsigned char ymax = 0x00;\n\n     if(fill != NO)\n     {\n        if(x1 &lt; x2)\n        {\n           xmin = x1;\n           xmax = x2;\n        }\n        else\n        {\n           xmin = x2;\n           xmax = x1;\n        }\n\n        if(y1 &lt; y2)\n        {\n           ymin = y1;\n           ymax = y2;\n        }\n        else\n        {\n           ymin = y2;\n           ymax = y1;\n        }\n\n        for(; xmin &lt;= xmax; ++xmin)\n        {\n             for(i = ymin; i &lt;= ymax; ++i)\n             {\n                 Draw_Pixel(xmin, i, colour);\n             }\n         }\n     }\n\n     else\n     {\n        Draw_Line(x1, y1, x2, y1, colour);\n        Draw_Line(x1, y2, x2, y2, colour);\n        Draw_Line(x1, y1, x1, y2, colour);\n        Draw_Line(x2, y1, x2, y2, colour);\n     }\n}\n\nvoid Draw_Circle(signed int xc, signed int yc, signed int radius, unsigned char fill, unsigned char colour)\n{\n    signed int a = 0x0000;\n    signed int b = 0x0000;\n    signed int p = 0x0000;\n\n    b = radius;\n    p = (1 - b);\n\n    do\n    {\n        if(fill != NO)\n        {\n            Draw_Line((xc - a), (yc + b), (xc + a), (yc + b), colour);\n            Draw_Line((xc - a), (yc - b), (xc + a), (yc - b), colour);\n            Draw_Line((xc - b), (yc + a), (xc + b), (yc + a), colour);\n            Draw_Line((xc - b), (yc - a), (xc + b), (yc - a), colour);\n        }\n        else\n        {\n            Draw_Pixel((xc + a), (yc + b), colour);\n            Draw_Pixel((xc + b), (yc + a), colour);\n            Draw_Pixel((xc - a), (yc + b), colour);\n            Draw_Pixel((xc - b), (yc + a), colour);\n            Draw_Pixel((xc + b), (yc - a), colour);\n            Draw_Pixel((xc + a), (yc - b), colour);\n            Draw_Pixel((xc - a), (yc - b), colour);\n            Draw_Pixel((xc - b), (yc - a), colour);\n        }\n\n        if(p &lt; 0)\n        {\n            p += (0x03 + (0x02 * a++));\n        }\n        else\n        {\n            p += (0x05 + (0x02 * ((a++) - (b--))));\n        }\n    }while(a &lt;= b);\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong><em>main.c<\/em><\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">#include&lt;msp430.h&gt;  #include \"driverlib.h\" #include \"delay.h\" #include \"USCI_I2C.h\" #include \"USCI_SPI.h\" #include \"PCD8544.h\" #include \"BH1750.h\" void clock_init(void); void main(void) {     unsigned int LX = 0x0000;     unsigned int tmp = 0x0000;     WDT_A_hold(WDT_A_BASE);     clock_init();     PCD8544_init();     BH1750_init();     print_string(1, 3, \"Lux:\", ON);     while(1)     {         tmp = get_lux_value(cont_H_res_mode1, 20);         if(tmp &gt; 10)         {             LX = tmp;         }         else         {             LX = get_lux_value(cont_H_res_mode1, 140);         }         print_int(35, 3, LX, ON);         delay_ms(200);     }; } void clock_init(void) {     PMM_setVCore(PMM_CORE_LEVEL_3);     GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,                                                (GPIO_PIN4 | GPIO_PIN2));     GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,                                                 (GPIO_PIN5 | GPIO_PIN3));     UCS_setExternalClockSource(XT1_FREQ,                                XT2_FREQ);     UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);     UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,                     UCS_XCAP_3);     UCS_initClockSignal(UCS_FLLREF,                         UCS_XT2CLK_SELECT,                         UCS_CLOCK_DIVIDER_4);     UCS_initFLLSettle(MCLK_KHZ,                       MCLK_FLLREF_RATIO);     UCS_initClockSignal(UCS_SMCLK,                         UCS_XT2CLK_SELECT,                         UCS_CLOCK_DIVIDER_4);     UCS_initClockSignal(UCS_ACLK,                         UCS_XT1CLK_SELECT,                         UCS_CLOCK_DIVIDER_1); }<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"583\" height=\"657\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI3.png\" alt=\"\" class=\"wp-image-14684\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI3.png 583w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI3-577x650.png 577w\" sizes=\"auto, (max-width: 583px) 100vw, 583px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The USCI libraries for SPI and I2C here are mostly coded at raw\nlevel and without much driverlib help. These are based on my past tutorials. I actually\ncopied from those tutorial examples and made some minor changes. These\nlibraries are already proven and so there is nothing new here. Basically, this\nUSCI example is mere a proof-of-concept of the fact that we can use USCI\nwithout driverlib.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We start by declaring I\/O pins as per device\u2019s pin mapping. Let\u2019s see the I2C library first. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#include&lt;msp430.h&gt;  #include \"driverlib.h\" #define USCI_B0_I2C_port                                  GPIO_PORT_P3 #define USCI_B0_I2C_SDA_pin                               GPIO_PIN0 #define USCI_B0_I2C_SCL_pin                               GPIO_PIN1 #define USCI_B1_I2C_port                                  GPIO_PORT_P4 #define USCI_B1_I2C_SDA_pin                               GPIO_PIN1 #define USCI_B1_I2C_SCL_pin                               GPIO_PIN2<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">GPIOs to be used need to set for alternative roles.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">GPIO_setAsPeripheralModuleFunctionOutputPin(USCI_B0_I2C_port, \n                                            (USCI_B0_I2C_SDA_pin \n                                            | USCI_B0_I2C_SCL_pin));<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The rest of the code is same as like the ones in the HW_I2C files of\nmy past tutorial. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The demo here uses USCI B0 I2C module to operate a BH1750 light sensor as shown below:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void BH1750_write(unsigned char cmd)\n{  \n    I2C_USCI_B0_write_byte(BH1750_addr, cmd);\n}\n\nunsigned int BH1750_read_word(void)\n{                      \n  unsigned long value = 0x0000;\n  unsigned char bytes[2] = {0x00, 0x00};\n\n  I2C_USCI_B0_read_word(0x11, bytes, 2);\n\n  value = ((bytes[1] &lt;&lt; 8) | bytes[0]);  \n\n  return value;\n} <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The same goes for the USCI SPI library.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#include&lt;msp430.h&gt;  #include \"driverlib.h\" #define USCI_A0_MOSI_port                   GPIO_PORT_P3 #define USCI_A0_MISO_port                   GPIO_PORT_P3 #define USCI_A0_CLK_port                    GPIO_PORT_P2 #define USCI_A0_MOSI_pin                    GPIO_PIN3 #define USCI_A0_MISO_pin                    GPIO_PIN4 #define USCI_A0_CLK_pin                     GPIO_PIN7 #define USCI_A1_MOSI_port                   GPIO_PORT_P4 #define USCI_A1_MISO_port                   GPIO_PORT_P4 #define USCI_A1_CLK_port                    GPIO_PORT_P4 #define USCI_A1_MOSI_pin                    GPIO_PIN4 #define USCI_A1_MISO_pin                    GPIO_PIN5 #define USCI_A1_CLK_pin                     GPIO_PIN0 #define USCI_B0_MOSI_port                   GPIO_PORT_P3 #define USCI_B0_MISO_port                   GPIO_PORT_P3 #define USCI_B0_CLK_port                    GPIO_PORT_P3 #define USCI_B0_MOSI_pin                    GPIO_PIN0 #define USCI_B0_MISO_pin                    GPIO_PIN1 #define USCI_B0_CLK_pin                     GPIO_PIN2 #define USCI_B1_MOSI_port                   GPIO_PORT_P4 #define USCI_B1_MISO_port                   GPIO_PORT_P4 #define USCI_B1_CLK_port                    GPIO_PORT_P4 #define USCI_B1_MOSI_pin                    GPIO_PIN1 #define USCI_B1_MISO_pin                    GPIO_PIN2 #define USCI_B1_CLK_pin                     GPIO_PIN3<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">SPI has separate input and output pins and so their declaration need care.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">GPIO_setAsPeripheralModuleFunctionInputPin(USCI_A0_MISO_port, USCI_A0_MISO_pin);\n\nGPIO_setAsPeripheralModuleFunctionOutputPin(USCI_A0_MOSI_port, USCI_A0_MOSI_pin);\n\nGPIO_setAsPeripheralModuleFunctionOutputPin(USCI_A0_CLK_port, USCI_A0_CLK_pin);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Many SPI devices need additional control pins and those can be declared as ordinary GPIOs. These pins can be any pins of our choice. In this case, our Nokia GLCD has a reset, chip select and data-command pin apart from SPI communication pins.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#define RST_port                   GPIO_PORT_P6\n#define CS_port                    GPIO_PORT_P6\n#define DC_port                    GPIO_PORT_P6\n\n#define RST_pin                    GPIO_PIN0\n#define CS_pin                     GPIO_PIN1\n#define DC_pin                     GPIO_PIN2\n\n#define RST_pin_high()             GPIO_setOutputHighOnPin(RST_port, RST_pin)\n#define RST_pin_low()              GPIO_setOutputLowOnPin(RST_port, RST_pin)\n\n#define CS_pin_high()              GPIO_setOutputHighOnPin(CS_port, CS_pin)\n#define CS_pin_low()               GPIO_setOutputLowOnPin(CS_port, CS_pin)\n\n#define DC_pin_high()              GPIO_setOutputHighOnPin(DC_port, DC_pin)\n#define DC_pin_low()               GPIO_setOutputLowOnPin(DC_port, DC_pin)\n\n....\n\nGPIO_setAsOutputPin(RST_port, RST_pin);\nGPIO_setDriveStrength(RST_port, RST_pin, GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\nGPIO_setAsOutputPin(CS_port, CS_pin);    \nGPIO_setDriveStrength(CS_port, CS_pin, GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\nGPIO_setAsOutputPin(DC_port, DC_pin);\nGPIO_setDriveStrength(DC_port, DC_pin, GPIO_FULL_OUTPUT_DRIVE_STRENGTH);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The code below shows how we used the USCI_A0 in SPI mode to operate the Nokia GLCD.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void PCD8544_write(unsigned char type, unsigned char value)\n{\n    switch(type)\n    {\n        case 1:\n        {\n            DC_pin_high();\n            break;\n        }\n\n        default:\n        {\n            DC_pin_low();\n            break;\n        }\n    }\n\n    CS_pin_low();\n    SPI_USCI_A0_write(value);\n    CS_pin_high();\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Writing the display is same as the TFT write example. There is no read back from the GLCD.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"769\" height=\"1024\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI-EX3-769x1024.jpg\" alt=\"\" class=\"wp-image-14685\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI-EX3-769x1024.jpg 769w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI-EX3-488x650.jpg 488w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI-EX3-768x1022.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USCI-EX3.jpg 1369w\" sizes=\"auto, (max-width: 769px) 100vw, 769px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/bomb4JiuQAM?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">USCI \u2013 UART<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">UART\/serial communication in MSP430s is achieved using USCI modules. In MSP430F5529, USCI A modules can be used for both SPI and UART.&nbsp; <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"698\" height=\"823\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Block-1.png\" alt=\"\" class=\"wp-image-14687\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Block-1.png 698w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/Block-1-551x650.png 551w\" sizes=\"auto, (max-width: 698px) 100vw, 698px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The block diagram of USCI in UART mode is shown above. As can be seen, UART module can be clocked with four clock sources. These clock sources can be fine-tuned for desired baud rates. There are separate buffers and state machines for transmission and reception parts. The UART module can use used for IrDA communication and there are optional internal encoder and decoder for so. Lastly, there are flags for events and errors at various points.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Eltima Soft<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.eltima.com\/\">Eltima<\/a> software is a US-based company that make some useful computer communication software interfaces. Eltima has been kind enough to supply me their <a href=\"https:\/\/www.eltima.com\/products\/serial-port-monitor\/\">Serial Port Monitor<\/a>. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"689\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/eltima-1024x689.png\" alt=\"\" class=\"wp-image-14688\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/eltima-1024x689.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/eltima-580x390.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/eltima-768x516.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/eltima.png 1426w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">In embedded-system world, we all use some kind of\nserial port monitor but Eltima\u2019s serial port monitor has the following features\nthat are not usually available in other software:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>COM data logging in real-time\nand saving for later uses<\/li><li>Multi-port monitoring in one\nsession<\/li><li>Five different visualization modes<\/li><li>Emulation of port<\/li><li>Sniffing of MODBUS RTU and\nASCII data<\/li><li>Comparison of sessions<\/li><li>Easy to use user-interface<\/li><li>Changing of serial port\nparameters on-the-fly<\/li><li>Digitally signed drivers<\/li><li>Advanced filtering<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Of the many features, I particularly liked the\nlogging and MOBUS features. I have no other similar software to compare with\nit. I highly recommend readers to use it and see for themselves. &nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this tutorial post, I have exclusively used this software. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"lcd.h\"\n#include \"lcd_print.h\"\n\nchar RX_Data = 0;\nchar TX_Data = 0;\n\nvoid clock_init(void);\nvoid GPIO_init(void);\nvoid USCI_UART_init(void);\n\n#pragma vector = USCI_A1_VECTOR\n__interrupt void UART_ISR(void)\n{\n    switch(__even_in_range(UCA1IV, 4))\n    {\n        case 0x00:      \/\/ None\n        {\n            break;\n        }\n\n        case 0x02:      \/\/Data RX\n        {\n            RX_Data = USCI_A_UART_receiveData(USCI_A1_BASE);\n\n            GPIO_toggleOutputOnPin(GPIO_PORT_P4,\n                                   GPIO_PIN7);\n\n            break;\n        }\n\n        case 0x04:      \/\/TX Buffer Empty\n        {\n            break;\n        }\n    }\n}\n\nvoid main(void)\n{\n    WDT_A_hold(WDT_A_BASE);\n\n    clock_init();\n\n    USCI_UART_init();\n\n    GPIO_init();\n\n    LCD_init();\n    LCD_clear_home();\n\n    LCD_goto(0, 0);\n    LCD_putstr(\"MSP430 USCI UART\");\n    LCD_goto(0, 1);\n    LCD_putstr(\"TXD: \");\n    LCD_goto(10, 1);\n    LCD_putstr(\"RXD: \");\n\n    while(1)\n    {\n        TX_Data = RX_Data;\n\n        GPIO_toggleOutputOnPin(GPIO_PORT_P1,\n                               GPIO_PIN0);\n\n        USCI_A_UART_transmitData(USCI_A1_BASE,\n                                 TX_Data);\n\n        while(USCI_A_UART_getInterruptStatus(USCI_A1_BASE,                                                                                                               USCI_A_UART_TRANSMIT_INTERRUPT_FLAG) == 0);\n\n        LCD_goto(5, 1);\n        LCD_putchar(TX_Data);\n\n        LCD_goto(15, 1);\n        LCD_putchar(RX_Data);\n\n        delay_ms(900);\n    };\n}\n\nvoid clock_init(void)\n{\n    PMM_setVCore(PMM_CORE_LEVEL_3);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,\n                                               (GPIO_PIN4 | GPIO_PIN2));\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5,\n                                                (GPIO_PIN5 | GPIO_PIN3));\n\n    UCS_setExternalClockSource(XT1_FREQ,\n                               XT2_FREQ);\n\n    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);\n\n    UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,\n                    UCS_XCAP_3);\n\n    UCS_initClockSignal(UCS_FLLREF,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initFLLSettle(MCLK_KHZ,\n                      MCLK_FLLREF_RATIO);\n\n    UCS_initClockSignal(UCS_SMCLK,\n                        UCS_XT2CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_4);\n\n    UCS_initClockSignal(UCS_ACLK,\n                        UCS_XT1CLK_SELECT,\n                        UCS_CLOCK_DIVIDER_1);\n}\n\nvoid GPIO_init(void)\n{\n    GPIO_setAsOutputPin(GPIO_PORT_P1,\n                        GPIO_PIN0);\n\n    GPIO_setDriveStrength(GPIO_PORT_P1,\n                          GPIO_PIN0,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsOutputPin(GPIO_PORT_P4,\n                        GPIO_PIN7);\n\n    GPIO_setDriveStrength(GPIO_PORT_P4,\n                          GPIO_PIN7,\n                          GPIO_FULL_OUTPUT_DRIVE_STRENGTH);\n\n    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4,\n                                               GPIO_PIN5);\n\n    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P4,\n                                                GPIO_PIN4);\n}\n\nvoid USCI_UART_init(void)\n{\n    USCI_A_UART_initParam UART_Param = {0};\n\n    UART_Param.selectClockSource = USCI_A_UART_CLOCKSOURCE_ACLK;\n    UART_Param.clockPrescalar = 3;\n    UART_Param.firstModReg = 0;\n    UART_Param.secondModReg = 3;\n    UART_Param.msborLsbFirst = USCI_A_UART_LSB_FIRST;\n    UART_Param.parity = USCI_A_UART_NO_PARITY;\n    UART_Param.numberofStopBits = USCI_A_UART_ONE_STOP_BIT;\n    UART_Param.uartMode = USCI_A_UART_MODE;\n    UART_Param.overSampling = USCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION;\n\n    USCI_A_UART_init(USCI_A1_BASE,\n                     &amp;UART_Param);\n\n    USCI_A_UART_resetDormant(USCI_A1_BASE);\n\n    USCI_A_UART_enable(USCI_A1_BASE);\n\n    USCI_A_UART_enableInterrupt(USCI_A1_BASE,\n                                USCI_A_UART_RECEIVE_INTERRUPT);\n\n    __enable_interrupt();\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"626\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UART-1024x626.png\" alt=\"\" class=\"wp-image-14689\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UART-1024x626.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UART-580x355.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UART-768x469.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UART.png 1317w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Firstly, GPIO pins are initialized as secondary function pins. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4, GPIO_PIN5);\n\nGPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P4, GPIO_PIN4);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The following function initializes USCI A1 module in UART mode.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void USCI_UART_init(void)\n{\n    USCI_A_UART_initParam UART_Param = {0};\n\n    UART_Param.selectClockSource = USCI_A_UART_CLOCKSOURCE_ACLK;\n    UART_Param.clockPrescalar = 3;\n    UART_Param.firstModReg = 0;\n    UART_Param.secondModReg = 3;\n    UART_Param.msborLsbFirst = USCI_A_UART_LSB_FIRST;\n    UART_Param.parity = USCI_A_UART_NO_PARITY;\n    UART_Param.numberofStopBits = USCI_A_UART_ONE_STOP_BIT;\n    UART_Param.uartMode = USCI_A_UART_MODE;\n    UART_Param.overSampling = USCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION;\n\n    USCI_A_UART_init(USCI_A1_BASE, &amp;UART_Param);\n    USCI_A_UART_resetDormant(USCI_A1_BASE);\n    USCI_A_UART_enable(USCI_A1_BASE);\n    USCI_A_UART_enableInterrupt(USCI_A1_BASE, USCI_A_UART_RECEIVE_INTERRUPT);\n    __enable_interrupt();\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In serial communication, baud rate selection is very important because two serial communication devices must negotiate under a common data transaction rate or else data is unrecognized or treated as garbage. Since baud rate clock-sensitive, we have to carefully chose clock and prescalar settings and this is reflected in the first setting values \u2013 <em>clockPrescalar<\/em>, <em>firstModReg<\/em> and <em>secondModReg<\/em>.  Now let\u2019s see how we came to these values. Refer to section <strong><em>36.3.13 Typical Baud Rates and Errors<\/em><\/strong> of <strong><em>MSP430x5xx and MSP430x6xx Family User&#8217;s Guide<\/em><\/strong>.  <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"326\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/baud-rate-1024x326.png\" alt=\"\" class=\"wp-image-14690\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/baud-rate-1024x326.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/baud-rate-580x185.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/baud-rate-768x245.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/baud-rate.png 1051w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">We have used ACLK as the clock source for UART. ACLK happens to be derived from XT1 oscillator and so its frequency is 32.768 kHz. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">UCS_initClockSignal(UCS_ACLK, UCS_XT1CLK_SELECT, UCS_CLOCK_DIVIDER_1);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Therefore, to achieve a baud rate of 9600, we have to put the values\nas shown in the highlighted section of the table above. With these settings the\nTX-RX errors are high but still we will go with these just to see that even\nafter such high error rates, the serial communication remains smooth and\nsteady.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The rest of the settings describe other properties of our MSP430\u2019s\nserial port. These include number of stop bits, parity, USCI mode and others. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We will be using reception interrupt and so it is also needed to be enabled. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">USCI_A_UART_enableInterrupt(USCI_A1_BASE, USCI_A_UART_RECEIVE_INTERRUPT);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Sending data is very easy. It is just like what we did in SPI examples. We write the data to be sent and wait for the transmit buffer to get empty.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">USCI_A_UART_transmitData(USCI_A1_BASE, TX_Data);\nwhile(USCI_A_UART_getInterruptStatus(USCI_A1_BASE, \n                                     USCI_A_UART_TRANSMIT_INTERRUPT_FLAG) == 0);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Data is received in the interrupt. It is a very simple process. Once a reception interrupt is triggered, we just have to read the reception buffer. Interrupt flag is automatically cleared. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#pragma vector = USCI_A1_VECTOR\n__interrupt void UART_ISR(void)\n{\n    switch(__even_in_range(UCA1IV, 4))\n    {\n        case 0x00:      \/\/ None\n        {\n            break;\n        }\n\n        case 0x02:      \/\/Data RX\n        {\n            RX_Data = USCI_A_UART_receiveData(USCI_A1_BASE);\n\n            GPIO_toggleOutputOnPin(GPIO_PORT_P4, GPIO_PIN7);\n\n            break;\n        }\n\n        case 0x04:      \/\/TX Buffer Empty\n        {\n            break;\n        }\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We chose interrupt method for reception because we don\u2019t know for sure\nwhen a data will be sent to the MSP430 and as such so we don\u2019t want to miss any\ndata sent to the micro. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The demo here simply echoes any character data that has been sent to it from a host PC.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"717\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UART-1024x717.jpg\" alt=\"\" class=\"wp-image-14691\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UART-1024x717.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UART-580x406.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UART-768x538.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UART.jpg 1337w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UART-1-1024x576.png\" alt=\"\" class=\"wp-image-14692\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UART-1-1024x576.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UART-1-580x326.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UART-1-768x432.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/UART-1.png 1366w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/0gZMtbxT7Sw?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">USB Module Overview<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The USB module of MSP430F5529 is not very difficult to use. TI has provided some working deploy-able examples in their 430ware software suite. However, some explanation is needed at first to get started. We will go through two basic USB module examples \u2013 USB CDC and USB HID. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In simple terms, USB CDC is a USB mode with which we\ncan emulate virtual serial COM ports and USB HID is another common USB mode\nwith which we can make devices like USB keyboard, mouse, input devices,\nprinter, scanner, etc as well as other similar I\/O devices. MSP430F5529 also\nsupports mass storage class. In all cases, we create a way to make our MSP430\nmicro communicate with a host device. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now let\u2019s see what we need to get started with USB\ncoding. Apart from driverlib files and personal libraries we will need\nadditional libraries for USB software development. Note the following folders:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><em>USB API<\/em> Folder<\/li><li><em>USB_app<\/em> Folder<\/li><li><em>USB_config<\/em> Folder<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Apart from these we\u2019ll need some important files too:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><em>Hal<\/em> header and source files<\/li><li><em>system_pre_init<\/em> source file<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Fortunately for us we don\u2019t have to change anything\nin these files\/folders. We just have to add them in our USB projects and the\nprocess of adding doesn\u2019t need any special attention. Alternatively, we can\nsimply copy example USB projects from MSP430ware and have them customized as\nper need. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Very briefly speaking, <em>USB API folder<\/em>,\nsub-folders and files in them are what describe a specific USB mode\u2019s working.\nThey list relevant functions for a given mode. <em>USB_app<\/em> folder and\nassociated files further elaborate these operations. USB devices need\ndescriptors and <em>USB_config<\/em> folder and files contain them. <em>Ha<\/em>l\nsource and header files contain clock and GPIO setups and <em>system_pre_init<\/em>\nbasically contains nothing except watchdog setup.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Shown below is the folder tree of a typical USB project. All I stated so far is what boils down to this folder tree.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"393\" height=\"899\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/files.png\" alt=\"\" class=\"wp-image-14693\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/files.png 393w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/files-284x650.png 284w\" sizes=\"auto, (max-width: 393px) 100vw, 393px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">In the main, all of the aforementioned files are included as shown below:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n\n#include \"USB_config\/descriptors.h\"\n#include \"USB_API\/USB_Common\/device.h\"\n#include \"USB_API\/USB_Common\/usb.h\"\n#include \"USB_API\/USB_CDC_API\/UsbCdc.h\"\n#include \"USB_app\/usbConstructs.h\"\n\n#include \"hal.h\"<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Pay attention to these functions shown below:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>PMM_setVCore(PMM_CORE_LEVEL_2);\nUSBHAL_initPorts();\nUSBHAL_initClocks(8000000);\nUSB_setup(TRUE, TRUE);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Clock setting is very important because USB hardware\nis clock sensitive. FLL is used for both MCLK and USB clock. It is also necessary\nto set the right level for PMM core. Usually level 2 is preferred as the clock\nspeed is 8MHz. On start-up, all GPIO ports are driven low to avoid floating\ninput and unwanted EMI-related issues. This causes some additional power\nconsumption. Thus, it is recommended to setup GPIOs for other tasks after\ninitial USB port initialization. Please refer to TI\u2019s official docs for\nadditional info.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you are not using official TI boards or\nequivalents and designing stuffs on your own then pay attention to USB hardware\ndesign considerations. EMC considerations are also needed to focused more\nalongside good PCB layout practices. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In addition to these, we can develop our own customized PC\/mobile applications with Visual C Sharp (C#), Visual Basic or some other similar computer programming languages. This part is beyond the scope of this tutorial and won\u2019t be discussed. <\/p>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">USB CDC<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">With USB CDC mode we can directly transfer data to and from a PC\/mobile device without needing an external USB-to-Serial converter like FT232, CP2102, PL2303, etc. We\u2019ll simply make a virtual COM port. The idea in this demo is to send out on-chip temperature sensor\u2019s temperature reading upon request from a host PC. The request is nothing special but just an ASCII character. The key that was pressed in the host PC\u2019s keyboard is then displayed on an LCD connected with the MSP430.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"525\" height=\"486\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/eltima-1.png\" alt=\"\" class=\"wp-image-14696\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"346\" height=\"209\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/ft232.png\" alt=\"\" class=\"wp-image-14697\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"lcd.h\"\n#include \"lcd_print.h\"\n\n#include \"USB_config\/descriptors.h\"\n#include \"USB_API\/USB_Common\/device.h\"\n#include \"USB_API\/USB_Common\/usb.h\"\n#include \"USB_API\/USB_CDC_API\/UsbCdc.h\"\n#include \"USB_app\/usbConstructs.h\"\n\n#include \"hal.h\"\n\nvolatile uint8_t bCDCDataReceived_event = FALSE;\n\n#define RX_BUFFER_SIZE  1\n#define TX_BUFFER_SIZE  4\n\nchar dataBuffer[RX_BUFFER_SIZE] = \"\";\nchar nl[2] = \"\\n\";\nuint16_t count;\n\nvoid ADC12_init(void);\nvoid REF_init(void);\n\n#pragma vector = UNMI_VECTOR\n__interrupt void UNMI_ISR (void)\n{\n    switch (__even_in_range(SYSUNIV, SYSUNIV_BUSIFG ))\n    {\n        case SYSUNIV_NONE:\n            __no_operation();\n            break;\n        case SYSUNIV_NMIIFG:\n            __no_operation();\n            break;\n        case SYSUNIV_OFIFG:\n            UCS_clearFaultFlag(UCS_XT2OFFG);\n            UCS_clearFaultFlag(UCS_DCOFFG);\n            SFR_clearInterrupt(SFR_OSCILLATOR_FAULT_INTERRUPT);\n            break;\n        case SYSUNIV_ACCVIFG:\n            __no_operation();\n            break;\n        case SYSUNIV_BUSIFG:\n            SYSBERRIV = 0;\n            USB_disable();\n    }\n}\n\nvoid main (void)\n{\n    float tmp = 0.0;\n    signed int ADC_Count = 0;\n    signed long temp = 0;\n    uint8_t tc[TX_BUFFER_SIZE] = {0x00, 0x00, '\\r', '\\n'};\n\n    WDT_A_hold(WDT_A_BASE);\n\n    PMM_setVCore(PMM_CORE_LEVEL_2);\n\n    REF_init();\n\n    ADC12_init();\n\n    LCD_init();\n    LCD_clear_home();\n\n    LCD_goto(1, 0);\n    LCD_putstr(\"MSP430 USB CDC\");\n\n    LCD_goto(0, 1);\n    LCD_putstr(\"T\/'C:\");\n\n    LCD_goto(11, 1);\n    LCD_putstr(\"RX:\");\n\n    USBHAL_initPorts();\n    USBHAL_initClocks(8000000);\n    USB_setup(TRUE, TRUE);\n\n    __enable_interrupt();\n\n    while (1)\n    {\n        uint8_t ReceiveError = 0;\n        uint8_t SendError = 0;\n\n        ADC_Count = ADC12_A_getResults(ADC12_A_BASE,\n                                       ADC12_A_MEMORY_0);\n\n        tmp = (((float)ADC_Count * 1.5) \/ 4095.0);\n        temp = ((tmp - 0.688) \/ 0.00252);\n\n        print_C(6, 1, temp);\n\n        switch (USB_getConnectionState())\n        {\n            case ST_ENUM_ACTIVE:\n            {\n                __disable_interrupt();\n                if (!USBCDC_getBytesInUSBBuffer(CDC0_INTFNUM))\n                {\n                    __bis_SR_register(LPM0_bits + GIE);\n                }\n\n                __enable_interrupt();\n\n                if (bCDCDataReceived_event)\n                {\n                    bCDCDataReceived_event = FALSE;\n\n                    count = USBCDC_receiveDataInBuffer((uint8_t*)dataBuffer,\n                                                       RX_BUFFER_SIZE,\n                                                       CDC0_INTFNUM);\n                    LCD_goto(15, 1);\n                    LCD_putstr(dataBuffer);\n                }\n\n                tc[0] = ((temp \/ 10) + 0x30);\n                tc[1] = ((temp % 10) + 0x30);\n\n                if(USBCDC_sendDataInBackground((uint8_t*)tc,\n                                               TX_BUFFER_SIZE,\n                                               CDC0_INTFNUM,\n                                               1))\n                {\n                    SendError = 0x01;\n                    break;\n                }\n\n                break;\n\n            }\n            case ST_PHYS_DISCONNECTED:\n            case ST_ENUM_SUSPENDED:\n            case ST_PHYS_CONNECTED_NOENUM_SUSP:\n                __bis_SR_register(LPM3_bits + GIE);\n                _NOP();\n                break;\n\n            case ST_ENUM_IN_PROGRESS:\n            default:;\n        }\n\n        if (ReceiveError || SendError)\n        {\n        }\n    }\n}\n\nvoid ADC12_init(void)\n{\n    ADC12_A_configureMemoryParam configureMemoryParam = {0};\n\n    ADC12_A_init(ADC12_A_BASE,\n                 ADC12_A_SAMPLEHOLDSOURCE_SC,\n                 ADC12_A_CLOCKSOURCE_ACLK,\n                 ADC12_A_CLOCKDIVIDER_1);\n\n    ADC12_A_setupSamplingTimer(ADC12_A_BASE,\n                               ADC12_A_CYCLEHOLD_768_CYCLES,\n                               ADC12_A_CYCLEHOLD_4_CYCLES,\n                               ADC12_A_MULTIPLESAMPLESENABLE);\n\n    ADC12_A_setResolution(ADC12_A_BASE,\n                          ADC12_A_RESOLUTION_12BIT);\n\n    configureMemoryParam.memoryBufferControlIndex = ADC12_A_MEMORY_0;\n    configureMemoryParam.inputSourceSelect = ADC12_A_INPUT_TEMPSENSOR;\n    configureMemoryParam.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_INT;\n    configureMemoryParam.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;\n    configureMemoryParam.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;\n\n    ADC12_A_configureMemory(ADC12_A_BASE,\n                            &amp;configureMemoryParam);\n\n    ADC12_A_enable(ADC12_A_BASE);\n\n    ADC12_A_startConversion(ADC12_A_BASE,\n                            ADC12_A_MEMORY_0,\n                            ADC12_A_REPEATED_SINGLECHANNEL);\n}\n\nvoid REF_init(void)\n{\n    while(REF_ACTIVE == Ref_isRefGenBusy(REF_BASE));\n\n    Ref_setReferenceVoltage(REF_BASE,\n                            REF_VREF1_5V);\n\n    Ref_enableReferenceVoltage(REF_BASE);\n\n    __delay_cycles(100);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"629\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-CDC-1024x629.png\" alt=\"\" class=\"wp-image-14698\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-CDC-1024x629.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-CDC-580x356.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-CDC-768x472.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-CDC.png 1249w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The setup for using the ADC and on-chip temperature sensor have already been discussed and demoed previously. Likewise, the basic USB setup has been discussed in the USB module overview section. Therefore, I\u2019ll skip these parts. The main loop is the part that is of our interest. As can be seen, temperature read from ADC is shown in the display first. The <em>switch-case<\/em> statement acts according to the state of the USB module\u2019s connection state. Of these states, the first one (<em>ST_ENUM_ACTIVE<\/em>) is of most importance. In this state, data is transferred by a method called enumeration. The rest of the states have other importance but these won\u2019t be needed here. The whole system is interrupt driven and so it is necessary to disable interrupts upon a reception event and reenable interrupts after processing them.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">while (1)\n{\n    uint8_t ReceiveError = 0;\n    uint8_t SendError = 0;\n\n    ADC_Count = ADC12_A_getResults(ADC12_A_BASE, ADC12_A_MEMORY_0);\n\n    tmp = (((float)ADC_Count * 1.5) \/ 4095.0);\n    temp = ((tmp - 0.688) \/ 0.00252);\n\n    print_C(6, 1, temp);\n\n    switch (USB_getConnectionState())\n    {\n        case ST_ENUM_ACTIVE:\n        {\n            __disable_interrupt();\n            if (!USBCDC_getBytesInUSBBuffer(CDC0_INTFNUM))\n            {\n                __bis_SR_register(LPM0_bits + GIE);\n            }\n\n            __enable_interrupt();\n\n            if (bCDCDataReceived_event)\n            {\n                bCDCDataReceived_event = FALSE;\n\t\n                count = USBCDC_receiveDataInBuffer((uint8_t*)dataBuffer,\n                                                    RX_BUFFER_SIZE,\n                                                    CDC0_INTFNUM);\n                LCD_goto(15, 1);\n                LCD_putstr(dataBuffer);\n            }\n\n            tc[0] = ((temp \/ 10) + 0x30);\n            tc[1] = ((temp % 10) + 0x30);\n\n            if(USBCDC_sendDataInBackground((uint8_t*)tc, \n                                            TX_BUFFER_SIZE,\n                                            CDC0_INTFNUM,\n                                            1))\n            {\n                SendError = 0x01;\n                break;\n            }\n\n            break;\n\n        }\n        case ST_PHYS_DISCONNECTED:\n        case ST_ENUM_SUSPENDED:\n        case ST_PHYS_CONNECTED_NOENUM_SUSP:\n             __bis_SR_register(LPM3_bits + GIE);\n             NOP();\n             break;\n\n        case ST_ENUM_IN_PROGRESS:\n        default:;\n    }\n\n    if (ReceiveError || SendError)\n    {\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Out of the all the jargon, the following codes are what that we need to receive and transmit data respectively. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">USBCDC_receiveDataInBuffer((uint8_t*)dataBuffer, RX_BUFFER_SIZE, CDC0_INTFNUM);\n\nUSBCDC_sendDataInBackground((uint8_t*)tc, TX_BUFFER_SIZE, CDC0_INTFNUM, 1))<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The receive function reads received data from <em>CDC0_INTFNUM<\/em>\nbuffer. This is simply a buffer location that acts bidirectionally. We have to\nmention the array to which received data needs to be transferred. We also have\nto mention the size of this array. The transmit function is almost the same as\nthe receive function. Note that all data transactions are done in chunks of\nbytes. For the sake of simplicity, errors and other USB states are not used.\nHowever, when developing a good real-life USB device these should not be\nignored.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Since it is a USB example, our MSP430 launchpad board needs to be connected\nwith a host PC. Note that no driver installation would be needed for this COM\nport device as it is a virtual\/non-physical COM port and the port number can be\nany port number.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We\u2019ll need a port monitoring terminal software like the Eltima\nSoft\u2019s Serial Port Monitor. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The demo here works by sending out on-chip temperature sensor\u2019s reading when a keyboard key of the host PC is pressed. The key that was pressed is echoed back. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"448\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-CDC-1024x448.jpg\" alt=\"\" class=\"wp-image-14699\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-CDC-1024x448.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-CDC-580x254.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-CDC-768x336.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-CDC.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-CDC-1-1024x576.png\" alt=\"\" class=\"wp-image-14700\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-CDC-1-1024x576.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-CDC-1-580x326.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-CDC-1-768x432.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-CDC-1.png 1366w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/0HfwllD4ig0?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">USB HID<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Most of the common devices like keyboards, mice, printers, scanners, barcode readers, gamepads, etc that we use with our PCs and laptops in regular life are USB HID devices. We can use our MSP430F5529 microcontroller to make USB HID devices and in this example, we will use our MSP430 microcontroller to make a rudimentary mouse. Unlike conventional mice, our mouse will be using a keypad joystick instead of optoelectronics or mechanical trackball.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"457\" height=\"457\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/xiaomi-mi-portable-mouse-silver-01_14582_1479118812.jpg\" alt=\"\" class=\"wp-image-14701\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/xiaomi-mi-portable-mouse-silver-01_14582_1479118812.jpg 457w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/xiaomi-mi-portable-mouse-silver-01_14582_1479118812-150x150.jpg 150w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/xiaomi-mi-portable-mouse-silver-01_14582_1479118812-90x90.jpg 90w\" sizes=\"auto, (max-width: 457px) 100vw, 457px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Code Example<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"driverlib.h\"\n#include \"delay.h\"\n#include \"lcd.h\"\n#include \"lcd_print.h\"\n\n#include \"USB_config\/descriptors.h\"\n#include \"USB_API\/USB_Common\/device.h\"\n#include \"USB_API\/USB_Common\/usb.h\"\n#include \"USB_API\/USB_HID_API\/UsbHid.h\"\n\n#include \"hal.h\"\n\n#define LED_PORT            GPIO_PORT_P4\n#define LED_PIN             GPIO_PIN7\n\n#define MOUSE_PORT          GPIO_PORT_P6\n#define MOUSE_UP_PIN        GPIO_PIN0\n#define MOUSE_DOWN_PIN      GPIO_PIN1\n#define MOUSE_LEFT_PIN      GPIO_PIN2\n#define MOUSE_RIGHT_PIN     GPIO_PIN3\n#define MOUSE_BUTTON_PIN    GPIO_PIN4\n\n#define change_amount       1\n\ntypedef struct\n{\n    int8_t buttons;\n    int8_t dX;\n    int8_t dY;\n    int8_t dZ;\n}MOUSE_REPORT;\n\nMOUSE_REPORT mouseReport = {0x00, 0x00, 0x00, 0x00};\n\nvoid DIO_init(void);\n\n#pragma vector = UNMI_VECTOR\n__interrupt void UNMI_ISR (void)\n{\n    switch (__even_in_range(SYSUNIV, SYSUNIV_BUSIFG ))\n    {\n        case SYSUNIV_NONE:\n        {\n            __no_operation();\n            break;\n        }\n\n        case SYSUNIV_NMIIFG:\n        {\n            __no_operation();\n            break;\n        }\n\n        case SYSUNIV_OFIFG:\n        {\n            UCS_clearFaultFlag(UCS_XT2OFFG);\n            UCS_clearFaultFlag(UCS_DCOFFG);\n            SFR_clearInterrupt(SFR_OSCILLATOR_FAULT_INTERRUPT);\n            break;\n        }\n\n        case SYSUNIV_ACCVIFG:\n        {\n            __no_operation();\n            break;\n        }\n        case SYSUNIV_BUSIFG:\n        {\n            SYSBERRIV = 0;\n            USB_disable();\n        }\n    }\n}\n\nvoid main (void)\n{\n    unsigned char t = 0x0000;\n\n    WDT_A_hold(WDT_A_BASE);\n\n    LCD_init();\n    LCD_clear_home();\n\n    LCD_goto(1, 0);\n    LCD_putstr(\"MSP430 USB HID\");\n\n    LCD_goto(0, 1);\n    LCD_putstr(\"X: \");\n\n    LCD_goto(6, 1);\n    LCD_putstr(\"Y:\");\n\n    LCD_goto(12, 1);\n    LCD_putstr(\"B:\");\n\n    PMM_setVCore(PMM_CORE_LEVEL_2);\n    USBHAL_initPorts();\n    USBHAL_initClocks(8000000);\n    USB_setup(TRUE, TRUE);\n\n    DIO_init();\n\n    __enable_interrupt();\n\n    while (1)\n    {\n        if(GPIO_getInputPinValue(MOUSE_PORT,\n                                 MOUSE_UP_PIN) == false)\n        {\n            mouseReport.dY += change_amount;\n        }\n\n        if(GPIO_getInputPinValue(MOUSE_PORT,\n                                 MOUSE_DOWN_PIN) == false)\n        {\n            mouseReport.dY -= change_amount;\n        }\n\n        if(mouseReport.dY &gt; 127)\n        {\n            mouseReport.dY = 127;\n        }\n\n        if(mouseReport.dY  127)\n        {\n            mouseReport.dX = 127;\n        }\n\n        if(mouseReport.dX  40)\n        {\n            t = 0;\n            mouseReport.dX = 0;\n            mouseReport.dY = 0;\n            mouseReport.buttons = 0;\n        }\n    }\n}\n\n\nvoid DIO_init(void)\n{\n    GPIO_setAsInputPinWithPullUpResistor(MOUSE_PORT,\n                                         MOUSE_UP_PIN);\n\n    GPIO_setAsInputPinWithPullUpResistor(MOUSE_PORT,\n                                         MOUSE_DOWN_PIN);\n\n    GPIO_setAsInputPinWithPullUpResistor(MOUSE_PORT,\n                                         MOUSE_LEFT_PIN);\n\n    GPIO_setAsInputPinWithPullUpResistor(MOUSE_PORT,\n                                         MOUSE_RIGHT_PIN);\n\n    GPIO_setAsInputPinWithPullUpResistor(MOUSE_PORT,\n                                         MOUSE_BUTTON_PIN);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hardware Setup<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"575\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-HID-1024x575.png\" alt=\"\" class=\"wp-image-14702\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-HID-1024x575.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-HID-580x326.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-HID-768x431.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-HID.png 1327w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Just like the past example, again we are interested in the main loop as everything is done here. On each press of joystick buttons <em>x<\/em> and <em>y<\/em> coordinates are changed by 1 unit. We are not using mouse coordinate acceleration as with any regular mouse and that is why the change amount is 1 unit only. On PC screen, the mouse cursor will appear to move slowly as if the PC is busy doing some other works. We are also assuming that the <em>x <\/em>and <em>y<\/em> coordinate boundaries range from -127 to +127 units. In the code, we have to take care that these extremes are not exceeded. We are not using typical mouse click buttons although I coded the joystick middle button for clicking. This is not very important here as mouse cursor movement is all that is needed for USB HID demo. In the <em>ST_ENUM_ACTIVE<\/em> case, the location of cursor and button state are reported to host PC. The PC then uses these to change the position of the mouse cursor.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">while (1)\n{\n    if(GPIO_getInputPinValue(MOUSE_PORT, MOUSE_UP_PIN) == false)\n    {\n        mouseReport.dY += change_amount;\n    }\n\n    if(GPIO_getInputPinValue(MOUSE_PORT, MOUSE_DOWN_PIN) == false)\n    {\n        mouseReport.dY -= change_amount;\n    }\n   \n    if(mouseReport.dY &gt; 127)\n    {\n        mouseReport.dY = 127;\n    }\n\n    if(mouseReport.dY  127)\n    {\n        mouseReport.dX = 127;\n    }\n\n    if(mouseReport.dX  40)\n     {\n         t = 0;\n         mouseReport.dX = 0;\n         mouseReport.dY = 0;\n         mouseReport.buttons = 0;\n      }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For 40 times, the mouse\u2019s coordinate changes and button states are not reset automatically and this is so because we don\u2019t want to keep holding the joystick buttons for movement once our desired speed is achieved. Remember no acceleration is used. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"363\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-HID-1024x363.jpg\" alt=\"\" class=\"wp-image-14703\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-HID-1024x363.jpg 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-HID-580x205.jpg 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-HID-768x272.jpg 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2020\/01\/USB-HID.jpg 1369w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/JdS_LfKBhjk?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Epilogue<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">My journey with MSP430F5529 has been a mixture of\nsuccess and failure. It is successful in terms of being able to apply driverlib\nsuccessfully while being able to master a mid-range high performance TI\nmicrocontroller. Most of the hardware is similar to other MSP430 micros and so\nI had little or no issues understanding them. This is for the first time I got\nto get myself introduced with a TI micro that has USB hardware as well as other\nadvanced hardware like DMA, RTC, hardware multiplier, etc that are typically\nfound in ARM microcontrollers. Previously, I have seen similar microcontrollers\nlike PIC18F4550 and ATMega32U4 but none of them were as rich as MSP430F5529\nwhen it comes to both hardware and software suites. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The failure part is the time it took for me to get\nall these things together because on the internet I didn\u2019t find much support\nfor most of the stuffs I needed to know quickly. I had to read lot of docs and\ntry out several things before I could make a solid conclusion. However, after\ncompleting this tutorial doc, I believe no one will have issues as I had. I\nalso believe that it will pave way for developing stuffs with TI\u2019s Tiva C ARM\nmicrocontrollers as working with Tiva micros need knowledge of TivaWare \u2013 a\nsoftware suite from TI that is similar to MSP430Ware. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To summarize, this MSP430 beast packs a good punch that can help us avoid investing on an ARM overkill or on other expensive platforms. It has everything to make devices like a datalogger, a USB power meter, an advanced MPPT solar charge controller, a balancing robot, etc. In fact, in my professional career, I have seen several control systems that host TI microcontrollers like the MSP430F5529. MSP430F5529 is like an ARM micro in 16-bit disguise. I would strongly urge readers to explore this microcontroller family and beyond. Last but not least, TI microcontroller portfolio has microcontrollers for various application-specific purpose but compared to other manufacturers TI\u2019s microcontrollers are smart and well-designed in terms of hardware management. TI also manufactures other digital and analogue components. This allows us to design a complete board with all-TI components while making TI a good component partner.\u00a0\u00a0  <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The PDF version of this post and the code examples can be found <a href=\"https:\/\/github.com\/sshahryiar\/MSP430F5529LP-Tutorial\">here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In my past tutorials on MSP430s, I demonstrated how to get started with MSP430 general purpose microcontrollers from Texas Instruments (TI). Those tutorials covered most aspects of low and mid-end MSP430G2xxx series microcontrollers. For those tutorials, TI\u2019s official software suite \u2013 Code Composer Studio (CCS) \u2013 an Eclipse-based IDE and GRACE \u2013 a graphical peripheral initialization and configuration tool similar to STM32CubeMX were used. To me, those low and mid-end TIs chips are cool and offer best resources one can expect at affordable prices and small physical form-factors. I also briefly discussed about advanced MSP430 microcontrollers and the software resources<\/p>\n","protected":false},"author":5,"featured_media":14524,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[29,367,379,933,955,1466],"tags":[473,384,773,1742,1741,326,1415,346,324,1719],"class_list":["post-14523","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-embedded-lessons","category-mcu-develeopment-tools","category-msp430-launchpad","category-texas-instruments","category-ti-2","category-tutorials","tag-launchpad","tag-launchpad-kit","tag-msp430","tag-msp430-launchpad","tag-msp430f5529","tag-msp430f5529-usb","tag-texas-instruments","tag-ti","tag-ti-msp","tag-ti-msp430-microcontrollers"],"_links":{"self":[{"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/posts\/14523","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/comments?post=14523"}],"version-history":[{"count":37,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/posts\/14523\/revisions"}],"predecessor-version":[{"id":15407,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/posts\/14523\/revisions\/15407"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/media\/14524"}],"wp:attachment":[{"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/media?parent=14523"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/categories?post=14523"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/tags?post=14523"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}