mpc_response_sim/simul_kl25z.cpp

536 lines
14 KiB
C++
Raw Normal View History

2020-12-11 20:04:31 +01:00
/* Simple simulator for Kinetis KL25Z MCU
* Main implementation file.
* Add this file to your project to be build with your sources.
* Requires C++11 support.
*/
#include "simul_kl25z.h"
#include <iostream>
#include <thread>
#include <mutex>
#include <time.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
2020-12-11 20:04:31 +01:00
////////////////////////////////////////////////////////////////
// Delay with time in milliseconds
void delay(unsigned int mseconds)
{
clock_t goal = mseconds + clock();
while (goal > clock() ) ;
}
// simple delay with some default value
void delay(void)
{
delay(500);
}
// clear screen
void myclear(){
2020-12-11 20:04:31 +01:00
#if defined(__linux__) || defined(__unix__) || defined(__APPLE__)
system("clear");
#endif
#if defined(_WIN32) || defined(_WIN64)
system("cls");
#endif
}
// Buffers used by drivers to print to screen
char gLEDsBuffer[256];
char gLCDBuffer[256];
// mutex to protect access to screen
std::mutex gScreenMutex;
void WriteLEDsToScreen(); // in drv_gpio
void WriteLCDToScreen(); // in drv_lcd
void WriteLEDsToBuffer(char* buffer); // in drv_gpio
void WriteLCDToBuffer(char* buffer); // in drv_lcd
/////////////////////////////////////////////////////
static SIM_Peripheral sim_peripheral_object;
SIM_Peripheral* SIM = &sim_peripheral_object;
// Port C module (needed for ADC input on port C)
static PORT_Peripheral portc_peripheral_object;
PORT_Peripheral* PORTC = &portc_peripheral_object;
//////////////////////////////////////////////////
// GPIO driver code
static bool gInitialized;
static FRDM_kit_pinmode gPinModes[LAST_PIN];
static uint8_t gPinOutputValues[LAST_PIN];
static const char* gLedNames[] = {"LD1", "LD2", "LD3", "RED", "GREEN", "BLUE" };
// Status of input pins
constexpr int MAX_SWITCHES = 4;
static bool gSwitchInputs[MAX_SWITCHES];
// mutex to protect the switch input variable
std::mutex gMutexSwitches;
// Background thread to process key press
void task1(std::string msg)
{
(void)msg;
while(1) {
char c = getchar();
2020-12-11 20:04:31 +01:00
gMutexSwitches.lock();
switch(c) {
case '1':
// toggle input state when key is pressed
gSwitchInputs[0] = !gSwitchInputs[0];
break;
case '2':
gSwitchInputs[1] = !gSwitchInputs[1];
break;
case '3':
gSwitchInputs[2] = !gSwitchInputs[2];
break;
case '4':
gSwitchInputs[3] = !gSwitchInputs[3];
break;
}
gMutexSwitches.unlock();
} // while 1
}
// Thread to process screen refresh....
void taskScreen() {
while(1) {
myclear();
2020-12-11 20:04:31 +01:00
printf("KL25Z Simulation, version %d.%d\n\n", VERSION_MAJOR, VERSION_MINOR);
gScreenMutex.lock();
printf(gLEDsBuffer);
printf(gLCDBuffer);
gScreenMutex.unlock();
// print status of switches
printf("\n\n%5c%5c%5c%5c",
gSwitchInputs[0] ? 'X' : '-',
gSwitchInputs[1] ? 'X' : '-',
gSwitchInputs[2] ? 'X' : '-',
gSwitchInputs[3] ? 'X' : '-' );
printf("\n SW1 SW2 SW3 SW4\n");
delay(80);
}
}
// This will create thread when the program starts...
std::thread t1(task1, "Hello");
std::thread t2(taskScreen);
/* Initialize the gpio driver for LEDs and push buttons. */
void GPIO_Initialize(void)
{
gInitialized = true;
for ( int i=0; i<MAX_SWITCHES; i++ )
gSwitchInputs[i] = false;
}
/* Configure given pin to behave as input or output. */
void pinMode(FRDM_kit_pin pin, FRDM_kit_pinmode mode )
{
if ( !gInitialized ) {
printf("BSOD - Default ISR :) \nGPIO driver not initialized!\n");
while (1) ;
}
switch (pin)
{
/* All LEDs are on port B */
case LD1:
case LD2:
case LD3:
case LED_RED:
case LED_GREEN:
case LED_BLUE:
case SW1:
case SW2:
case SW3:
case SW4:
gPinModes[(int)pin] = mode;
break;
default:
printf("Warning: Invalid pin %d in pinMode.\n", pin);
//while (1) ; /* Error: invalid pin! */
}
}
/* Set value for given pin. The pin must be configured as output with pinMode first! */
void pinWrite(FRDM_kit_pin pin, uint8_t value )
{
if ( !gInitialized ) {
printf("BSOD - Default ISR :) \nGPIO driver not initialized!\n");
while (1) ;
}
switch(pin)
{
/* All LEDs are on port B */
case LD1:
case LD2:
case LD3:
case LED_RED:
case LED_GREEN:
case LED_BLUE:
case SW1:
case SW2:
case SW3:
case SW4:
if ( gPinModes[(int)pin] == OUTPUT ) {
// update screen
gPinOutputValues[(int)pin] = value;
WriteLEDsToBuffer(gLEDsBuffer);
//WriteLEDsToScreen();
} else {
// do nothing
printf("Warning: Pin %d is not an output.\n", pin);
}
break;
default:
printf("Warning: Invalid pin %d in pinWrite.\n", pin);
//while(1) ; /* Error: invalid pin! */
}
}
/* Read value on given pin. The pin must be configured as input with pinMode first! */
uint8_t pinRead(FRDM_kit_pin pin)
{
if ( !gInitialized ) {
printf("BSOD - Default ISR :) \nGPIO driver not initialized!\n");
while (1) ;
}
uint8_t result = LOW;
if ( gPinModes[(int)pin] == INPUT || gPinModes[(int)pin] == INPUT_PULLUP ) {
// Background thread reads the keyboard and sets gSwitchInputs
gMutexSwitches.lock();
switch(pin)
{
case SW1:
result = (gSwitchInputs[0]) ? LOW : HIGH;
break;
case SW2:
result = (gSwitchInputs[1]) ? LOW : HIGH;
break;
case SW3:
result = (gSwitchInputs[2]) ? LOW : HIGH;
break;
case SW4:
result = (gSwitchInputs[3]) ? LOW : HIGH;
break;
default:
printf("Warning: Pin %d not supported for input in simulator.\n", pin);
break;
}
gMutexSwitches.unlock();
} else {
printf("Warning: Pin %d is not an input.\n", pin);
}
return result;
}
// Helpers to print LED state to console
#define GET_LED_SYMBOL(a) ((a == 0) ? 'X' : '-')
#define PRINT_LED_FROM_MODE(mode, value) ((mode == OUTPUT) ? GET_LED_SYMBOL(value) : '-')
void WriteLEDsToBuffer(char* buffer) {
char buff[512];
gScreenMutex.lock();
buffer[0] = '\0';
sprintf(buff, "%5c%5c%5c\t\t%3c%3c%3c\n",
PRINT_LED_FROM_MODE(gPinModes[0], gPinOutputValues[0]),
PRINT_LED_FROM_MODE(gPinModes[1], gPinOutputValues[1]),
PRINT_LED_FROM_MODE(gPinModes[2], gPinOutputValues[2]),
PRINT_LED_FROM_MODE(gPinModes[3], gPinOutputValues[3]),
PRINT_LED_FROM_MODE(gPinModes[4], gPinOutputValues[4]),
PRINT_LED_FROM_MODE(gPinModes[5], gPinOutputValues[5])
);
strcat(buffer, buff);
sprintf(buff, "%5s%5s%5s\t\t%s/%s/%s\n", gLedNames[0], gLedNames[1], gLedNames[2],
gLedNames[3], gLedNames[4], gLedNames[5]);
strcat(buffer, buff);
gScreenMutex.unlock();
}
void WriteLEDsToScreen() {
printf("%5c%5c%5c\t\t%3c%3c%3c\n",
PRINT_LED_FROM_MODE(gPinModes[0], gPinOutputValues[0]),
PRINT_LED_FROM_MODE(gPinModes[1], gPinOutputValues[1]),
PRINT_LED_FROM_MODE(gPinModes[2], gPinOutputValues[2]),
PRINT_LED_FROM_MODE(gPinModes[3], gPinOutputValues[3]),
PRINT_LED_FROM_MODE(gPinModes[4], gPinOutputValues[4]),
PRINT_LED_FROM_MODE(gPinModes[5], gPinOutputValues[5])
);
printf("%5s%5s%5s\t\t%s/%s/%s\n", gLedNames[0], gLedNames[1], gLedNames[2],
gLedNames[3], gLedNames[4], gLedNames[5]);
}
// end GPIO driver code
//////////////////////////////////////////////////
//////////////////////////////////////////////////
// ADC code
// Simulated ADC values
static uint16_t adc_values[] = { 10, 30, 60, 100, 110, 120, 130, 140, 150, 170, 200, 230, 255,
230, 200, 170, 150, 130, 100, 60, 30, 0, 0 };
static int MAX_ADC_VALUES = sizeof(adc_values)/sizeof(uint16_t);
// Define the ADC0 module for use in user program
static ADC_Peripheral adc_module_object;
ADC_Peripheral* ADC0 = &adc_module_object;
void AdcValueWrite(unsigned int data) {
(void)data; // just to remove unused param warning
ADC0->UpdateData();
}
// handler for write to CFG1[0] only to indicate we have valid settings
void AdcStartConversion(unsigned int data) {
//std::cout << "Start conversion " << data << '\n';
// For our pin - channel 11 check the pin config, for other channels just
// skip test and simulated that conversion completed. This is needed for
// calibration etc.
int channel = (data & ADC_SC1_ADCH_MASK) >> ADC_SC1_ADCH_SHIFT;
if ( channel == 11 ) {
if ( ADC0->IsPinConfigValid() )
ADC0->mConversionStarted = true;
} else {
// conversion must be started for any other channel, also for calibration
ADC0->mConversionStarted = true;
}
ADC0->UpdateData();
}
void ADC_Peripheral::UpdateData()
{
// test if clock is enabled
if ( (SIM->SCGC6 & SIM_SCGC6_ADC0_MASK) == 0 ) {
printf("BSOD - Default ISR :) \nADC - clock not enabled!\n");
while (1) ;
}
if ( mConversionStarted ) {
// get next value for ADC if channel is 11
if ( (SC1[0] & 0x1F) == ADC_SC1_ADCH(11) ) {
// rozliseni
int mode = (CFG1 & ADC_CFG1_MODE_MASK) >> ADC_CFG1_MODE_SHIFT;
int shift = 0;
switch ( mode) {
case 0: // 8 bit
shift = 0;
PRINT_DGMSG("ADC resolution is 8 bit.");
break;
case 1: // 12 bit
shift = 4;
PRINT_DGMSG("ADC resolution is 12 bit.");
break;
case 2: // 10 bit
shift = 2;
PRINT_DGMSG("ADC resolution is 10 bit.");
break;
case 3: // 16 bit
shift = 8;
PRINT_DGMSG("ADC resolution is 16 bit.");
break;
}
R[0].data = adc_values[mCurrentDataIndex++] << shift;
if ( mCurrentDataIndex >= MAX_ADC_VALUES )
mCurrentDataIndex = 0;
}
SC1[0].data |= ADC_SC1_COCO_MASK; // set conversion complete flag
mConversionStarted = false;
}
}
// end ADC driver code
//////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// LCD driver code
static bool gLcdInitialized;
static char gDispData[4][21];
static int gRow, gColumn;
void WriteLCDToScreen() {
//clear();
printf("\n\nLCD-----------------\n");
//printf("123456789ABCDEFGHIJK\n");
for ( int i=0; i<4; i++ )
printf("%s\n", gDispData[i]);
printf("---------------------\n");
}
void WriteLCDToBuffer(char* buffer) {
//clear();
char buff[512];
gScreenMutex.lock();
buffer[0] = '\0';
sprintf(buff, "\n\nLCD-----------------\n");
strcat(buffer, buff);
//printf("123456789ABCDEFGHIJK\n");
for ( int i=0; i<4; i++ ) {
sprintf(buff, "%s\n", gDispData[i]);
strcat(buffer, buff);
}
sprintf(buff, "---------------------\n");
strcat(buffer, buff);
gScreenMutex.unlock();
}
/* initialize display */
void LCD_initialize(void)
{
gLcdInitialized = true;
gRow = 0; // 1 - 4
gColumn = 0; // 1 - 20
}
void LCD_set_cursor(uint8_t line, uint8_t column) {
if ( line > 0 && line < 5)
gRow = line - 1;
if ( column > 0 && column < 21 )
gColumn = column - 1;
}
void LCD_putch(char c) {
if ( !gLcdInitialized ) {
printf("BSOD - Default ISR :) \nLCD driver not initialized!\n");
while (1) ;
}
if ( gColumn > 19 ) {
printf("Warning: LCD writing beyond last column!\n");
return;
}
if ( gRow > 3 ) {
printf("Warning: LCD writing below last line!\n");
return;
}
gDispData[gRow][gColumn] = c;
gColumn++;
if ( gColumn > 19 )
gColumn = 0;
// update screen
WriteLCDToBuffer(gLCDBuffer);
}
void LCD_puts(const char* str) {
if ( !gLcdInitialized ) {
printf("BSOD - Default ISR :) \nLCD driver not initialized!\n");
while (1) ;
}
char* p = gDispData[gRow];
int len = 20 - gColumn;
if ( len > 0) {
strncpy(p + gColumn, str, len);
gDispData[gRow][gColumn+len] = '\0';
gColumn += strlen(str);
} else {
printf("Warning: LCD writing beyond last column!\n");
return;
}
WriteLCDToBuffer(gLCDBuffer);
}
void LCD_clear(void) {
if ( !gLcdInitialized ) {
printf("BSOD - Default ISR :) \nLCD driver not initialized!\n");
while (1) ;
}
gRow = 0; // 1 - 4
gColumn = 0;
for ( int i = 0; i<4; i++ ) {
for ( int j = 0; j<20; j++) {
gDispData[i][j] = ' ';
}
}
WriteLCDToBuffer(gLCDBuffer);
}
void LCD_backlight_on(void) {
printf("Warning: LCD_backlight_on not implemented.\n");
}
void LCD_backlight_off(void) {
printf("Warning: LCD_backlight_off not implemented.\n");
}
// end LCD driver code
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
// SYSTICK driver code
// Simulate systick driver functions
// Functions implemented in simul_kl25z.cpp
void SYSTICK_initialize(void)
{
// do nothing
}
uint32_t SYSTICK_millis(void)
{
return (uint32_t)clock();
}
uint32_t SYSTICK_micros(void)
{
return SYSTICK_millis() * 1000;
}
void SYSTICK_delay_ms(uint32_t millis)
{
delay(millis);
}
// end SYSTICK driver code
//////////////////////////////////////////////////////////////////