www.cypress.com -
www.cypress.com -
by Robert Ashby
Copyrights
Copyrights
© Cypress Semiconductor Corporation, 2010. The information contained herein is subject to change without notice. Cypress
Semiconductor Corporation assumes no responsibility for the use of any circuitry other than circuitry embodied in a Cypress
product. Nor does it convey or imply any license under patent or other rights. Cypress products are not warranted nor
intended to be used for medical, life support, life saving, critical control or safety applications, unless pursuant to an express
written agreement with Cypress. Furthermore, Cypress does not authorize its products for use as critical components in life-
support systems where a malfunction or failure may reasonably be expected to result in significant injury to the user. The
inclusion of Cypress products in life-support systems application implies that the manufacturer assumes all risk of such use
and in doing so indemnifies Cypress against all charges.
Trademarks
PSoC Creator™ is a trademark and PSoC® and CapSense® are registered trademarks of Cypress Semiconductor Corp. All
other trademarks or registered trademarks referenced herein are property of the respective corporations.
Source Code
Any Source Code (software and/or firmware) is owned by Cypress Semiconductor Corporation (Cypress) and is protected by
and subject to worldwide patent protection (United States and foreign), United States copyright laws and international treaty
provisions. Cypress hereby grants to licensee a personal, non-exclusive, non-transferable license to copy, use, modify, create
derivative works of, and compile the Cypress Source Code and derivative works for the sole purpose of creating custom soft-
ware and or firmware in support of licensee product to be used only in conjunction with a Cypress integrated circuit as speci-
fied in the applicable agreement. Any reproduction, modification, translation, compilation, or representation of this Source
Code except as specified above is prohibited without the express written permission of Cypress.
Disclaimer
CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH REGARD TO THIS MATERIAL,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PAR-
TICULAR PURPOSE. Cypress reserves the right to make changes without further notice to the materials described herein.
Cypress does not assume any liability arising out of the application or use of any product or circuit described herein. Cypress
does not authorize its products for use as critical components in life-support systems where a malfunction or failure may rea-
sonably be expected to result in significant injury to the user. The inclusion of Cypress' product in a life-support systems appli-
cation implies that the manufacturer assumes all risk of such use and in doing so indemnifies Cypress against all charges.
Use may be limited by and subject to the applicable Cypress software license agreement.
2. CY8C38xxx Introduction 15
2.1 CY8C38xxx................................................................................................................15
2.2 DVK1 Board...............................................................................................................17
2.3 PSoC Creator™.........................................................................................................18
2.3.1 Workspace Explorer .......................................................................................19
2.3.2 Design-Wide Resources ................................................................................21
2.3.3 Schematic View..............................................................................................21
2.3.4 Source Files and Header Files.......................................................................22
2.4 Example Designs.......................................................................................................22
Index 105
Blink an LED
Project 1
Set up timing structure and set up basic signal input and output.
UART
Project 2 Set up a link between your project and the computer. Use the computer as an input and out-
put tool to enhance and debug your project.
CapSense®
Project 3
Add CapSense buttons and a slider to your project.
Digital Logic
Project 4
Create a PSoC simulation of the farmer, fox, goose, corn riddle.
Precision Analog
Project 5
Add simple analog processing to your project.
The designs selected for this book provide you with a working foundation. Each project builds upon
the knowledge you learn from the previous project. By the time you finish the Project 5, you will know
about the PSoC CY8C38xxx core, its digital peripheral capabilities, and its analog capabilities. Each
completed project includes interfaces to user input, display, and computer communication. You will
have created an entire system using a single chip and will realize how easy it is to complete these
designs. The Cypress system is perfect for the hobbyist, student, and engineer. The design process
is easy enough for a beginner with minimal experience, and powerful enough to stretch the imagina-
tion of the most seasoned engineer.
Before discussing a few of the features for the PSoC 3 and PSoC 5 architectures, there is a brief
explanation of Microcontroller Basics on page 6. If you have a good working knowledge of microcon-
trollers, you can skip the section.
1.2.2 Memories
The memories in a microcontroller contain both data and instructions. Some microcontrollers, includ-
ing the PSoC 3 and PSoC 5 devices, can interface with memory that is contained in separate
devices. Memories come in two broad categories; volatile and nonvolatile. Volatile memory loses its
contents when power is removed. Nonvolatile memory retains its contents even when power is
removed. In general, volatile memories are much faster than nonvolatile memories. Another differ-
ence between volatile and nonvolatile memories is that all nonvolatile memories wear out. They can
only be erased an rewritten a limited number of times. The endurance value of a nonvolatile memory
is the number of times that it can be erased and programmed without error.
There are three memory types in the PSoC 3 and PSoC 5 architecture: flash, electrically erasable
programmable read only memory (EEPROM), and random access memory (RAM). Flash and
EEPROM are two types of nonvolatile memory. RAM is volatile. Some PSoC 3 and PSoC 5 devices
also have an extended memory interface (EMIF) that allows you to add additional memory to the
device if you need to.
Flash memory is your program memory. You might hear it referred to as read only memory (ROM)
because it holds your program memory. However, you can erase and reprogram flash memory. An
important characteristic of flash memory is that it must be erased in blocks. You cannot erase a sin-
gle byte at a time. This might be seen as a disadvantage compared to other nonvolatile memories if
you are storing small amounts of data. Flash data also has a lower endurance value than some other
types of nonvolatile memory. Wear leveling is a technique that writes the small amounts of data over
several areas in succession to increase the amount of times that you can rewrite the data without
damaging the flash memory.
EEPROM is also nonvolatile memory. You can erase and rewrite information on a byte-by-byte basis
to EEPROM. The endurance value of EEPROM is much higher than flash. This makes EEPROM
ideal for storing nonvolatile information that needs frequent updates and especially for smaller
amounts of information.
RAM memory holds data during program execution. It is possible in some microcontrollers, including
the PSoC 5 architecture, to copy program memory into RAM and execute that program memory
while still in RAM. The important characteristics to remember about RAM are that you can change its
contents as often as you like and that you can read from and write to RAM very quickly. The endur-
ance value of RAM is high enough that this should not be a concern. RAM is a volatile memory
meaning it does not retain its information during a power loss. There are some newer technologies
that provide nonvolatile storage for RAM, but they are not discussed here.
Note The acronyms RAM and ROM are legacy terms that persist today. The names were given to
early devices and reflect the abilities of that memory at that time. However, the evolution of micro-
controller design has improved the memories. The limitations described by the names are often
defunct. RAM is not the only memory that can be accessed in a random order and not all ROM mem-
ory is read only.
1.2.3 Peripherals
The peripherals in a microcontroller are functions that are performed by the device. Common periph-
erals include I/O ports, analog to digital converters (ADCs), universal asynchronous receiver trans-
mitters (UARTs), timers, pulse width modulators (PWMs), generators, and many others. Peripheral
functionality built within the microcontroller distinguishes a microcontroller from a microprocessor. A
microprocessor (such as the one found in your computer) does not typically include these peripheral
functions, but instead communicates with separate devices that implement the peripheral functions.
A microcontroller contains CPU, memories, and peripherals to create an embedded system.
ories, and other peripherals in the PSoC. The AHB allows transfers that range from 16 bits to 32 bits
wide, accommodating both the 8 bit and 32 bit CPU options. All transfers on the AHB are initiated by
the CPU or PHUB. The PHUB contains the direct memory access (DMA) controller, allowing the
PHUB to manage transfers of data without any need for CPU interaction. The hub configuration of
the PSoC 3 and PSoC 5 architecture offers some very significant advantages. The separation of the
spokes and the multiple channels of the DMA controller allow simultaneous transfers among devices
on different spokes. This allows for efficient and speedy transfers of data.
The analog system of the PSoC 3 and PSoC 5 architectures features very high precision because of
a very low noise floor and a very accurate reference level. I have not seen the analog capabilities of
the PSoC 3 and PSoC 5 architectures duplicated or matched in any microcontroller, field program-
mable gate array (FPGA), or any other standard device. Embedded systems need analog interfaces
to connect to the outside world. Reading temperatures, playing music, controlling liquid crystal dis-
plays (LCDs), or reading touch pads all require analog processing. The processing of these analog
systems needs more than a simple ADC. These projects require gain stages, filtering, analog output
signals, and special sensing circuitry. The PSoC 3 and PSoC 5 architectures provide this capability
in a single chip.
The analog system includes a sigma delta ADC that is capable of 20 bits of resolution and very fast
conversion times. A full 20 bits of resolution is fantastic. In a 3.3V system, this means that the ADC
reads changes in a signal as small as three millionths of a volt. An ADC with this type of accuracy
depends heavily upon the precision reference and the low noise floor. The noise floor is kept very
low by separating the analog power system from the digital system with the PSoC device itself.
Power and ground can connect together at the same pin on some devices, but they separate at the
bonding pin inside the chip. The internal reference swings less than 0.2% through the device’s volt-
age and temperature range.
The digital filter block (DFB) collects data from the ADC block. The DFB is a small digital signal pro-
cessing (DSP) engine that operates independently from the CPU. The DFB has its own arithmetic
logic unit (ALU), its own hardware multiplier, and its own RAM. The DFB is configured as a single 64
tap filter or as multiple filters with fewer taps, (for example, 4 filters with 16 taps each).
The PSoC 3 and PSoC 5 architectures include uncommitted operational amplifiers, switched cap/
continuous time (SC/CT) blocks, and comparators. All of the blocks, including the SC/CT blocks,
have an operational amplifier inside.
Note I have seen the term switched cap raise uncertainty and quizzical looks. The concept of a
switched cap analog system is to use capacitors and analog switches to transfer charge in a system.
The combination of the switch system and the capacitor acts similarly to a resistor allowing change-
able flexible analog designs.
The uncommitted operational amplifiers are usually configured as unity gain buffers. They can also
route their input and output pins to GPIO, allowing you to add your own components to construct
gain stages, filters, oscillators, and so on. The SC/CT blocks have resistors, capacitors, and
switches that allow you to build gain stages, filters, differential amplifiers, and so on.
The digital to analog converter (DAC) of the PSoC 3 and PSoC 5 architectures operates as either a
voltage DAC or a current DAC. It is the means by which you send the DFB output back out to the
analog domain.
The universal digital blocks (UDBs) are the key to the flexible digital system in the PSoC 3 and
PSoC 5 architectures. The UDB does not stand alone as an entity, but is part of a larger array that
holds all the UDBs in the system. This array structure allows the UDB to interact with other UDB
blocks before consuming resources in the digital systems interface (DSI). The DSI is the connection
that allows the UDB to send and receive signals from the I/O and other fixed function peripherals in
the chip.
The UDB contains two programmable logic devices (PLDs), a datapath module, and some control
and timing logic (see Figure 1-1).
Figure 1-1. UDB Block Diagram
PLD
Chaining
PLD PLD
Clock 12C4 12C4
and Reset (8 PTs) (8 PTs)
Control
Status and
Control Datapath
Datapath
Chaining
Routing Channel
Each PLD is a logic array that accepts 12 inputs into a group of eight product terms (AND function).
These product terms are summed (OR function) to provide a 4-bit-wide result. The use of PLD logic
does not always have to link to the datapath module within that UDB. It can use other UDBs sepa-
rate from the datapath module in its own UDB. An example of this situation is if the UDB is config-
ured to be an 8-bit timer, then the PLDs are not used for that functionality. In that case, those PLDs
are used for other functions if desired. This allows you to fully use all (some limitations exist) the
logic in the UDB array.
PT0
PT1
PT2
PT3
PT4
PT5
PT6
PT7
IN0 TC TC TC TC TC TC TC TC
IN1 TC TC TC TC TC TC TC TC
IN2 TC TC TC TC TC TC TC TC
IN3 TC TC TC TC TC TC TC TC
IN4 TC TC TC TC TC TC TC TC
IN5 TC TC TC TC TC TC TC TC AND
IN6 TC TC TC TC TC TC TC TC Array
IN7 TC TC TC TC TC TC TC TC
IN8 TC TC TC TC TC TC TC TC
IN9 TC TC TC TC TC TC TC TC
IN10 TC TC TC TC TC TC TC TC
IN11 TC TC TC TC TC TC TC TC
SELIN
(carry in)
OUT0 MC0 T T T T T T T T
OUT1 MC1 T T T T T T T T
OUT2 MC2 T T T T T T T T
OUT3 MC3 T T T T T T T T
SELOUT
(carry out) OR
Array
The datapath is a collection of logic that is optimized to perform functions such as PWMs, timers,
integrators, counters, cyclic redundancy check (CRC) calculations, and pseudo random sequence
(PRS) generation. The datapath implements an arithmetic logic unit (ALU). The ALU can increment,
decrement, AND, OR, XOR, add, and subtract. The datapath is also able to shift data and perform a
nibble swap. The datapath has six registers that feed into the ALU: two accumulators A0 and A1, two
data registers D0 and D1, and two first in and first out (FIFOs) F0 and F1. The FIFO registers are the
link between the ALU and the system interface.
The datapath is reconfigured cycle by cycle with an eight word by 16 bit configuration RAM. Chang-
ing the address inputs to this RAM alters the sequence of datapath operation. This ability allows the
UDB to perform what Cypress calls time multiplexing. By using the registers and toggling the func-
tion of the datapath from one set of registers to another, you can perform 16-bit functions with one
(8-bit) datapath.
F1
FIFOs
Conditions: 2 Compares,
Input Output
Programmable A1 Programmable
Routing 6 6 Routing
D1 D0
D1
Data Registers
D0
To/From To/From
Previous Chaining Next
Datapath Datapath
A1
Accumulators
A0
PI
Parallel Input/Output
(to/from Programmable Routing)
PO
ALU
Shift
Mask
The UDBs are arranged in a row and column format referred to as the UDB array. This allows an effi-
cient means of signal routing between UDBs. Each UDB is paired with another UDB in the same col-
umn. There are 64 I/O lines between these two blocks. These I/O lines connect to the horizontal
channel routes. There are 96 lines in each horizontal channel route. A switch mechanism toggles the
signals from the horizontal channel route to the vertical channel route. There are 32 lines in each
vertical channel route. The vertical channel routes extend beyond the UDBs to connect to the digital
system interface.
Function I/O
Controller
Controller
I/O Ports
Interrupt
Fixed
DMA
DSI Routing Interface
HV HV HV HV
A B A B
HV HV HV HV
B A B A
I/O Ports
Controller
Interrupt
Controller
DMA
The PSoC 3 and PSoC 5 architectures also include other fixed functions including controller area
network (CAN) bus and USB. This platform offers dramatic improvements to existing designs and
exciting opportunities for new designs that were not previously possible.
1.4 Conventions
These conventions are used throughout this guide.
2.1 CY8C38xxx
The CY8C38xxx family is built on the PSoC® 3 architecture. The CY8C38xxx devices have an 8-bit
8051 CPU that runs up to 67 MHz. Most instructions take only one or two cycles to complete. The
popularity of the 8051 provides a familiar environment for many experienced programmers. There
are many existing compilers for the 8051 and many free tools and existing code on the Internet that
were designed for the 8051 and can be used for your CY8C38xxx design.
The 8051 in the CY8C38xxx has enhancements and extra features that were not in the original 8051
design. These include an enhanced interrupt controller, instruction cache, and extra pointers. The
enhancements and features allow the 8051 in the CY8C38xxx devices to run faster, with less power,
and reduce your code size compared to the original 8051.
The CY8C38xxx has a single sigma delta ADC. The ADC is capable of a maximum 20 bits of resolu-
tion while maintaining a 110 dB signal to noise ratio. Higher resolution requires longer sampling time.
A conversion of 20-bit resolution can be completed 180 times in a second. Lower resolution conver-
sion happens much faster. A 16-bit conversion can be completed 48 thousand times per second.
Conversions can be started by a software instruction or by the assertion of a Start of Conversion
hardware signal that can be triggered from an external source.
There are various modes for the ADC that allow you to capture a single signal, or several different
signals. The DMA controller allows you to automatically transfer the results of the conversions to the
DFB for filtering. The CY8C38xxx offers a single DFB, but that single DFB can be used to construct
multiple filters.
The CY8C38xxx has up to four of each of the following:
■ Comparators
■ Uncommitted opamps
■ SC/CT blocks
■ Voltage/current DACs
These are configurable to provide various components for pure analog processing without processor
intervention.
The CY8C38xxx offers up to 24 UDBs. The UDBs are configured automatically when you use the
associated components in PSoC Creator™. However, you can also create your own components
using Verilog to configure the digital logic of the UDBs.
The CY8C38xxx features a USB controller and a CAN controller. The USB transceiver provides a
full-speed USB peripheral connection with up to eight endpoints. Configuration of the USB trans-
ceiver is made much easier with a USB wizard tool included in PSoC Creator. The CAN controller
supports the CAN 2.0 protocol and handles all low-level tasks of the CAN transmission including
message separation, CRC checking, CRC calculation, and message buffering.
The CY8C38xxx has up to 62 general purpose input/output (GPIO) pins, eight special input/output
(SIO) pins, and two USB pins.
The GPIO on the CY8C38xxx allows you to route functions to almost any pin on the device. The
GPIO pins can operate as a digital input, analog input, or digital output. Each GPIO pin can operate
with internal pull up or pull down resistors. They also can operate in a open drain (drive high or drive
low) mode. All pin routing for GPIO functionality is done internally which gives you the ability to lay
out your printed circuit board (PCB) to maximize size, power, and noise immunity with unprece-
dented freedom.
Changing between the different modes of the GPIO pins requires changing values in several regis-
ters. The CY8C38xxx allows a special addressing scheme to write to multiple port configuration reg-
isters in a single write to change the mode of a single pin. This prevents any unwanted intermediate
states that can exist between register writes.
The CY8C38xxx allows GPIO pins to be configured to drive LCD glass directly. LCDs are con-
structed of polarized glass and a liquid crystal layer that is controlled with a voltage to allow or disal-
low light to pass through the filtered glass. The display is changed by placing a voltage potential
across the liquid crystal. When a voltage is placed across the liquid crystal layer, the crystal twists.
This stops light from being seen through that portion of glass. Pretty basic don't you think? The trick
comes in timing and voltage levels. In order to prevent the crystal material from being permanently
twisted, the average voltage across it must be zero. Every element (pixel) on the glass that needs to
be controlled separately requires a method to control that area individually. Pixels are mapped into
groups of rows and columns.
An LCD driver is responsible for applying the voltages to the rows and columns in such a way to
apply voltages to the liquid crystal for the pixels that you want to be on and keep the voltage neutral
on the pixels that you want to be off. At all times it must maintain an average voltage of zero across
all pixels or the LCD can be damaged and stay on. This process requires several voltage levels in
order to work correctly. The voltage levels are different for the rows compared to the voltage levels
for the columns. The rows in our driving circuitry will be referred to as segments and the columns are
referred to as commons. The CY8C38xxx uses a digital to analog converter (DAC) to produce up to
six different voltage levels that generate these voltage waveforms.
Figure 2-1 shows waveforms for two modes of operation with a CY8C38xxx. The LCD drive voltage
level represents the columns or commons. The display data represents a single row or segment. As
you can see, Type A achieves an average of 0 volts across both the segment that is on and the seg-
ments that are off. Note that the off segments still experience a small change in voltage up and down
as the LCD drive voltage level is moving. This voltage level is too small to actually turn on the LCD.
Figure 2-1. A Typical LCD Voltage Waveform
*1:4 Multiplex
Ratio
Type A 1/3 Bias Type B
(2x Type A Data Clock)
LCD Drive
Voltage Level
Display
Data
The CY8C38xxx uses a UDB to generate the clocking signals necessary to switch voltage levels
from the DAC and the segment pins as needed. The UDB also initiates the DMA transactions that
move data from the Display RAM area into the LCD driver block so that they can be sent to the
appropriate I/O pins.
Figure 2-2. LCD Configuration Block Diagram
LCD DAC
Global
Clock
UDB
Pin
Display
DMA
RAM
PHUB
■ Second, you need to configure the fixed function and configurable analog and digital resources
within the PSoC.
■ Third, you need to write the firmware associated with your project.
PSoC Creator helps you complete these three steps. The process is very simple and will become
second nature to you very quickly. Changes can be made to the design at any time to any of the
three areas. When you generate and compile the project, PSoC Creator will integrate the latest
changes into the completed output file. Navigation through the different areas of your design is made
very simple with Workspace Explorer.
The Components tab shows your schematic as the only component by default. You can add addi-
tional components as needed. Components include source files, symbols, and Verilog files. You can
create your own design and then export that design as a component for easy implementation in
future designs.
The Results tab shows a tree view of files generated during the compilation of the project. It includes
important information such as use of analog and digital resources within the device, mapping files,
and the programmable output file.
Figure 2-6. The Workspace Explorer Results Tab
10.Click OK.
PSoC Creator generates the associated directories and files needed for your project and opens into
schematic view (see Figure 3-2). Schematic view gives the overall picture of the components you
have selected for your project and how they are connected to other components. You should see
Workspace Explorer to the left of your schematic, the Component Catalog to the right of your
schematic, and the Output window below your schematic. If you do not see all three of these win-
dows, click the View menu and choose the missing window from the menu.
Figure 3-2. Schematic View
The Data Sheet button in the Configure dialog opens the data sheet associated with that compo-
nent. The data sheet for any component can also be easily opened by right clicking on the compo-
nent in schematic view and selecting the data sheet from the menu. The data sheet describes the
functionality of the component including available connections and parameters of the component.
The data sheet also includes example source code for that component.
4. Double click the PWM component to open the Configure dialog (Figure 3-5).
Figure 3-5. PWM_Timer Configuration
The PWM_Timer needs an additional logic signal that I want to define rather than route to an exter-
nal I/O pin. The state of this signal is not going to change during our design.
1. From the Digital Logic group, drag an instance of the Logic Low ‘0’ component onto your design.
2. Connect the Logic Low ‘0’ component to the reset terminal of the PWM_Timer.
Your schematic should now look like Figure 3-8.
Figure 3-8. PWM_Pin Connection
1. Errors, Warnings, and Notes are shown in the Notice list. Select View > Other Windows >
Notice List to make sure that you do not have any errors.
If you have any errors go back and review the previous steps to see if you missed something.
2. Verify that the connections between components in your schematic do not overlap and are con-
nected properly.
3. Add an Interrupt component from the Systems group in the Component Catalog.
4. Connect its terminal to the interrupt terminal of the PWM_Timer component. Previously you set
this terminal to generate a signal on terminal count.
5. Rename this component to isr_PWM.
6. Add another Digital Output Pin component from the Ports and Pins group to your design.
7. Double click the pin component and change the Name to LED_Pin.
8. This time the pin is going to be software controlled, so deselect the HW Connection setting on
the Pins Type subtab. As before, the remaining defaults are sufficient to drive an LED.
9. Add a Digital Input Pin component to your design.
This pin is going to be connected to a switch on the DVK1.
10.Rename this component to Button_Pin.
11. On the General subtab of the Pins tab change the Drive Mode to Resistive Pull Up.
12.Set the Initial State to High (1). When you press the button, the pin is grounded and the state
goes low.
Your schematic should now look like Figure 3-9 on page 30.
3.3.5 Code
PSoC Creator generates much of the code needed for this project. Open main.c by double clicking
the main.c icon under Source Files folder in the Workspace Explorer. The code needed in the
main.c file is quite concise for our simple project and is included in its entirety.
The first task to be completed upon entering main() is to call the start functions for the different com-
ponents that we have added. The start functions route power to those components and enable their
functionality. The parameters for each component's functions are found in the data sheet for that
component. After initializing the components the main code enters an endless loop that checks flags
to see if a given amount of time has expired since the last iteration of the loop. If the given amount of
time has expired, the endless loop executes the appropriate portion of code and returns to checking
the other time intervals. A simple flow chart depicting this operation is included in Figure 3-11 on
page 32.
Main() Entry
Initialization of
Components
#include <device.h>
#include "timing.h"
void ToggleLed(void);
/*******************************************************************************
* Function Name: main()
********************************************************************************
* Summary:
* Contains initialization for different components and main loop
*
* Parameters:
* none
*
* Return:
* none
*
*****************************************************************************/
void main()
{
/* Components should be initialized in the following order:
* 1. interrupts
* 2. sources of interrupts (clocks are auto-initialized)
* 3. global interrupt enable
*/
InitTiming(); /* interrupt */
PWM_Timer_Start(); /* source of interrupt */
CYGlobalIntEnable /* macro */
/* Toggle the LED if the button is NOT pressed. This will cause
* the LED to blink rapidly when the button is NOT pressed.
*/
if(Button_Pin_Read()) /* read a 1 when button is NOT pressed */
{
ToggleLed();
}
} /* end of tenth second section */
/*******************************************************************************
* Function Name: ToggleLed()
********************************************************************************
* Summary:
* Toggles the LED
*
* Parameters:
* none
*
* Return:
* none
*******************************************************************************/
void ToggleLed(void)
{
/* Set the pin to the opposite of what is read from the pin. The pin value
In the initialization area of main(), first enable the interrupt by calling InitTiming(). The clock compo-
nent, Clock_PWM, is automatically enabled. To confirm this you can look at the Clocks tab of the
.cydwr file. There is a check in the Start on Reset column. Then call the enable function for the
source of the interrupt, the PWM_Timer component. After starting the PWM_Timer and isr_PWM
components, you enable the global interrupt flag so that the isr_PWM component can be serviced
when the terminal count of the PWM_Timer is reached.
The SW1 button on the DVK1 board will short the SW1 pin to ground when pressed. When you
check the status of the button with Button_Pin_Read() the result will be 0 (or ‘false’) when the
button is pressed, and 1 when it is not. For this reason, (!(Button_Pin_Read()) is true when
the button is pressed.
The final function in main.c file is the toggleLED function. The toggleLED function simply toggles the
state of the appropriate bit in the data register to change the state of the LED_Pin.
One important piece of information to note here is that I am getting the state of the DataReg (data
register) and I am toggling that value before writing it back to the data register. This is the value that
is written to the output latches of the I/O logic. The alternative value you can examine is the value
read from the state of the pin using the PS (pin state) register. An example of reading the PS register
instead of the data register is given here.
CY_SET_REG8(LED_Pin__DR,(CY_GET_REG8(LED_Pin__PS)^LED_Pin__MASK));
I do not recommend using the PS register when you toggle an output because if the pin on that reg-
ister does not currently see the same logic as the DR register, then an incorrect value will be written
back to the DR register. Consider our button component as an example. We have output a high to
the button DR register bit to enable the pull up resistor. However, when SW1 is depressed, the PS
register bit will be a zero. If we were to toggle another bit on that same port using the PS register
instead of the DR register, then we would write a zero to that register. This results in the pull up being
disabled. The project will interpret the SW1 button being pressed even when it is not pressed.
1. Add a file to your project called timing.c.
2. Highlight the Project 'Chapter3'[CY8C3866AXI-40] icon in the Workspace Explorer and right
click on it.
3. Choose New Item from the context menu.
4. Select C File from the list of templates and change the name to timing.c.
5. Pressing OK creates the timing.c file, adds it to the project, and opens that file for editing. Copy
the code below into the timing.c file.
#include <device.h>
#include "timing.h"
/***************************************
* Global Variables
***************************************/
/* event flags for each of the time periods */
uint8 milliSecond;
uint8 tenthSecond;
uint8 oneSecond;
/***************************************
* Private Functions
***************************************/
/*****************************************************************************
* Function Name: TimerIsr()
******************************************************************************
* Summary:
* An Interrupt Service Routine (ISR) for the pulse width modulator. This
* function is not public. The ISR provides basic timing for all background
* functions. It is assumed that the ISR is called once per millisecond.
*
* Parameters:
* none
*
* Return:
* None. Timing event flags are set.
*
*****************************************************************************/
static CY_ISR(TimerIsr)
{
/* counters for the longer time periods */
static uint8 tenthSecondCount = 0U;
static uint8 oneSecondCount = 0U;
/* Read the PWM status byte to clear the interrupt source. Since function
* calls should not be done from interrupt handlers, the register is read
* directly. Dump the value into a dummy location; we're not interested in
* the value of the register.
*/
(void)PWM_Timer_STATUS;
/***************************************
* Global Functions
***************************************/
/*****************************************************************************
* Function Name: InitTiming()
*****************************************************************************/
void InitTiming(void)
{
isr_PWM_Start();
/* set the interrupt's ISR function to be the one in this file */
isr_PWM_SetVector(TimerIsr);
} /* end of InitTiming() */
/*******************************************************************************
* Function Name: TenthSecondDelay()
*******************************************************************************/
void TenthSecondDelay(uint8 count)
{
/* count down every tenth second, and return when counted down to zero */
do
{
while(!tenthSecond){}
tenthSecond = 0U;
count--;
} while(count != 0U);
}/* end of TenthSecondDelay() */
1. Right click on the Project icon in Workspace Explorer and add a New Item.
2. This time select a Header File from the list of templates and name the header file timing.h.
3. Add the following code to the timing.h file.
/***************************************
* Function Prototypes
***************************************/
/*****************************************************************************
* Function Name: InitTiming()
******************************************************************************
* Summary:
* Initializes the timing system, particularly the interrupt component and
* the ISR.
*
* Parameters:
* none
*
* Return:
* none
*
*****************************************************************************/
void InitTiming(void);
/*******************************************************************************
* Function Name: TenthSecondDelay()
********************************************************************************
* Summary:
* Waits for a given delay in tenths of seconds. The actual delay will be:
* count - 1 < actual delay ? count
*
* Parameters:
* uint8 number of tenth-seconds to wait
*
* Return:
* none
*******************************************************************************/
/***************************************
* Global Variables
***************************************/
/* These timing event flags are set at the corresponding time interval by the ISR.
* It is the responsibility of the background function to reset them before they
* are set again.
*/
extern uint8 milliSecond;
extern uint8 tenthSecond;
extern uint8 oneSecond;
An interrupt service routine for the isr_PWM component exists in the isr_PWM.c file generated by
PSoC Creator. However, we will be using our own interrupt service routine, TimerIsr(), defined in
timing.c. Note the 'CY_ISR' macro that defines that this function is an interrupt service routine. In
the InitTiming() function, after we initialize the interrupt by calling isr_PWM_Start(), we change
the interrupt's vector to point to our routine by calling isr_PWM_SetVector().
Executing code will build the project if any changes have been made to source files or any config-
uration. It will program the target device and will halt at the main label in main.c.
7. Press the small green arrow on the Debugger toolbar or press [F5] to continue executing code.
You should see a dim light coming from LED1, and LED2 should be flashing at 5 Hz. Pressing on
SW1 should change the blink rate of LED2 to 0.5 Hz.
3.4 Conclusions
This project demonstrated one of many ways to create a periodic interrupt. The method used in this
project allows you to configure system-wide resources, digital logic in the UDB blocks, and I/O pins.
The PWM module created a system that is easy to debug at the most rudimentary levels so that you
have a basis for the other projects in this book. If a project from the other chapters is not working cor-
rectly, make sure that this basic LED functionality is still working. If it is not working correctly, then
make sure to restore that functionality first as it is a requirement for the added features of the other
projects.
The timing flags create a basic task scheduler that can be easily altered to meet different periodic
requirements. The use of timing flags set within a timing interrupt allows the bulk of code execution
to be done outside the interrupt. If execution of a task is very time critical and needs to be able to
interrupt other task execution, that task can be called from within the timing interrupt. Caution should
be taken to make sure that any task execution called from within the timing interrupt does not take
longer to execute than the period of the timing interrupt.
/*******************************************************************************
* Function Name: stateBlink
********************************************************************************
* Summary:
* Blinks a specific amount of blinks
*
* Parameters:
* none
*
* Return:
* none
*
*****************************************************************************/
void stateBlink(void)
{
/* Check to see if blinkCount has reached zero yet */
if(blinkCount>0)
{
/* If it is not zero, then default the LED off */
LED_Pin2_Write(0);
The second recommended method for displaying a state is to use a counter so that the LED is
blinked the amount of times equal to the value of state.
/*******************************************************************************
* Function Name: stateBlinkDecode
********************************************************************************
* Summary:
* Blinks a specific amount of blinks
*
* Parameters:
* none
*
* Return:
* none
*
*****************************************************************************/
void stateBlinkDecode(void)
{
if(blinkCount1>0)
{
/* Decrement blinkCounter */
blinkCount1--;
if((blinkCount1>BLANKTIME)&(blinkCount1%2))
{
/* Turn on the LED; */
LED_Pin3_Write(1);
}
else
{
/* Turn off the LED; */
LED_Pin3_Write(0);
}
}
else
{
/* Turn off the LED; */
LED_Pin3_Write(0);
This method is simple and straightforward. It becomes more cumbersome as the numbers become
larger. A suggestion for larger numbers is to break the number up into digits. For example, a code of
35 could be shown by a set of three blinks of the LED, a short pause and then a set of five blinks of
the LED. This could be done digitally in the UDBs so that blinking LEDs would not burden the CPU.
The advantages of rebuilding each chapter from scratch include the ability to see all five projects in
the same session of PSoC Creator. You can also easily go back to a previous project with the assur-
ance that the older project is not affected by changes made in the new project. You also gain confi-
dence and speed in placing and configuring new components.
5. Now add two files to your project: display.c and display.h. For now, we will keep the contents of
display.c simple.
#include <device.h>
#include "display.h"
/*******************************************************************************
* Function Name: DisplayWelcome()
*******************************************************************************/
void DisplayWelcome(void)
{
CharLCD_ClearDisplay();
CharLCD_Position(0U, 0U); /* row, column */
CharLCD_PrintString("PSoC Rocks!");
} /* end of DisplayWelcome() */
/*******************************************************************************
* Function Name: UpdateDisplay()
*******************************************************************************/
6. Start the CharLCD component in the beginning of main.c and call the welcome screen to verify
that the display is working.
InitTiming(); /* interrupt */
PWM_Timer_Start(); /* source of interrupt */
CYGlobalIntEnable /* macro */
CharLCD_Start(); /* Start the CharLCD component */
DisplayWelcome(); /* Display the welcome message */
The DisplayCount routine will be called every tenth second and will simply show an incrementing
counter.
7. Add this code to the tenth second area of main.c.
The display.h file is needed to make the DisplayWelcome and DisplayCount routines visible to
main.c. Do not forget to include display.h in main.c. The contents of display.h are:
/***************************************
* Function Prototypes
***************************************/
/*******************************************************************************
* Function Name: DisplayWelcome()
********************************************************************************
* Summary:
* Displays a welcome message on the character LCD.
*
* Parameters:
* none
*
* Return:
* none
*******************************************************************************/
void DisplayWelcome(void);
/*******************************************************************************
* Function Name: DisplayCount()
********************************************************************************
* Summary:
* Prints a count result to the LCD.
*
* Parameters:
* count: the count value to be displayed
*
* Return:
* void
*******************************************************************************/
void DisplayCount(uint8 count);
Note. The code in the millisecond area may not execute every millisecond in this chapter. The func-
tion called in the tenth second area may take longer than 1 millisecond to execute. This is accept-
able in the projects in this book. If you need some code executed every millisecond in your project
and it is based on the projects in this book, you may need to execute that code in the ISR in the tim-
ing.c file.
The other options in the Configure ’UART’ window specify that the UART sends or receives
eight bits of data at a time. We will not be sending a parity bit. The stop bit will be only one bit in
length and there will not be any flow control to this communication. The computer that is con-
nected to this project needs to have the same COM port settings as the UART in the PSoC 3 to
communicate correctly.
Figure 4-4. UART Configuration - Advanced Settings
5. Click on the Advanced tab in the UART Configure dialog (Figure 4-4 on page 46).
The Clock Selection defaults to Internal Clock. This tells PSoC Creator to configure the internal
clocking distribution system to provide the necessary input frequency to the UART component. If
External Clock is selected, then a clock terminal will appear in schematic view to allow you to
connect a clock signal from another component in your design. The external clock signal needs
to have a frequency eight times the desired bit rate. This faster signal allows the UART compo-
nent to over-sample the incoming data and align the data sampling with the center of each bit
transmitted by another device. This oversampling helps with data integrity and proper error
detection.
6. Clear all selection boxes in the Interrupts section of the Advanced tab.
7. Scroll to the bottom of the Advanced tab and clear the Hardware TX-Enable option.
8. Set the buffer size for RX and TX to 1 (Figure 4-5).
When the buffer sizes for RX and TX are less than or equal to four, the options to enable internal
interrupts for the RX ISR and TX ISR are grayed out. You can enable external interrupts. The
PSoC 3 device implements a 4-byte buffer for RX and TX with the UART component. This
relieves the CPU of the need to manage the UART for every byte sent or received. If you want a
larger than 4-byte buffer, then PSoC Creator will generate the code needed to implement a larger
buffer using interrupts and additional RAM resources to manage that buffer. The calls to read and
write from the buffers are the same regardless of buffer size.
Figure 4-5. UART Configuration - Advanced Settings (continued)
6. Drag a Digital Output Pin component onto the design and name it Tx_Pin.
7. Connect the Tx_Pin I/O component to the tx port of the UART_1 Component.
8. Add a logic low signal to the reset input of UART_1.
Your schematic should look like Figure 4-7.
Figure 4-7. Chapter4 Schematic
Examine the UART_1_IntClock. The UART_1 component bit rate is set to 115,200 bits per second.
Earlier, we learned that the UART needs to over-sample each bit that is being received so that the
UART can provide good error detection and ensure data integrity. The required clock for the
UART_1 component must be eight times the 115,200 bits per second. This gives us a frequency of
921,600 bits per second. PSoC Creator is showing a desired frequency of 921.600 kHz for the
UART_1_IntClock. However, it is not able to divide any of the available clocks by an integer value to
achieve 921.600 kHz, so it chooses the closest integer possible. The source clock is the master
clock which is running at 24 MHz. PSoC Creator divides this clock by 26 which results in an actual
frequency of approximately 923.077 kHz. That might seem like a large error to be off by more than
1.5 kHz, however, the percentage of error between the actual clock and the desired clock is only
about 0.16%. This error is acceptable for communication with the computer.
You will notice that some of the clocks listed in the light tan area have a ‘?’ listed under the Actual
Frequency column. These frequencies require an external crystal or clock signal which we are not
going to have for this project. The other clocks listed in the light tan area are derived from the internal
clock sources of the PSoC device. Double click in the light tan area to examine this arrangement
(Figure 4-10 on page 51).
The Configure System Clocks dialog allows you to configure the clocking structure for your PSoC
project. External crystals can provide different frequencies or greater accuracy than the internal
clock. The Master Clock and Bus Clock allow you to set up the overall system frequency to balance
performance requirements and power used. PSoC Creator gives you a very visual picture of how the
configuration is arranged as well as the table format to view this configuration while examining other
clocks that you have added to your design.
4.3.5 Code
1. Create a new file to add to your project called comport.c and add the following content to that file.
#include <device.h>
#include <stdio.h>
#include "comport.h"
/***************************************
* Global Variables
***************************************/
/* flag to indicate LED should be toggled or turned off */
uint8 ledEnabled = (uint8)1;
/***************************************
* Private Functions
***************************************/
/*******************************************************************************
* Function Name: ExecuteCommand()
********************************************************************************
* Summary:
* Executes a command based on an input byte. The input byte is expected to
* be an ASCII character.
*
* Parameters:
* thisCommand: the command byte
*
* Return:
* none
*******************************************************************************/
static void ExecuteCommand(char thisCommand)
{
/* An ASCII number character changes the PWM duty cycle */
if (('0' <= thisCommand) && (thisCommand <= '9'))
{
/* Display "PWM xx%", where xx is the number times 10. For example,
* an ASCII '7' results in "PWM 70%".
*/
uint8 temp = (uint8)(((uint8)thisCommand & 0x0FU) * 10U);
char msg[10]; /* leave room for CR, LF and 0 */
sprintf(msg, "PWM %u%%\r\n", (unsigned int)temp);
UART_1_PutString(msg);
/* set the PWM duty cycle to the corresponding value, assumes that the
* PWM period is 100.
*/
PWM_Timer_WriteCompare(temp);
} /* end of if(), i.e. number key */
else /* not a number character */
{
switch(thisCommand)
{
/* An S or G character (either case) stops or starts blinking the
* LED, respectively. Stop also turns off the LED.
*/
case 's':
case 'S':
UART_1_PutString("Stop LED\r\n");
ledEnabled = 0U;
break;
case 'g':
case 'G':
UART_1_PutString("Go LED\r\n");
ledEnabled = 1U;
break;
default:
UART_1_PutString("Unknown Command\r\n");
break;
} /* end of switch(thisCommand) */
} /* end of else, i.e. not a number character */
} /* end of ExecuteCommand() */
/***************************************
* Global Functions
***************************************/
/*******************************************************************************
* Function Name: InitComPort ()
*******************************************************************************/
void InitComPort(void)
{
UART_1_Start();
/* delay for the UART to initialize */
CyDelay(1LU); /* msec */
UART_1_PutString("My First Five Designs\r\n");
} /* end of InitComPort() */
/*******************************************************************************
* Function Name: UpdateComPort
*******************************************************************************/
void UpdateComPort(void)
{
/* if the UART has a received byte, execute a command based on that byte */
if(UART_1_ReadRxStatus() & (uint8)UART_1_RX_STS_FIFO_NOTEMPTY)
{
ExecuteCommand((char)UART_1_ReadRxData());
}
} /* end of UpdateComPort() */
2. Create a new header file for your project called comport.h and add the following content to that
file. Include this file in main.c.
/*******************************************************************************
* Function Name: InitComPort()
********************************************************************************
* Summary:
* Sets up the UART for operation and sends out a message.
*
* Parameters:
* none
*
* Return:
* none
*******************************************************************************/
void InitComPort(void);
/*******************************************************************************
* Function Name: UpdateComPort
********************************************************************************
* Summary:
* Checks for any received bytes and calls executes commands as needed, based
* on those bytes. It is expected that the received bytes are ASCII characters
* as follows:
* '0' - '9' : set the PWM duty cycle to 0%, 10%, ..., 90%
* 'S', 's' : stop the blinking LED, turning it off.
* 'G', 'g' : start blinking the LED.
*
* In addition to the above actions, a corresponding message is sent out the
* UART transmit. This includes an error message if the received byte is not
* one of the above characters.
*
* This routine should be called every millisecond.
*
* Parameters:
* none
*
* Return:
* none
*******************************************************************************/
void UpdateComPort(void);
/***************************************
* Global Variables
***************************************/
/* This flag is used to indicate whether or not a command has been received from
* the ComPort to enable or disable the blinking LED.
*/
extern uint8 ledEnabled;
3. Now place the call to intializeComPort in the main routine and place the call to the
UpdateComPort function in the millisecond area as shown below. Don’t forget to include
comport.h.
InitTiming(); /* interrupt */
PWM_Timer_Start(); /* source of interrupt */
CYGlobalIntEnable /* macro */
CharLCD_Start(); /* Start the CharLCD component */
InitComPort(); /* UART component */
......
/* This section contains code to be executed every millisecond */
if(milliSecond)
{
milliSecond = 0U;
/* poll the UART and execute a command if bytes received */
UpdateComPort();
} /* end of millisecond section */
......
The InitComPort call in the beginning of main will both start the UART_1 component and send a
string through that ComPort to your computer. In order to see this message, you will need to have
the computer terminal program running and set to the same parameters as the UART_1 component
when the debugger executes this code. The UpdateComPort is called every millisecond to see if a
character has arrived from the computer, respond to any character received, and send out the
appropriate response. See the ExecuteCommandNote that UART_1_PutString will loop and not
return until all the characters are sent. This may not be desirable for your project, but it is an accept-
able characteristic for our purposes in this chapter.
I have limited the commands in this project to single characters for simplicity. This simplifies the
receive process by removing the need to align to the beginning of a command sequence. If a com-
mand is received that is not understood, it is simply discarded. Commands can easily be sent with
any terminal program, such as Hyperterminal or Tera Term. The number keys will change the duty
cycle of the PWM_Timer PWM output and therefore the brightness of the LED attached to the
PWM_Pin. The S and G commands change the value of ledEnabled. We need to modify the tog-
gleLED function in main.c to utilize ledEnabled. It should toggle the LED if the ledEnabled is a non
zero value and it should shut the LED off if ledEnabled is equal to zero. Here is the modified tog-
gleLED function.
/***************************************************
* Function Name: ToggleLed()
****************************************************
* Summary:
* Toggles or turns off the LED, depending on an enable state.
*
* Parameters:
* none
*
* Return:
* none
****************************************************/
void ToggleLed(void)
{
/* toggle the LED if it is enabled, otherwise just keep it turned off */
if(ledEnabled)
{
/* Set the pin to the opposite of what is read from the pin. The pin
* value is always right-justified to the LS bits.
*/
LED_Pin_Write(LED_Pin_Read() ^ 1U);
}
else
{
LED_Pin_Write(0U);
}
} /* end of ToggleLed() */
1. Before downloading the code to the project, connect the computer to the serial port connector on
the DVK1 board
2. Start your terminal program.
3. Download the code to the PSoC and run the program. You should see the message “My First
Five Designs” returned to the terminal window.
4. Press the [S] key on the keyboard to turn off the LED connected to the LEDPin.
5. Press the [G] key on the keyboard. The LED should start blinking again.
6. Press each of the number keys to observe the different duty cycle rates to the LED connected to
the PWM_Pin. The [0] key sets the duty cycle to 0%, which just holds the signal low and turns off
the LED.
4.4 Conclusions
Two-way communication with a PC is a very powerful tool for any embedded designer. A simple
UART connection allows our project to benefit from the rich interface and display capabilities of a
computer. The UART connection can serve as a real-time debugging tool during operation.
The format of communication for the UART makes it a good choice for a part-time debugging tool.
Since the communication does not require a response from the computer in order to continue, you
can leave a computer disconnected with the debugging code active. A computer can be connected
to the project for debugging at any time without restarting the project.
Each data bit in the UART communication including the start bit and stop bit are sent for a specific
time duration. The time duration of each bit needs to be established to interpret the communication.
A device will typically sample the signal several times each bit to be able to center data sampling
towards the middle of the bit time and to verify that the signal is not noisy. The rate bits that are able
to be sent are referred to as bits per second (bps). The number of bits per second can be shown in
thousands of bits per second by the term kilobits per second (kbps), or in millions of bits per second
(Mbps). In order to have successful communication between devices, it is necessary that they all
have a clock that is accurate to within about 2%. This assures that each side can time the communi-
cation correctly. The bits per second describe the transfer rate of data. There is another term that
you may have heard called baud rate. The use of baud rate very often means the bit rate. However,
there are times that the baud rate and bit rate are different. The term baud rate can also specifically
mean the rate at which the state of the transmission signal changes.
The PSoC implementation of the UART is very flexible. Using the clocking system, you are able to
generate virtually every standard baud rate. The UART block supports 7- and 8-bit data transfer with
a configurable number of stop bits to assure compatibility with other systems. If you are only going to
communicate with a local system that is running at the same voltage as the PSoC device, then there
is not a need to get the voltage converter chip to step up to the higher voltages required by the
RS232 standard.
4. Select the Clock Source tab and set the Prescaler to UDB and the CPS_CLK to BUS_CLK: 24
MHz.
3. After you have created the two buttons, click on each button in turn and set the Debounce to 5,
the Hysteresis to 5, the Finger Threshold to 75, and the Noise Threshold to 10 (Figure 5-3).
Figure 5-3. CapSense Buttons Threshold
The capacitance measurement on the circuit is a very sensitive measurement. The circuit is sensi-
tive to changes in temperature, humidity, voltage, and so on. The capacitive system must be tuned
and adjusted for the board layout and the environment that it is in. The numbers that you are adjust-
ing for the button relate to how much expected variance there is in the capacitive measurement.
Each time your finger approaches the circuit, capacitance increases because the capacitance of
your finger with respect to circuit ground is in parallel with the sensing I/O pin with respect to circuit
ground.
Figure 5-4. Cross Section of a Capacitive Sensor
The code establishes a baseline measurement. The baseline value is the value of capacitance mea-
sured when no finger or object is present. This number is subject to some natural variance from
reading to reading as well as a drift in average measurements due to changing environmental condi-
tions. If the increase in a reading compared to the baseline is less than the noise threshold, then the
baseline is adjusted by a percentage of that change to compensate for changing environmental con-
ditions.
If the new reading is above the finger threshold, then the debounce counter starts to count. If the
counter is incremented by the value of Debounce, then the finger is declared to be present. There is
an adjustable Hysteresis value around the finger threshold to handle small deviations above and
below the threshold.
Pressing the Enter key enters the information and selects the next item. When you are in the last
column pressing the Enter key completes the current line and takes you to the beginning of the
next line.
8. Click on the name Slider0.
9. Verify that the Filters Configuration items are all set to Disabled.
10.Set the Finger Threshold to 30 and the Noise Threshold to 10 (Figure 5-5).
Figure 5-5. CapSense Slider Configuration
11. Click on the Scan Slots tab (Figure 5-6 on page 64).
12.Select the Custom box for each of the buttons and slider elements, and set the Prescaler
Period to 11, Resolution to 10 bits, IDAC range to 2, Scan Speed to Normal, and the IDAC
Setting to 127.
13.Press OK.
#include <device.h>
#include "myCapsense.h"
/***************************************
* Global Functions
***************************************/
/*******************************************************************************
* Function Name: InitCapSense()
*******************************************************************************/
void InitCapSense(void)
{
/* Components should be initialized in the following order:
* 1. interrupts
* 2. sources of interrupts (clocks are auto-initialized)
* 3. global interrupt enable
*/
CapSense_Start(); /* interrupt and source of interrupt */
CYGlobalIntEnable /* macro */
/*******************************************************************************
* Function Name: UpdateCapSense()
*******************************************************************************/
void UpdateCapSense(void)
{
/* Scan all buttons and slider */
CapSense_CSD_ScanAllSlots();
/* update baseline values for all buttons and slider */
CapSense_CSHL_UpdateAllBaselines();
} /* end of UpdateCapSense() */
/*******************************************************************************
* Function Name: GetButtonP0_5()
*******************************************************************************/
uint8 GetButtonP0_5(void)
{
return CapSense_CSHL_CheckIsSlotActive((uint8)CapSense_SCANSLOT_BTN_P0_5);
} /* end of GetButtonP0_5() */
/*******************************************************************************
* Function Name: GetButtonP0_6()
*******************************************************************************/
uint8 GetButtonP0_6(void)
{
return CapSense_CSHL_CheckIsSlotActive((uint8)CapSense_SCANSLOT_BTN_P0_6);
} /* end of GetButtonP0_6() */
/*******************************************************************************
* Function Name: GetSlider()
*******************************************************************************/
uint8 GetSlider(void)
{
return (uint8)(CapSense_CSHL_GetCentroidPos((uint8)CapSense_CSHL_LS_SLIDER0));
} /* end of GetSlider() */
3. Create a header file called myCapsense.h and include the following in that file.
/*******************************************************************************
* Function Name: InitCapSense()
********************************************************************************
* Summary:
* Initializes the CapSense component for the DVK.
*
* Parameters:
* none
*
* Return:
* none
*******************************************************************************/
void InitCapSense(void);
/*******************************************************************************
* Function Name: UpdateCapSense()
********************************************************************************
* Summary:
* Scans slots and updates baselines for the CapSense component for the DVK.
*
* Parameters:
* none
*
* Return:
* none
*******************************************************************************/
void UpdateCapSense(void);
/*******************************************************************************
* Function Name: GetButtonP0_5
********************************************************************************
* Summary:
* Reports if a finger is present or not at DVK button P0_5.
*
* Parameters:
* none
*
* Return:
* 1 if finger is present, 0 if finger is not present
*******************************************************************************/
uint8 GetButtonP0_5(void);
/*******************************************************************************
* Function Name: GetButtonP0_6
********************************************************************************
* Summary:
* Reports if a finger is present or not at DVK button P0_6.
*
* Parameters:
* none
*
* Return:
* 1 if finger is present, 0 if finger is not present
*******************************************************************************/
uint8 GetButtonP0_6(void);
/*******************************************************************************
* Function Name: GetSlider
********************************************************************************
* Summary:
* Reports the presence / position of a finger on the DVK slider.
*
* Parameters:
* none
*
* Return:
* Position 0 - 100 if finger is present, 0xFF if finger is not present
*******************************************************************************/
uint8 GetSlider(void);
A CapSense project must follow a basic pattern to sense the presence of a finger. First, the
CapSense component must be started, which also starts a clock and an interrupt associated with the
component. Then, after global interrupts are enabled, the baselines must be established. This is
done by calling the InitializeAllBaselines routine. After the baselines are initialized, periodically call
the ScanAllSlots and UpdateAllBaselines routines. The call to ScanAllSlots will read and save the
current capacitive measurement on each of the I/Os configured for CapSense. The UpdateAllBase-
lines routine will use the new capacitive measurements to determine the new baseline values for
each sensor.
The code in main.c implements both the initialization and periodic updating of the ScanAllSlots and
UpdateAllBaselines call. Do not forget to #include myCapsense.h in main.c.
void main()
{
/* Components should be initialized in the following order:
* 1. interrupts
* 2. sources of interrupts (clocks are auto-initialized)
* 3. global interrupt enable
* This is all done in the following function:
*/
InitCapSense();
The code in the main() routine uses the CharLCD to feed back the results of the capacitive sensing.
1. Compile and run your project. The code in main() displays labels on the first row of the LCD dis-
play corresponding to each element in the CapSense component. The result of each scan is dis-
played below the label.
2. Verify that your finger is detected properly by placing your finger in turn on each element. Notice
that the slider element returns an 0xFF when the finger is not present on the slider. It returns the
position 0x00 - 0x64 (0-100) when the finger is present. The position range is the Resolution
value set up when the Slider was defined - see Figure 5-5 on page 63.
We will reuse the code in myCapsense.c in later designs so that the buttons and slider can be used
in those designs. For now we have successfully added CapSense buttons and verified that they
work.
5.4 Conclusions
The PSoC platform makes capacitive sensing easy while still giving you full power to adjust and
modify the firmware. Capacitive sensing does not need to involve a separate microcontroller or
ASIC. It is available on the same chip using the same design resources. Cypress offers powerful
tools to help you tune your design and provides extreme flexibility in routing the CapSense signals to
the pins needed by your design criteria.
Since capacitive sensing is done directly on the PSoC device, tuning the capacitive sensing can take
advantage of all the capabilities of the device. Debug information can be sent out of a communica-
tions port, logged for later investigation, or combined with other readings to make more complex
decisions.
1. Add a Control Register to your project from the Digital-Registers group of the Component Cat-
alog.
2. Double click the Control Register and configure the Name to be Control_Reg_NextStep.
3. Change the NumOutputs variable to 4. This is the driving value that puts items on one side of
the river or the other. Each of the four bits represents one of the items in our riddle (Figure 6-2).
Figure 6-2. Control Register Configuration
The Sheet Connector component allows you to connect signals from different schematic pages. It
also allows you to connect signals on the same page that are not otherwise visibly connected. This is
going to help us organize the visual appearance of the logic devices. Without the Sheet Connectors,
it can be hard to follow the wire connections that cross (Figure 6-4 and Figure 6-5 on page 75).
6. Drag the name Farmer and place it on top of the wire. Figure 6-5 on page 75 gives you an idea of
what type of layout I am expecting to use.
7. Continue to add Sheet Connectors for the remaining three bits. Name these wires Corn,
Goose, and Fox in that order.
As you can see in Figure 6-5 on page 75. I have added two other text boxes to remind me of the
order of bits as they relate to the Control_Reg_NextStep and the LUT.
The LUT_Riddle compares each state of the Farmer, Corn, Goose, and Fox to see which step of the
riddle it is on. If the step is undefined, then the output of the LUT is 0x0F. Since there is not a clock
input for the LUT_Riddle, the output pins of the LUT change immediately after the input signals
change. Note, however, that the value of Status_Reg_CurrentStep does not change until I pulse the
Control_Reg_Clock value. Therefore, the process to progress to the next step in the riddle requires
me to first write to Control_Reg_NextStep and then set and clear the bit in Control_Reg_Clock. After
completing those two steps, I will have the current step value in the Status_Reg_CurrentStep regis-
ter.
6.3.2 Code
1. Create two new files in the project called farmerRiddle.h and farmerRiddle.c.
2. Include farmerRiddle.h in the main.c file. The farmerRiddle.h file will only have three prototypes.
/***************************************
* Function Prototypes
***************************************/
/*******************************************************************************
* Function Name: InitRiddle()
********************************************************************************
* Summary:
* Initializes Riddle conditions, UART communications, and the display.
*
* Parameters:
* none
*
* Return:
* none
*******************************************************************************/
void InitRiddle(void);
/*******************************************************************************
* Function Name: UpdateRiddle()
********************************************************************************
* Summary:
* Processes commands from the UART, updating Riddle conditions and display.
* Since a display update may include an animation, this function can pend for
* a long time until it returns.
*
* Parameters:
* none
*
* Return:
* none
*******************************************************************************/
void UpdateRiddle(void);
/*******************************************************************************
* Function Name: TestRiddle()
********************************************************************************
* Summary:
* Tests the Riddle functions.
*
* Parameters:
* none
*
* Return:
* none
*******************************************************************************/
void TestRiddle(void);
3. Add calls to the InitRiddle and testRiddle functions to the main.c file just before the endless loop.
The TestRiddle call is usually commented out unless you want an automated method to test the
rest of the project.
/* Riddle initialization */
/*TestRiddle();*/ /* optional function, typically commented out */
InitRiddle();
UpdateRiddle();
} /* end of tenth second section */
The function call TestRiddle is not needed for the project, but it does run through each of the steps in
turn to illustrate on the LCD what is expected to happen. I used it to test the operation of the code
that is included here.
Below I have included the code for farmerRiddle.c. Most of the code written in this file is simply to
have fun and illustrate the riddle on the LCD display. The tenthSecondDelay routine from timing.c is
called several times simply to give a short delay. This call does prevent the code execution from
returning to the main loop for some time, so you will need to wait for animations and displays to finish
before the DVK1 will respond to any further inputs. This limitation is intentional to keep the code as
clear and straightforward as possible. The code to talk to the LCD display and show what is going on
is more than 60% of what is contained here, but it makes the project a lot more fun.
The InitRiddle function sends instructions out the UART_1 component to a terminal program and
sets the logic to its initial state with all four items on the starting side of the river. It also pulses the
clock wire to make sure the Status_Reg_LastState has the proper value in it for starting.
The UpdateRiddle function checks the UART_1 component to see if a new command has come in. If
a command has been received, it processes the command with the ExecuteRiddle function. After the
command has been processed, the Control_Reg_Clock register is clocked to load the D Flip Flops
with their next value.
The ExecuteRiddle function checks to see if the farmer and desired passenger are on the same side
of the river. If they are on the same side of the river, then the boat is sent with farmer and passenger
to the other side. The digital logic will then determine the success of your choice after they reach the
other side. If the farmer and desired item is not on the same side of the river, then an error is
returned. The AnimateBoat function is called to display the moving boat of the farmer with his pas-
senger going from one side of the river to the other.
#include <device.h>
#include "farmerRiddle.h"
#include "timing.h"
/***************************************
/***************************************
* Private functions
***************************************/
/*******************************************************************************
* Function Name: DisplayElements()
********************************************************************************
* Summary:
* Displays on the char LCD the positions, i.e. which side of the river, of
* each of the four elements of the riddle, i.e. Farmer (F), Corn (C), Goose
* (G), and Fox (X). The positions are read from the control reg NextStep.
* The current boat position is also displayed.
*
* Parameters:
* none
*
* Return:
* none
*******************************************************************************/
static void DisplayElements(void)
{
/* message buffers for displaying the positions of the riddle elements.
* msg[0] shows those elements on the near side of the river,
* msg[1] shows those elements on the far side of the river.
*/
char msg[2][5];
uint8 temp;
/* Build and redisplay two messages to show the current position, i.e. on the
* near or the far side of the river, of each element of the riddle, i.e.
* farmer, corn, goose, fox.
*/
/* messages are based on the values in the control reg NextStep */
temp = Control_Reg_NextStep_Read();
/* first build the far side message */
msg[1][0] = ((temp & FARMER) ? 'F' : ' ');
msg[1][1] = ((temp & CORN) ? 'C' : ' ');
msg[1][2] = ((temp & GOOSE) ? 'G' : ' ');
msg[1][3] = ((temp & FOX) ? 'X' : ' ');
/* Then build the near side message, as the opposite of the far side message */
msg[0][0] = ((msg[1][0] == ' ') ? 'F' : ' ');
msg[0][1] = ((msg[1][1] == ' ') ? 'C' : ' ');
/*******************************************************************************
* Function Name: AnimateBoat()
********************************************************************************
* Summary:
* Does an animated display on the char LCD of the boat going across the river.
* Pends in this function until the animation is done.
*
* Parameters:
* passenger: ASCII character for the boat's passenger
*
* Return:
* none
*******************************************************************************/
static void AnimateBoat(char passenger)
{
/* animation display messages */
static const char* msgs[7] =
{
"<F >(((((", " <F >(((( ", " (<F >((( ", " ((<F >(( ", " (((<F >( ",
" ((((<F > ", " (((((<F >"
};
/* erase Farmer and other icon from land (farmer is always in boat) */
CharLCD_Position(0U, ((boatDir == 1) ? 0U : 12U)); /* row, column */
CharLCD_PutChar(' ');
if(passenger == 'C')
{
CharLCD_Position(0U, ((boatDir == 1) ? 1U : 13U)); /* row, column */
CharLCD_PutChar(' ');
}
else if(passenger == 'G')
{
CharLCD_Position(0U, ((boatDir == 1) ? 2U : 14U)); /* row, column */
CharLCD_PutChar(' ');
}
else if(passenger == 'X')
{
CharLCD_Position(0U, ((boatDir == 1) ? 3U : 15U)); /* row, column */
CharLCD_PutChar(' ');
}
else {} /* no default action */
/*******************************************************************************
* Function Name: ExecuteRiddle()
********************************************************************************
* Summary:
* Executes a command based on an input byte. The input byte is expected to
* be an ASCII character. Updates riddle conditions and display. Since this
* function calls AnimateBoat(), this function can pend for a long time until
* it returns.
*
* Parameters:
* thisCommand: the command byte
*
* Return:
* none
*******************************************************************************/
static void ExecuteRiddle(char thisCommand)
{
char passenger = ' '; /* passenger in the boat */
uint8 temp;
Control_Reg_NextStep_Write(Control_Reg_NextStep_Read() ^ FARMER);
passenger = ' '; /* no passenger */
display = 1U; /* update positions display */
break;
/* briefly display the order of steps and indicate out of order or not */
CharLCD_ClearDisplay();
CharLCD_Position(0U, 0U); /* row, column */
temp = Status_Reg_CurrentStep_Read();
if((temp != 0U) && (temp != 7U))
{
CharLCD_PrintString(
(temp == (Status_Reg_LastStep_Read() + 1U)) ?
"Correct order" : "Incorrect order");
/* display the current and last step values */
CharLCD_Position(1U, 0U); /* row, column */
CharLCD_PrintString("Curr:");
CharLCD_PrintInt8(Status_Reg_CurrentStep_Read());
CharLCD_PrintString(" Last:");
CharLCD_PrintInt8(Status_Reg_LastStep_Read());
TenthSecondDelay(20U);
}
} /* end of ExecuteRiddle() */
/***************************************
* Global Functions
***************************************/
/*******************************************************************************
* Function Name: InitRiddle()
*******************************************************************************/
void InitRiddle(void)
{
UART_1_PutString("\r\nTime to play Farmer, Corn, Goose, and Fox\r\n");
UART_1_PutString("Press a Letter to put a passenger in the boat. \r\n");
UART_1_PutString("Press space bar for no passenger.\r\n");
UART_1_PutString("Press F or X for Fox, but he is displayed as X.\r\n");
UART_1_PutString("Press R to restart.\r\n");
UART_1_PutString("Watch the LCD for results.\r\n");
/*******************************************************************************
* Function Name: UpdateRiddle
*******************************************************************************/
void UpdateRiddle(void)
{
/* if the UART has a received byte, execute a command based on that byte */
if(UART_1_ReadRxStatus() & (uint8)UART_1_RX_STS_FIFO_NOTEMPTY)
{
char inbyte = (char)UART_1_ReadRxData();
if ((inbyte == 'r') || (inbyte == 'R')) /* R = reinitialize game */
{
UART_1_PutStringConst("Restarting\r\n");
InitRiddle();
}
else /* not a restart command */
{
/* process other command if not done and no game error */
uint8 temp = Status_Reg_Error_Read();
if((Status_Reg_CurrentStep_Read() != 7U) && (temp == 0U))
{
/* This may involve a boat animation so may pend for a while */
ExecuteRiddle(inbyte);
/* Clock the DFFs and last step */
Control_Reg_Clock_Write(1U); /* single clock pulse */
Control_Reg_Clock_Write(0U);
}
}
} /* end of if UART byte received */
} /* end of UpdateRiddle() */
/*******************************************************************************
* Function Name: TestRiddle
*******************************************************************************/
void TestRiddle(void)
{
InitRiddle();
ExecuteRiddle('G'); /* bring the goose over */
/* Clock the DFFs and last step */
Control_Reg_Clock_Write(1U); /* single clock pulse */
Control_Reg_Clock_Write(0U);
TenthSecondDelay(30U);
} /* end of TestRiddle() */
6.4 Conclusions
The configurable digital functions available in the UDBs of the PSoC device can be customized for
your design and routed to any GPIO pin. The digital functions can operate independently from the
CPU or the CPU can monitor and control the digital logic fabric through the use of control and status
registers.
them. A basic potentiometer provides a great diagnostic tool for analog processing since you can
slowly sweep the signal through the range of the potentiometer and observe the output. The DAC is
used to create a few basic patterns using some timing and a lookup table. We will use the CapSense
buttons and slider to provide the controls, and the Char LCD and the UART to provide visual feed-
back.
1. Drag an Analog Pin component onto your design.
2. Name it VR_Pin. This pin will be connected to the potentiometer on the DVK.
3. Drag an Analog Mux component into the design.
4. Rename the Analog Mux component AMux_Signal.
5. Change the Channels parameter to 2 (Figure 7-1).
The AMux_Signal multiplexer selects between the potentiometer input and the DAC input and will
send the selected output to the ADC.
Figure 7-1. AMux Configuration
6. Add a Voltage DAC to your project from the DAC group of the component catalog.
7. Keep the default range of 0 - 1.020V and name it VDAC8 (Figure 7-2).
Figure 7-2. VDAC8 Configuration
The last component needed for this design is an analog to digital converter (ADC).
1. Add a Delta Sigma ADC component from the Component Catalog to your design.
2. Double Click the ADC to configure it.
3. Name the component ADC.
4. Configure the Power setting to Medium Power.
5. Set the Conversion Mode to Continuous.
6. Set the Resolution to be 14 bits and the Conversion Rate to be 5,000 SPS (samples per sec-
ond).
7. Set the Input Range to be Vssa to Vdda (Single Ended).
8. Set the Input Buffer Gain to 1 (Figure 7-3 on page 94).
7.3.4 Code
#include "myADC.h"
#include "myDAC.h"
....................
void main()
{
/* Components should be initialized in the following order:
* 1. interrupts
* 2. sources of interrupts (clocks are auto-initialized)
* 3. global interrupt enable
*/
InitTiming(); /* interrupt */
CapSense_Start(); /* interrupt and source of interrupt */
PWM_Timer_Start(); /* source of interrupt */
InitAdc(); /* source of interrupt */
CYGlobalIntEnable /* macro */
..........
2. Add the following lines to the tenth second area of the main loop to call the UpdateCapSense,
UpdateAdc, and UpdateDac routines.
3. Comment out the DisplayCount call.
/* Toggle the LED if the button is NOT pressed. This will cause
* the LED to blink rapidly when the button is NOT pressed.
*/
if(Button_Pin_Read()) /* read a 1 when button is NOT pressed */
{
ToggleLed();
}
UpdateCapSense();
UpdateAdc();
UpdateDac();
} /* end of tenth second section */
4. Create a file called myADC.c. Add the following code to the myADC.c file.
#include <device.h>
#include "myADC.h"
#include "myDAC.h"
/***************************************
* Global Functions
***************************************/
/*******************************************************************************
* Function Name: InitAdc()
*******************************************************************************/
void InitAdc(void)
{
ADC_Start();
ADC_StartConvert(); /* Starts a continuous cnversion process */
} /* end of InitAdc() */
/*******************************************************************************
* Function Name: UpdateAdc()
*******************************************************************************/
void UpdateAdc(void)
{
if(ADC_IsEndConversion(ADC_RETURN_STATUS))
{
uint8 adcval8;
/* if reading from the DAC, amplify the reading, because the DAC is
* putting out voltage in the range 0 - 1.024V
*/
if(source != 0U)
{
adcval8 *= 3U;
}
The beginning lines in main routine start the ADC and begin the first conversion. Every 100 millisec-
onds, the main loop will check the ADC to see if it has completed its conversion. If the conversion
has completed, it will process and display that conversion result. The next conversion starts auto-
matically (continuous conversion mode).
The ADC in this chapter is set to do a 14-bit conversion. The 8 most significant bits are preserved
and displayed as an 8-bit result on the LCD screen. The project begins by displaying the letters ADC
in the first row of the LCD display with its own conversion result displayed directly below this label.
The UpdateAdc routine also sends a string of X characters to the UART. Open a terminal window
while running this project to see a simple bar graph representation of the voltage read by the ADC.
1. Create a file called myDAC.c. Add the following code to the myDAC.c file.
#include <device.h>
#include "myCapsense.h"
#include "myDAC.h"
/***************************************
* Global Variables and Macros
***************************************/
uint8 source = 0U; /* current ADC source, 0 = POT, 1 = DAC */
/***************************************
* Private Variables and Macros
***************************************/
/* These variables are used to generate the DAC waveform */
static uint8 waveType = 0U; /* which waveform table to use (see below) */
static uint8 waveSpeed = 1U; /* how fast to move through the waveform table */
127U,135U,143U,151U,159U,166U,174U,181U,188U,195U,202U,208U,214U,220U,225U,230U,2
34U,238U,242U,245U,
248U,250U,252U,253U,254U,254U,254U,253U,252U,250U,248U,245U,242U,238U,234U,230U,2
25U,220U,214U,208U,
202U,195U,188U,181U,174U,166U,159U,151U,143U,135U,127U,119U,111U,103U, 96U,
88U, 80U, 73U, 66U, 59U,
53U, 46U, 40U, 35U, 29U, 24U, 20U, 16U, 12U, 9U, 6U, 4U, 2U, 1U, 0U, 0U,
0U, 1U, 2U, 4U,
6U, 9U, 12U, 16U, 20U, 24U, 29U, 34U, 40U, 46U, 52U, 59U, 65U, 73U, 80U,
87U, 95U,103U,111U,119U
},
{ /* sawtooth */
0U, 3U, 5U, 8U, 10U, 13U, 15U, 18U, 21U, 23U, 26U, 28U, 31U, 33U, 36U, 39U,
41U, 44U, 46U, 49U,
52U, 54U, 57U, 59U, 62U, 64U, 67U, 70U, 72U, 75U, 77U, 80U, 82U, 85U, 88U,
90U, 93U, 95U, 98U,100U,
103U,106U,108U,111U,113U,116U,118U,121U,124U,126U,129U,131U,134U,137U,139U,142U,1
44U,147U,149U,152U,
155U,157U,160U,162U,165U,167U,170U,173U,175U,178U,180U,183U,185U,188U,191U,193U,1
96U,198U,201U,203U,
206U,209U,211U,214U,216U,219U,222U,224U,227U,229U,232U,234U,237U,240U,242U,245U,2
47U,250U,252U,255U
},
{ /* triangle */
0U, 5U, 10U, 16U, 21U, 26U, 31U, 36U, 42U, 47U, 52U, 57U, 62U, 68U, 73U,
78U, 83U, 88U, 94U, 99U,
104U,109U,114U,120U,125U,130U,135U,141U,146U,151U,156U,161U,167U,172U,177U,182U,1
87U,193U,198U,203U,
208U,213U,219U,224U,229U,234U,239U,245U,250U,255U,255U,250U,245U,239U,234U,229U,2
24U,219U,213U,208U,
203U,198U,193U,187U,182U,177U,172U,167U,161U,156U,151U,146U,141U,135U,130U,125U,1
20U,114U,109U,104U,
99U, 94U, 88U, 83U, 78U, 73U, 68U, 62U, 57U, 52U, 47U, 42U, 36U, 31U, 26U,
21U, 16U, 10U, 5U, 0U
},
{ /* square */
10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U,
10U, 10U, 10U, 10U, 10U,
10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U,
10U, 10U, 10U, 10U, 10U,
10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U, 10U,
10U,245U,245U,245U,245U,245U,245U,245U,245U,245U,245U,
245U,245U,245U,245U,245U,245U,245U,245U,245U,245U,245U,245U,245U,245U,245U,245U,2
45U,245U,245U,245U,
245U,245U,245U,245U,245U,245U,245U,245U,245U,245U,245U,245U,245U,245U,245U,245U,2
45U,245U,245U,245U
}
};
/***************************************
* Private Functions
***************************************/
/*******************************************************************************
* Function Name: DisplayDac()
********************************************************************************
* Summary:
* Displays on the char LCD the current state of the analog mux and DAC
* waveform generation, including waveform speed.
*
* Parameters:
* none
*
* Return:
* none
*
*******************************************************************************/
static void DisplayDac(void)
{
static char* const msgs[4] = {"SIN", "SAW", "TRI", "SQR"};
/***************************************
* Global Functions
***************************************/
/*******************************************************************************
* Function Name: InitDac()
*******************************************************************************/
void InitDac(void)
{
AMux_Signal_Start();
AMux_Signal_Select(0U); /* start up looking at the potentiometer */
VDAC8_Start();
} /* end of InitDac() */
/*******************************************************************************
int8 redisplay = 0;
uint8 temp;
The myDAC.c file indexes into four tables to create wave shapes that resemble a sine wave, saw-
tooth wave, triangle wave, and a square wave. The CapSense button P0_5 controls the mux and
switches between the potentiometer and the DAC as a signal source. Successive presses on button
P0_6 switch the DAC wave generation from the sine wave to the saw tooth, to the triangle, to the
square wave, and back to the sine wave. The speed of the wave varies from 1 to 5x, and is con-
trolled with the slider. The type of wave and speed of the wave being sent to the DAC are displayed
on the LCD display.
7.4 Conclusions
The PSoC device keeps the analog processing inside the microcontroller where it is more immune to
outside noise influences. The precision analog links with the digital resources to provide an interwo-
ven system inside a single chip.
Set up the components within your project before you start the PCB layout of the project. Make sure
the routing you need is possible after adding all the components to your schematic view. Note that if
you can alter your PCB to match the suggested pin assignments from PSoC Creator, you will be able
to fit the most components and functionality into your design.
The PSoC platform allows you to add external components to the design that interact with internal
analog to achieve custom gain and filter processing in the analog domain. Keep the power required
by the internal components to a minimum to guarantee the best accuracy. Experiment with different
power settings with the analog components. Power settings have tradeoffs in speed and power.
They may also have a slight effect on settling and accuracy.
There may be a bit of frustration when you cannot probe inside the chip to find out what is happening
with analog signals. It is good practice to leave a test point on your PCB to serve as a test output
point. Simply connect the point in question to this output point during development to measure what
is happening at that particular stage.
When you are developing more complex designs, the number of items in the schematic may make it
impossible to route the analog port components to any combination of pins that you want. In this sit-
uation it is best to first add your components and build the project without locking any analog or digi-
tal components to specific pins. PSoC Creator will optimize the routing inside the chip and suggest
the best pins to use according to its algorithms. After it has built successfully with the freedom to
assign pins, start with the pins that are most needed to be in specific locations and assign a few of
them to the desired I/O pins and rebuild the project.
If you do this a few pins at a time, you will have a better idea where the conflict is compared to lock-
ing all the pins in a particular location and then wondering why PSoC Creator cannot route the proj-
ect successfully.
L
E layout guidelines 69
LCD 16, 41, 45, 68, 80, 81, 98
embedded system 6
LCD_Char_1 component 43
error checking 78
LED 23, 27
error detection 50
blinking 23–40, 45, 56
example designs continual repeating blink 38
organization 22 using a counter 39
ExecuteRiddle function 81 ledEnabled 54
external clock 47 LEDPin 56
external crystal 51 liquid crystal display See LCD
logic component 71
lookup table See LUT
F LUT 71, 76, 77, 78, 92
farmerRiddle.c 79
farmerRiddle.h 79
finger threshold 62 M
firmware 68 main.c 31, 34, 38, 44, 53, 67, 79, 96
flag 23 Master Clock 51
flow control 46 memory 6
EEPROM 7
Flash 6
G RAM 7, 47
gesturing 59 microcontrollers 6, 68, 102
global interrupt flag 34 microprocessor 7
GPIO 16 MiniProg3 17
multi touch 59
multiplexer 30
myADC.c 97
H myCapsense.c 65
hardware delay 77 myCapsense.h 66
header files 22 myDAC.c 98, 102
headers 30
Hyperterminal 54
hysteresis 62
N
noise 91
noise floor 91
I noise immunity 91
I/O logic 34 noise threshold 62
IMO 49 non return to zero See NRZ communication
initialization 34, 67 NRZ communication 57
V
Verilog 15
View menu 25
W
wave shapes 102
Workspace Explorer 19, 25
Components tab 19
Results tab 20
Source tab 19
CONTACT US
ABOUT CYPRESS
and performance in multimedia handsets. Cypress serves numerous markets, including consumer,
computation, data communications, automotive and industrial. Cypress trades on the NYSE
© 20 Cypress Semiconductor Corporation. All rights reseSWed. All other trademarks are the propFSUZPGUIFJSSFTQFDUJWFPXOFST.