Mar 24, 2015
My colleague Mike brought me an interesting problem.
In some applications it may be required to bring out PSoC s internal VREF to an external pin for example, as analog ground, or as reference to an external analog circuit. In PSoC1, this can be achieved by using the testmux . This is explained in an article that I wrote a few years back My Favorite PSoC Hacks, Connect AGND to a pin. In PSoC3 and PSoC5, VREF may be connected as input to an OpAmp buffer and routed to an external pin.
But PSoC4 does not have the option to connect the internal VREF to an OpAmp. How do we bring out VREF in PSoC4 then?
As I have explained in a previous article Measuring VDD in PSoC4, PSoC4 has an external VREF bypass on P1.7. When enabled, an external bypass capacitor of 1uF connected to P1.7 reduces noise on VREF. Below picture shows the block diagram of the SAR Reference block. Turning on the switch (outlined with the red box) routes VREF to P1.7. The switch is controlled by Bit7 of SAR_CTRL register.
This can be done either by using the ADC configuration wizard or in firmware by direct register write to the SAR_CTRL register. Once VREF is brought out to P1.7 using either of these methods, P1.7 then can be connected to the input of an OpAmp buffer and the output of the buffer connected to a pin. Though this sounds straightforward, each of these methods has some implementation issues. Let us look at these issues and the solutions.
Some engineers prefer to keep the design clean and simple by avoiding custom register writes in firmware to enable features. As I too like to keep things simple here is the first option.
Option-1 VREF on P1.7 through ADC configuration window
Let us first enable external VREF bypass by selecting Internal 1.024V, bypassed option for the VREF parameter in the ADC configuration window.
Let's then place an OpAmp configured as a Follower . Let's connect an analog pin named VREF_IN to the input of the OpAmp and another pin VREF_OUT to the output.
The next step is to assign P1.7 to VREF_IN pin and any other port pin to VREF_OUT. Now we have a problem.
In the pin assignment table in .cydwr, there is a pin ADC_SAR_Seq_1:Bypass , with the only option as P1.7. Once P1.7 is assigned to the Bypass pin, it is not possible to assign P1.7 to VREF_IN. The simplest solution to this problem is use another pin, say P1_5 as VREF_IN and externally connect P1_7 and P1_5.
However, this has a disadvantage of using an extra pin and does not work with designs with shortage of IOs. The next option is for these designs.
Option-2 VREF on P1.7 with register write
Let us choose Internal 1.024V as VREF in the ADC configuration window.
This will let us choose P1_7 as VREF_IN input to the OpAmp buffer.
All we need to do now is to enable VREF bypass by writing to the ADC s configuration register. Following code does this.
/* Enable reference bypass */
SARControlReg = CY_GET_REG32(CYREG_SAR_CTRL);
SARControlReg |= 0x00000080;
This will enable the VREF bypass switch in the SAR ADC block and will bring out VREF to P1.7. Start the OpAmp, and buffered VREF should be available on the pin connected to OpAmp s output.
There is just one more problem to solve. Notice the max ADC sample rate from the ADC configuration window in Option#1 and Option#2. When the reference is selected to Internal 1.024V, bypassed , the maximum possible ADC sample rate is 1.125Msps for a single channel ADC. When the reference is set to Internal 1.024V the maximum possible sample rate is only 100ksps. For ADC sample rate above 100ksps, external VREF bypass is a must. Though we use external bypass, as we do this in firmware, the ADC wizard does not know this and does not allow you to select a higher speed.
Then how do we get a higher sample rate from the ADC?
Option 2a VREF on P1.7 with register write and high ADC sample rate
In this method, instead of letting ADC configuration wizard to select the ADC clock, we will set the clock. In the ADC configuration window, select the Clock Source parameter to External .
This will add a pin named aclk to the ADC component. Now drag a Clock component from the components catalog (under the System folder) and connect this to ADC s aclk input.
In the clock configuration window, select HFCLK as the clock source, and set the clock to 1MHz.
If we set the clock to a higher value in the clock configuration, next time when we open ADC configuration wizard, the wizard sees the value of the external clock to be more than 1MHz and will throw an error. We will fool the wizard by setting the required clock in firmware. For example, if we need an ADC clock of 2MHz then we require a divider of 12. Use the following code in firmware to set the divider.
Now we got VREF on an external pin, without having to waste an extra IO, and also can run the ADC at a higher sample rate without offending the ADC wizard!
Choose the option that best suits your application and get a buffered VREF to an external pin.
Mar 19, 2015
For a project that I have been working on with the PSoC4 BLE, I required a PWM source with a minimum frequency of 4.4kHz with a resolution of at least 14 bits the higher the better. However with a conventional PWM, with a clock of 24MHz, a 14 bit PWM would give an output frequency of 1.464kHz, which was not enough for my application. Then I remembered having used a high frequency high resolution PWM for an audio DAC application in PSoC1 many years back. This was based on my friend and fellow PSoC1 enthusiast Victor Kremin's (a genius in exploiting PSoC1's flexible analog and digital resources) application note AN2246 PWM Source High Frequency, High Resolution. Why not port this to PSoC4 BLE?
Picture below shows the High Resolution PWM architecture. The concept is to interlace two PWM signals with different duty cycles with a third PWM signal. The third PWM signal could be another conventional PWM, or a PRS PWM. The terminal count output of PWM1 or PWM2 is the clock to the control PWM.
PWM1 and PWM2 have the same period and compare value with one PWM having a compare type Less Than , and the other Less Than or Equal To . This introduces a difference in duty cycle between the two PWMs equal to one clock. The third PWM (or PRS PWM) is used to control a mux to switch the output between these two PWMs. The effective resolution is the sum of resolution of PWM1/PWM2 + the control PWM. For a 14 bit PWM, the resolution of PWM1 and PWM2 would be 8 bits and the control PWM, 6 bits. To set the duty cycle of the output, the most significant 8 bits of the 14 bit compare value is written to PWM1 and PWM2 and the least significant 6 bits is used as compare value for the control PWM.
An important requirement for this setup to work is PWM1 and PWM2 should be started exactly at the same time to have the one clock phase shift. This is achieved by tying the enable inputs of both the PWMs together and turning them on together. In PSoC1 this is done using the output of a LUT. Also, the two to one mux is implemented using three LUTs, two with AND functions and one with OR. Below picture shows the final implementation that uses four digital blocks (only either the PRS8 in DBB00 or PWM in DCB03 need to be used in the final project), four LUTs, and three global interconnects.
And here is the PSoC4 BLE implementation of a 16 bit High Resolution PWM with a 12MHz input clock and an output frequency of 46.875kHz. I have implemented a conventional PWM for the control PWM, as a PRS PWM in PSoC4 could not use the output of another block as clock.
Below picture shows the PWM1 configuration windows.
PWM1 is configured to have two 8 bit outputs, one channel with compare type Less and the other channel with compare type Less or Equal . PWM mode is set to Hardware Select . This implements a multiplexer between the two PWM channels selected by a hardware signal. This is the cmp_sel signal input in PWM1 which is driven by PWM2. While it was necessary to simultaneously start the two PWM channels in PSoC1, in PSoC4 BLE, as the PWM is one block simultaneous starting is automatically taken care of.
PWM2 is configured for single output, with a period of 255. Below picture shows the configuration windows for PWM2.
The code for the high resolution PWM is straightforward.
/* Start PWM1 and PWM2 */
/* Stop PWM1 and PWM2 */
The HighResPWM_Start function starts both the PWMs, and the HighResPWM_Stop function stops them.
void HighResPWM_WritePulseWidth(uint16 PulseWidth)
/* The most significant 8 bits become compare value for the two PWM channels in PWM1 */
/* The least significant 8 bits become compare value for the control PWM */
The HighResPWM_WritePUlseWidth function writes the most significant 8 bits of the compare value to the two channels of PWM1 and the least significant 8 bits of the compare value to the control PWM.
The duty cycle of the HighResPWM is given by:
Duty Cycle % = (Compare Value / 65536) * 100.
Following pictures show the output of the HighResPWM at 10% and 50% duty cycles.
So, I started with a minimum requirement of a 14 bit PWM with 4.4kHz, and ended up with a 16 bit PWM with 10x the frequency. Following is the digital resource usage of the HighResPWM.
The project file may be found below.
Sep 24, 2014
PSoC4 is the latest family in the Programmable System on Chip series that offers the low-power and high performance of ARM Cortex M0 processor, programmable analog and digital that is unique to the PSoC devices and low cost you can get a PSoC4 for as low as $1.
As a new user to any microcontroller family, there are several questions that I need answered to be able to start designing with the controller.
Architecture: What are the various resources available on the controller like System resources (CPU, Clocks, GPIO), Analog peripherals (amplifiers, comparators, ADCs) and digital peripherals (timers, counters, UARTs, I2C)?
Evaluation board: Now that I understood the architecture of the device, is there an evaluation board that I can use to quickly evaluate the capabilities of the device?
Software: What software platform do I need to develop with this device?
Hardware Guidelines and Best Practices: Okay. I am now convinced this is the device of my choice. I now need to quickly create a prototype. What are the hardware considerations and best practices I need to follow power supply pins, power supply decoupling, in circuit programming and debugging, pin allocations for analog and digital peripherals etc.
There are a couple of application notes that address the above questions and will get you started with a PSoC4 design.
This application note answers #1, #2 and #3 in the above list. It covers all the basic information about the PSoC4 architecture including comparison of various device families, system resources like CPU, RAM, Flash, GPIO, low power modes, digital peripherals like timers, counters, communication interfaces and LCD display, and analog peripheral like ADCs, amplifiers and comparators. The AN also covers development tools including software and evaluation boards. In the end, the application note provides step by step instructions to create your first PSoC4 project.
This application note answers #4 above and provides hardware guidelines and best practices to create your own board with a PSoC4. The document provides information on various power supply domains, power supply pins, decoupling capacitor requirements, reset pin connection, programming/debugging connector details for in circuit programming/debugging, pin selection for analog and digital functions and tips on using analog peripherals.
What are you waiting for? Get the CY8CKIT-042, download PSoC Creator, download the two application notes and get started with PSoC4!
Mar 23, 2014
PSoC has a single GPIO interrupt vector which is common for all the GPIO pins. This poses some problems when interrupts are enabled on multiple GPIO pins. Let us discuss the problems introduced by this architecture and techniques to address these problems.
The interrupt logic of a GPIO cell is shown in figure below.
The PRTxICx registers set the type of interrupt (disabled, high, low and change from last read). The corresponding PRTxIE bit enables or disables the interrupt for the GPIO. When the interrupt is enabled in the PRTxIE register and if the interrupt condition as configured by PRTxICx occurs on the GPIO pin, the IRQ# line is asserted.
The IRQ# lines from all the GPIO cells are tied together. This creates a wired OR setup for the active LOW IRQ signal. The IRQ signal is considered edge sensitive for asserting and level sensitive for releasing the interrupt. i.e., the interrupt controller registers a GPIO interrupt when a falling edge is detected on the IRQ line, but will not register any interrupts till the IRQ line goes back to HIGH state. This creates problems in detecting multiple interrupts occurring simultaneously.
For example, consider the scenario #1 shown in figure below.
GPIO#1 is configured for high level interrupt whereas GPIO#2 is configured for low level interrupt. When GPIO#1 goes high, the IRQ line is asserted and the interrupt controller posts an interrupt. While GPIO#1 is high asserting the IRQ line, GPIO#2 too goes low asserting the IRQ signal, and goes high de-asserting it before GPIO#1 de-asserts the IRQ. As no change is registered on the IRQ line, the interrupt from GPIO#2 is not registered by the interrupt controller.
Now consider another scenario #2 shown in figure below.
In this case, GPIO#1 asserts the IRQ line. Before it de-asserts the IRQ line, GPIO#2 also asserts the IRQ line. GPIO#2 continues to assert the IRQ line even after GPIO#1 de-asserts. As there is no state change on the IRQ line, the interrupt controller does not register the interrupt from GPIO#2.
Well. How do we address these scenarios? Below are some techniques that can be used to overcome these situations.
1. As soon as a GPIO pin generates an interrupt, change the interrupt type of the GPIO (high to low or low to high). This will immediately disable the GPIO from keeping the IRQ asserted.
2. Configure the interrupt mode to Change from Read . When the interrupt is asserted, inside the ISR, read from the PRTxDR register and this will immediately de-assert the IRQ line.
3. To address extreme corner cases where another GPIO asserts the IRQ line before the interrupt type of the present GPIO is changed, keep a copy of all the pin states in a RAM variable. Every time a GPIO interrupt is triggered, check the state of all the pins and compare this with the previous state stored in the RAM variable. This way, all the pins that changed state can be detected. Before exiting the ISR, update the RAM copy with the present state of the GPIO pins.
Apart from the above techniques, if you have free digital blocks or analog blocks left, you can also route the GPIO pin to a digital buffer and enable the interrupt of that digital block, or connect the GPIO to a comparator and enable the interrupt of the comparator bus. This will provide dedicated interrupt vectors to the GPIOs.
Mar 20, 2014
Usually in battery operated applications, the microcontroller also measures the level of the battery and either displays the percentage of the battery left or generates an alarm when the battery level is getting low. There are two methods to measure battery voltage.
Method #1: In microcontrollers that have an internal ADC reference, the straightforward approach is to use a potential divider and scale down VDD to the ADC s measurement range. For example, if the internal VREF of the ADC is 1.024V, and we need to measure VDD which can vary from 3.0V to 4.2V (this is the range of a Lithium Ion battery), the following circuit may be used.
In the above circuit, R1 and R2 form a potential divider and would develop 1.024V when VDD equals 4.43V. So, for a 12 bit ADC, VDD may be measured by the following equation.
VDD = (4.43/4095) * ADC Counts
Method #2: In microcontrollers that do not have an internal ADC reference, but use VDD as the reference, we need an external reference to measure VDD.
In the above circuit, an external reference of 1.2V is connected to the ADC input. As the reference of the ADC is VDD, the ADC counts for VDD would always be 4095 counts. So, the ADC counts while measuring the external reference would be proportional to VDD. For a 12 bit ADC, VDD can now be calculated using following formula.
VDD = (1.2V * 4095) / ADC Counts
Both the above methods have a disadvantage that they require external components. We can implement the same VDD measurement in PSoC4 without using any external components. Let us see how.
Note: The resistor and zener combination in the schematic above is just a representation of an external reference voltage.
The diagram below shows the block diagram of the ADC inside PSoC4.
The input to the SAR ADC can be directly from the SARMUX in Port2 or from the AMUXBUS that can connect any pin to the ADC. The SARREF block generates the reference to the ADC. Below picture shows the SARREF block.
The reference to the ADC can be one of three voltages 1.024V, VDD or VDD/2. There is a bypass switch that brings out the output of the reference buffer to P1.7. The intent of this bypass switch is to reduce noise on the VREF by connecting an external bypass capacitor. We are going to use this bypass switch and Method #2 described earlier to measure VDD.
Following are the steps to measure VDD:
Connect an external bypass capacitor 1uF to P1.
Set the reference of ADC to VREF and enable the bypass switch. Keep the bypass enabled for a short time, say 25ms. This charges the 1uF capacitor to 1.024V.
Disable the bypass switch. Now the capacitor holds the 1.024V (like a sample and hold circuit)
Change the reference of the ADC to VDD, connect P1 as input to the ADC and measure the voltage.
VDD can then be calculated using the formula:
VDD = (1.024 * 2047) / ADC Counts P1
The SAR ADC in PSoC4 is 12 bits. Then why am I using 2047 and not 4095 in the above equation? With the ADC configured for single ended measurement, the effective resolution of the ADC becomes 11 bits and hence the full scale count of 2047.
Let us now take a look at the project. Figure below shows the schematic of the project.
Place an OpAmp configured as a buffer. Place an analog input pin and connect this pin to the input of the buffer. Assign P1 to this pin. Place an ADC and configure the ADC for a reference of VDDA (we will dynamically change this in code). Select the Single Ended Negative Input to VSSA.
Following firmware will now take care of the VDD measurement. The result is availabe in the variable "Vdd" in millivolts.
/* Start the LCD, OpAmp and ADC */
/* Set the reference to VBG and enable reference bypass */
SARControlReg = CY_GET_REG32(CYREG_SAR_CTRL);
SARControlReg &= ~0x000000F0;
SARControlReg |= 0x000000C0;
/* 25ms delay for reference capacitor to charge */
/* Set the reference to VDD and disable reference bypass */
SARControlReg = CY_GET_REG32(CYREG_SAR_CTRL);
SARControlReg &= ~0x000000F0;
SARControlReg |= 0x00000070;
/* Perform an ADC conversion */
Vref = ADC_GetResult16(0x00);
/* Calculate Vdd */
Vdd = (1024*2047)/Vref;