Code Examples Forum Discussions
I decided to create a tutorial on various design strategies of reading multiple digital inputs (up to 16) and calculating each frequency.
Although intended to help students and those new to embedded processing, it can be used by anyone for the attached example projects and as a refresher.
I've attached a workspace with 8 projects each implementing different methods in different combinations. Each project is an improvement on the previous one.
Here are the different methods used:
- Polling
- Interrupt Service Routines (ISRs)
- Status Register Capture (SRs)
- Direct Memory Access (DMA)
- Multi-sample Averaging
- Frequency Down-scaling
I've also attached a document describing each of the 8 projects with:
- Theory of Operation
- Design Tradeoffs
- Design Improvements
- Design Scalability.
The document includes Appendices about:
- Measurement Accuracy
- Jitter Factors
- Measurement Range
- Measurement Resolution
Requirements:
- PSoC Creator 4.2
Target Hardware:
- CY8CKIT-059. However, little to no modifications need to be make to work on other PSoC5 platforms. Many of the projects can be modified to run on other PSoC chips.
The example code is free to be used and modified for your own projects.
Enjoy!
Len
Show LessHi,
We were wondering if we can have multiplexed input for ADC_DelSig.
Reading the datasheet of ADC_DelSig, it seemed to be possible.
So I tried one with CY8CKIT-059.
schematic
To test the behavior, I also added a couple of WaveDAC8s
One generates a sine wave, and the other generates a square wave.
And AMuxHw is controlled from Control_Reg.
To test, please connect following pins with jumper wires
P3[0] and P1[7]
P3[1] and P1[6]
The result viewed via SerialPlot was
So, yes, it is working.
Pins
main.c
Note: As usual, I cheated by using my tty_utils library,
But you could replace
tty_init() with UART_Start()
print() with UART_PutString()
if you don't want to use that library.
(You may need to comment out splash() though)
====================
#include "project.h"
#include "stdio.h"
#include "tty_utils.h"
#define DATA_NUM 1024
uint16_t data[2][DATA_NUM] ;
volatile int pit_flag = 0 ;
volatile int ch = 0 ;
volatile int data_index = 0 ;
volatile int data_full = 0 ;
CY_ISR(pit_isr)
{
pit_flag = 1 ;
Counter_ReadStatusRegister() ;
Control_Reg_Write(ch) ;
ADC_BUSY_Write(1) ;
ADC_StartConvert() ;
ADC_IsEndConversion(0) ;
ADC_BUSY_Write(0) ;
data[ch][data_index] = ADC_GetResult32() ;
ch++ ;
if (ch > 1) {
data_index++ ;
ch = 0 ;
if (data_index >= DATA_NUM) {
Counter_Stop() ;
data_full = 1 ;
data_index = 0 ;
}
}
}
void init_hardware(void)
{
CyGlobalIntEnable; /* Enable global interrupts. */
tty_init() ;
ADC_Start() ;
WaveDAC8_1_Start() ;
WaveDAC8_2_Start() ;
pit_int_ClearPending() ;
pit_int_StartEx(pit_isr) ;
}
int32_t measure(int ch)
{
int32_t value ;
Control_Reg_Write(ch) ;
ADC_BUSY_Write(1) ;
ADC_StartConvert() ;
ADC_IsEndConversion(0) ;
ADC_BUSY_Write(0) ;
value = ADC_GetResult32() ;
if (value < 0) {
value = 0 ;
}
return(value) ;
}
int main(void)
{
int i ;
init_hardware() ;
splash("DelSig ADC 2ch mux test") ;
Counter_Start() ;
for(;;) {
if (data_full) {
data_full = 0 ;
for (i = 0 ; i < DATA_NUM ; i++ ) {
snprintf(str, STR_BUF_LEN, "%d %d\n\r", data[0], data[1]) ;
print(str) ;
CyDelay(1) ;
}
Counter_Start() ;
}
}
}
====================
moto
Show LessHi,
=== precaution ===
There was a discussion/request for a garage door opener sample using PSoC 5LP (CY8CKIT-059)
As discussed in the thread, it is dangerous and probably prohibited to install/use the system developed by an amateur
especially without certification for such applications.
So this example is an idea sketch and is not intended to be used with real hardware which can cause a human injury or worse.
================
Having written above, here is my trial with CY8CKIT-059.
schematic
Digital Input
SW : Switch button input to operate the system. (active-low)
full_open: Sensor switch which will detect that the garage door is fully open. (active-low)
full_close: Sensor switch which will detect that the garage door is fully close. (active-low)
motion: Input from the motion sensor. (Although IR E18-D50INK is active-high, I just used an active-low switch for this test)
Digital Output:
UP_MOTOR: Motor switch signal to open (up) the garage door. (active-high)
DOWN_MOTOR: Motor switch signal to close (down) the garage door (active-high)
Needless to say, these two output is too weak to drive real motor, external relays or drivers needed to be applied.
LCD and ADC1:
This was added to support the light sensor (LDR GL55) but as I don't have the LCD nor the Sensor
I only tested it with an external POT via UART.
UART:
As usual for monitoring the activity of the system.
Pins
code description
usual utility functions
void print(char *str) : print str to UART
void locate(int x, int y) : move cursor to position (x, y) in the serial terminal, supporting vt100 sequence
void cls(void) : reset and clear the screen of the serial terminal
void splash(char *str) : display start up message with the compiled date and time.
State Values
ST_DOOR_ERROR /* An Error detected, the system is halted */
ST_DOOR_CLOSED /* The door is totally closed */
ST_DOOR_CLOSING /* The door is in the middle of closing */
ST_DOOR_STOPPED /* The door is stopped somewhere between fully opened and fully closed */
ST_DOOR_OPENING /* The door is in the middle of opening */
ST_DOOR_OPENED /* The door is totally opened */
Time parameters
DOOR_OPEN_DURATIN 300 The door closes automatically after opened for 5min without motion
MOTOR_UP_DURATION 60 The maximum running time of door opening motor
MOTOR_DOWN_DURATION 60 The maximum running time of door closing motor
SysTick related functions
CY_ISR(tick_callback) : called each 1ms by SysTick and keeping track of current_state_time
int find_empty_slot(void) : find an unused SysTick slot
void init_hardware(void)
initializes components, ADC1, LCD, UART and SysTick
also writes 0 to DOWN_MOTOR output and UP_MOTOR output
void measure_light(void)
measures light sensor's value using ADC1
print the result to LCD and UART
currently LCD is not used, to activate LCD change definition of USE_LCD from 0 to 1
void change_status(uint8_t current, uint8_t next)
reset current_state_time to 0
saves current status as prev_status
changes door_status from current to next
void poll_status(void)
check conditions of each switches
motion_flag : status of motion input
full_opened_flag : status of full_open input
full_closed_flag : status of full_closed input
if both full_opened_flag and full_closed_flag is true, treat it as error
and change_status to ST_DOOR_ERROR
void do_state_closed(void)
process of when the door is fully closed.
motion input is ignored
SW input changes the state to ST_DOOR_OPENING
void do_state_closing(void)
process of during the door is closing
UP_MOTOR <= 0
DOWN_MOTOR <= 1
motion input changes the state to ST_DOOR_STOPPED
SW input changes the state to ST_DOOR_STOPPED
full_close input changes the state to ST_DOOR_CLOSED
if current_state_time exceeds MOTOR_DOWN_DURATION changes the state to ST_DOOR_ERROR
void do_state_stopped(void)
process of during the door is stopped bitween full_open and full_close
motion input is ignored
SW input (starts the movement in the reverse direction)
if prev_status was ST_DOOR_OPENING changes the state to ST_DOOR_CLOSING
if prev_status was ST_DOOR_CLOSING changes the state to ST_DOOR_OPENING
void do_state_opening(void)
process of during the door is opening
UP_MOTOR <= 1
DOWN_MOTOR <= 0
motion input changes the state to ST_DOOR_STOPPED (maybe this can be ignored though)
SW input changes the state to ST_DOOR_STOPPED
full_open input changes the state to ST_DOOR_OPNED
if current_state_time exceeds MOTOR_UP_DURATION changes the state to ST_DOOR_ERROR
void do_state_opned(void)
process of during the door is fully opened
motion input resets current_state_time to 0
SW input changes the state to ST_DOOR_CLOSING
if current_state_time exceeds DOOR_OPEN_DURATION changes the state to ST_DOOR_CLOSING
main.c (the whole enchilada)
=======================
/***
* Prototype for a garage door opener
* This program is intended for experiment
* Not for the real use.
*
*/
#include "project.h"
#include "stdio.h"
#include "math.h"
void poll_status(void) ;
#define ESC '\033'
#define STR_BUF_LEN 32
char str[STR_BUF_LEN+1] ;
#define USE_LCD 0
void print(char *str)
{
UART_PutString(str) ;
}
void locate(int x, int y)
{
sprintf(str,"%c[%d;%dH",ESC,y,x) ;
print(str) ;
}
void cls(void)
{
print("\033c") ; /* reset */
CyDelay(100) ;
print("\033[2J") ; /* clear screen */
CyDelay(100) ;
}
void splash(char *title)
{
cls() ;
if (title && *title) {
print(title) ;
print(" ") ;
}
snprintf(str, STR_BUF_LEN, "(%s %s)\n\r", __DATE__, __TIME__) ;
print(str) ;
}
/*
* garage door specific
*/
#define ST_DOOR_ERROR 0x00
#define ST_DOOR_CLOSED 0x01
#define ST_DOOR_CLOSING 0x02
#define ST_DOOR_STOPPED 0x03
#define ST_DOOR_OPENING 0x04
#define ST_DOOR_OPENED 0x05
#define DOOR_OPEN_DURATIN 300 /* 5 min = 5 * 60 = 300 */
#define MOTOR_UP_DURATION 60
#define MOTOR_DOWN_DURATION 60
char *state_name[] = {
"Door Error",
"Door Closed",
"Door Closing",
"Door Stopped",
"Door Opening",
"Door Opened"
} ;
volatile int motion_flag = 0 ;
volatile uint32_t current_state_time = 0 ;
int sw_flag = 0 ;
int full_opened_flag = 0 ;
int full_closed_flag = 0 ;
uint8_t door_status = ST_DOOR_CLOSED ;
uint8_t prev_status = ST_DOOR_CLOSED ;
volatile uint32_t tick_count = 0 ;
volatile int sec_flag = 0 ;
volatile int poll_flag = 0 ;
int sys_tick_slot = 0 ;
CY_ISR(tick_callback)
{
tick_count++ ;
if ((tick_count % 1000) == 0) { /* 1sec passed */
current_state_time++ ;
sec_flag = 1 ;
}
}
int find_empty_slot(void)
{
int result = -1 ;
uint32_t i ;
for (i = 0 ; i < CY_SYS_SYST_NUM_OF_CALLBACKS ; i++ ) {
if (CySysTickGetCallback(i) == NULL) {
result = i ;
break ;
}
}
return(result) ;
}
void init_hardware(void)
{
CyGlobalIntEnable; /* Enable global interrupts. */
DOWN_MOTOR_Write(0) ; /* down motor off */
UP_MOTOR_Write(0) ; /* up motor off */
ADC1_Start() ;
LCD_Start() ;
UART_Start() ;
sys_tick_slot = find_empty_slot() ;
if (sys_tick_slot < 0) {
print("Sorry No empty SysTick Slot available\n\r") ;
while(1) { } /* halting here */
} else {
CySysTickStart() ;
CySysTickSetCallback(sys_tick_slot, tick_callback) ;
}
}
void measure_light(void)
{
float lux ;
float32 raw, conv ;
ADC1_StartConvert() ;
ADC1_IsEndConversion(ADC1_WAIT_FOR_RESULT) ;
raw = ADC1_GetResult16(0) ;
conv = ((5.000000 * raw)/1024) * 0.232 ;
lux = ((2500/conv) - 500) / 5 ;
if (lux < 0) {
lux = 0 ;
}
sprintf(str, "%d.%01d Lux", (int)lux, ((int)lux * 10)%10) ;
#if USE_LCD
LCD_Position(1, 7) ;
CyDelay(200) ;
#endif
// locate(7, 1) ;
print(str) ;
print("\n\r") ;
}
void change_status(uint8_t current, uint8_t next)
{
print("Status: ") ;
print(state_name[current]) ;
print(" -> ") ;
print(state_name[next]) ;
print("\n\r") ;
current_state_time = 0 ;
prev_status = current ;
door_status = next ;
}
void poll_status(void)
{
sw_flag = (SW_Read() == 0) ? 1 : 0 ;
motion_flag = (motion_Read() == 0) ? 1 : 0 ; /* for testing, The sensor is active High */
full_opened_flag = (full_open_Read() == 0) ;
full_closed_flag = (full_close_Read() == 0) ;
if (full_opened_flag && full_closed_flag) {
print("Both full-open and full-close are active!\n\r") ;
change_status(door_status, ST_DOOR_ERROR) ;
}
}
void do_state_closed(void)
{
UP_MOTOR_Write(0) ;
DOWN_MOTOR_Write(0) ;
if (motion_flag) {
motion_flag = 0 ;
} else if (sw_flag) {
sw_flag = 0 ;
change_status(ST_DOOR_CLOSED, ST_DOOR_OPENING) ;
}
}
void do_state_closing(void)
{
UP_MOTOR_Write(0) ;
DOWN_MOTOR_Write(1) ;
if (motion_flag) {
motion_flag = 0 ;
change_status(ST_DOOR_CLOSING, ST_DOOR_STOPPED) ;
} else if (sw_flag) {
sw_flag = 0 ;
change_status(ST_DOOR_CLOSING, ST_DOOR_STOPPED) ;
} else if (current_state_time > MOTOR_DOWN_DURATION) {
print("Closing duration time exceeded!\r\n") ;
change_status(ST_DOOR_CLOSING, ST_DOOR_ERROR) ;
} else if (full_closed_flag) {
print("Door fully closed!\n\r") ;
change_status(ST_DOOR_CLOSING, ST_DOOR_CLOSED) ;
}
}
void do_state_stopped(void)
{
UP_MOTOR_Write(0) ;
DOWN_MOTOR_Write(0) ;
if (motion_flag) {
motion_flag = 0 ;
/* do nothing here */
} else if (sw_flag) {
CyDelay(50) ;
sw_flag = 0 ;
switch(prev_status) {
case ST_DOOR_OPENING:
change_status(ST_DOOR_STOPPED, ST_DOOR_CLOSING) ;
break ;
case ST_DOOR_CLOSING:
change_status(ST_DOOR_STOPPED, ST_DOOR_OPENING) ;
break ;
default:
change_status(ST_DOOR_STOPPED, ST_DOOR_ERROR) ;
break ;
}
}
}
void do_state_opening(void)
{
UP_MOTOR_Write(1) ;
DOWN_MOTOR_Write(0) ;
if (motion_flag) {
motion_flag = 0 ;
change_status(ST_DOOR_OPENING, ST_DOOR_STOPPED) ;
} else if (sw_flag) { /* sw was pushed, stop openning */
sw_flag = 0 ;
change_status(ST_DOOR_OPENING, ST_DOOR_STOPPED) ;
} else if (current_state_time > MOTOR_UP_DURATION) {
print("Opening duration time exceeded!\r\n") ;
change_status(ST_DOOR_OPENING, ST_DOOR_ERROR) ;
} else if (full_opened_flag) {
print("Door fully opened!\n\r") ;
change_status(ST_DOOR_OPENING, ST_DOOR_OPENED) ;
}
}
void do_state_opened(void)
{
UP_MOTOR_Write(0) ;
DOWN_MOTOR_Write(0) ;
if (motion_flag) {
motion_flag = 0 ;
current_state_time = 0 ;
} else if (sw_flag == 1) {
sw_flag = 0 ;
change_status(ST_DOOR_OPENED, ST_DOOR_CLOSING) ;
} else if (current_state_time > DOOR_OPEN_DURATIN) {
print("Idle Time Exceeded, Closing the door\n\r") ;
change_status(ST_DOOR_OPENED, ST_DOOR_CLOSING) ;
}
}
void do_state_error(void)
{
UP_MOTOR_Write(0) ;
DOWN_MOTOR_Write(0) ;
print("ERROR Condition Detected!\n\r") ;
for (;;) { } /* halt here */
}
void do_state_machine(void)
{
switch(door_status) {
case ST_DOOR_CLOSED: do_state_closed() ; break ;
case ST_DOOR_CLOSING: do_state_closing() ; break ;
case ST_DOOR_STOPPED: do_state_stopped() ; break ;
case ST_DOOR_OPENING: do_state_opening() ; break ;
case ST_DOOR_OPENED: do_state_opened() ; break ;
default:
door_status = ST_DOOR_ERROR ;
do_state_error() ;
break ;
}
}
int main(void)
{
init_hardware() ;
splash("CY8CKIT-059 garage door algorithm test") ;
for(;;)
{
/*
if (sec_flag) {
sec_flag = 0 ;
measure_light() ;
}
*/
poll_status() ;
if (motion_flag) {
print("Motion Detected!\n\r") ;
CyDelay(100) ; /* debouncing */
} else if (sw_flag) {
print("SW pushed!\n\r") ;
CyDelay(100) ; /* debouncing */
}
do_state_machine() ;
CyDelay(100) ;
}
}
=======================
Tera Term log (test cases)
First I tested the "normal" operation.
After resetting the board
(1) I pushed SW and the mode changed from Door Closed to Door Opening
(2) I pushed full_open and the mode changed from Door Opening to Door Opened
(3) I pushed SW and the mode changed from Door Opened to Door Closing
(4) I pushed full_close and the mode changed from Door Closing to Door Closed.
Then I tested door stop and reverse by the SW
(5) I pushed SW and the mode changed from Door Closed to Door Opening
(6) I pushed SW and the mode changed from Door Opening to Door Stopped
(7) I pushed SW and the mode changed from Door Stopped to Door Closing (Note: Direction is reversed)
(8) I pushed SW and the mode changed from Door Closing to Door Stopped
I reset the system.
(9) I pushed SW and the mode changed from Door Closed to Door Opening
(10) I kept the system untouched more than a min.
Then UP_MOTOR_DURATION time exceeded and the mode changed from Door Opening to Door Error
I reset the system
(11) I pushed SW and the mode changed from Door Closed to Door Opening
(12) I pushed full_open and the mode changed from Door Opening to Door Opened
(13) I pushed SW and the mode changed from Door Opened to Door Closing
(14) I kept the system untouched more than a min.
The DOWN_MOTOR_DURATION time exceeded and the mode changed from Door Closing to Door Error
I reset the system
(15) I pushed SW and the mode changed from Door Closed to Door Opening
(16) I pushed full_open and the mode changed from Door Opening to Door Opened
(17) I kept the system untouched more than 5 min (300 sec).
The DOOR_OPEN_DURATIN time exceeded and the mode changed from Door Opened to Door Closing
(18) I pushed full_close and the mode changed from Door Closing to Door Closed.
moto
Show LessHello:
I Have been following along on the video PSoC 6 101 lesson 3-2a creating a BLE custom service... PSoC 6 101: Lesson 3-2a Creating a BLE Custom Service for Robotic Arm Project (MainController) - YouTube
At about 6:55 into the video Alan introduces a function called genericEventHandler(...), He "magickly" pasted this into main_cm4.c without any explaination of where it came from etc. It was not covered in any previous lesson. Also there was a comment that says "all of the code for these tutorials is on GitHub.
Can someone / anyone please tell me where exactly in GetHub that example is ?
Thanks
Brian F.
Show LessHello,
I have prepared a sample project to set parameters in a 2-dimensional array from Bridge Panel Control with EZI2C.
I have attached the script for Bridge Panel Control.
Best regards,
Yocchi
Show LessHello,
The sample code of the following thread has been changed for PC terminal software.
KBA225808 for CSD V7.0 with CY8CKIT-145-40XX
The configuration of the terminal software is as follows.
This is the execution result.
Best regards,
Yocchi
Show LessHello,
I have prepared a sample project to set parameters in a 2-dimensional array from Bridge Panel Control with I2C slave.
I changed EZI2C to I2C slave.
The operation on the Bridge Control Panel is the same, so refer to the Thread below.
Set parameters to two-dimensional array with EZI2C for CY8CKIT-145-40XX
Best regards,
Yocchi
Show LessHi all,
I make a CE which I2S in PSoC6 for CM4. This is a loopback program that divides data into two buffer for L / R using DMA.
The environment used is as follows:
・PSoC Creator 4.4
・CY8CKIT-062-BLE
・I2S format: 24bit 2word 1bit Delay
The array data of Tx or Rx is divided in half. The upper part is L and the lower part is R.
DMA Settings:
For Tx
For Rx
The circuit:
The observed waves and Rx Buffer values:
Thanks,
Kenshow
Show LessHi all,
I make a CE which is I2S separate mode in PSoC6. The I2S component is introduced the KBA “Import UDB-based I2S Component in a PSoC 6 MCU Project (PSoC Creator) – KBA229971”. This is simple loopback program.
The environment used is as follows:
・PSoC Creator 4.4
・CY8CKIT-062-BLE
・I2S format: 24bit 2word 1bitDelay
Thanks,
Kenshow
Show LessHi all,
PSoC6, which is already using one I2S, was requested to have another I2S. Fortunately, I was able to find a KBA “Import UDB-based I2S Component in a PSoC 6 MCU Project (PSoC Creator) – KBA229971” that showed how I2S could be represented in UDB. However, when I tried to implement it on PSoC Creator, I noticed that there was no CE for PSoC 6. I discussed in I2S using UDB.
It didn't work at first, but I finally created a program that works on PSoC 6, so I post it here.
The environment used is as follows:
・PSoC Creator 4.4
・CY8CKIT-062-BLE
・I2S format: 24bit 2word 1bitDelay
Thanks,
Kenshow
Show Less