Mcufriend tft not working

/* vim: set syntax=c expandtab sw=2 softtabstop=2 autoindent smartindent smarttab : /
/

  • Arbritrary wheel pattern generator
  • copyright 2014 David J. Andruczyk
  • Ardu-Stim software is free software: you can redistribute it and/or modify
  • it under the terms of the GNU General Public License as published by
  • the Free Software Foundation, either version 3 of the License, or
  • (at your option) any later version.
  • ArduStim software is distributed in the hope that it will be useful,
  • but WITHOUT ANY WARRANTY; without even the implied warranty of
  • MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  • GNU General Public License for more details.
  • You should have received a copy of the GNU General Public License
  • along with any ArduStim software. If not, see Licenses - GNU Project - Free Software Foundation

*/

#include "defines.h"
#include "ardustim.h"
#include "enums.h"
#include "comms.h"
#include "storage.h"
#include "user_defaults.h"
#include "wheel_defs.h"
#include <avr/pgmspace.h>
#include <EEPROM.h>
#include <Adafruit_GFX.h>
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;
#include <TouchScreen.h>

#include <Fonts/FreeSans9pt7b.h>
#include <Fonts/FreeSans12pt7b.h>
#include <Fonts/FreeSerif12pt7b.h>
#include <FreeDefaultFonts.h>

#define MINPRESSURE 200
#define MAXPRESSURE 1000

const int XP = 6, XM = A2, YP = A1, YM = 7;
const int TS_LEFT=952,TS_RT=125,TS_TOP=129,TS_BOT=906;

#define YP A1
#define XM A2
#define YM 7
#define XP 6
#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4

#define BLACK 0x0000
#define NAVY 0x000F
#define DARKGREEN 0x03E0
#define DARKCYAN 0x03EF
#define MAROON 0x7800
#define PURPLE 0x780F
#define OLIVE 0x7BE0
#define LIGHTGREY 0xC618
#define DARKGREY 0x7BEF
#define BLUE 0x001F
#define GREEN 0x07E0
#define CYAN 0x07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#define ORANGE 0xFDA0
#define GREENYELLOW 0xB7E0
#define PINK 0xFC9F
#define GREY 0x8410

TouchScreen ts(XP, YP, XM, YM, 200);
Adafruit_GFX_Button on_btn, off_btn;
int X,Y;

boolean sts1 =true;
boolean sts2 =true;
boolean sts3 =true;
boolean sts4 =true;
boolean sts5 =true;

/* Sensistive stuff used in ISR's /
volatile uint8_t fraction = 0;
volatile uint16_t adc5; /
POT RPM /
volatile uint16_t adc6; /
Pot Wheel select /
volatile uint32_t oc_remainder = 0;
/
Setting rpm to any value over 0 will enabled sweeping by default /
/
Stuff for handling prescaler changes (small tooth wheels are low RPM) /
volatile uint8_t analog_port = 0;
volatile bool adc5_read_complete = false;
volatile bool adc6_read_complete = false;
volatile bool reset_prescaler = false;
volatile bool normal = true;
volatile bool sweep_reset_prescaler = true; /
Force sweep to reset prescaler value /
volatile bool sweep_lock = false;
volatile uint8_t output_invert_mask = 0x00; /
Don't invert anything /
volatile uint8_t sweep_direction = ASCENDING;
volatile byte total_sweep_stages = 0;
volatile uint8_t sweep_stage = 0;
volatile uint8_t prescaler_bits = 0;
volatile uint8_t last_prescaler_bits = 0;
volatile uint8_t mode = 0;
volatile uint16_t new_OCR1A = 5000; /
sane default */
volatile uint16_t edge_counter = 0;

/* Less sensitive globals */
uint8_t bitshift = 0;
uint16_t sweep_low_rpm = 250;
uint16_t sweep_high_rpm = 4000;
uint16_t sweep_rate = 1;
volatile bool serial_upd = false;

#define pri_out 22
#define sec_out 23
#define sec_out1 24
#define sec_out2 25
#define sec_out3 26
#define sync_out 27

sweep_step SweepSteps; / Global pointer for the sweep steps */

wheels Wheels[MAX_WHEELS] = {
/* Pointer to friendly name string, pointer to edge array, RPM Scaler, Number of edges in the array */
{ dizzy_four_cylinder_friendly_name, dizzy_four_cylinder, 0.003333, 4, 360 },
{ dizzy_six_cylinder_friendly_name, dizzy_six_cylinder, 0.05, 6, 360 },
{ dizzy_eight_cylinder_friendly_name, dizzy_eight_cylinder, 0.06667, 8, 360 },
{ sixty_minus_two_friendly_name, sixty_minus_two, 1.0, 120, 360 },
{ sixty_minus_two_with_cam_friendly_name, sixty_minus_two_with_cam, 1.0, 240, 720 },
{ thirty_six_minus_one_friendly_name, thirty_six_minus_one, 0.6, 72, 360 },
{ twenty_four_minus_one_friendly_name, twenty_four_minus_one, 0.5, 48, 360 },
{ four_minus_one_with_cam_friendly_name, four_minus_one_with_cam, 0.06667, 16, 720 },
{ eight_minus_one_friendly_name, eight_minus_one, 0.13333, 16, 360 },
{ six_minus_one_with_cam_friendly_name, six_minus_one_with_cam, 0.15, 36, 720 },
{ twelve_minus_one_with_cam_friendly_name, twelve_minus_one_with_cam, 0.6, 144, 720 },
{ fourty_minus_one_friendly_name, fourty_minus_one, 0.66667, 80, 360 },
{ dizzy_four_trigger_return_friendly_name, dizzy_four_trigger_return, 0.15, 9, 720 },
{ oddfire_vr_friendly_name, oddfire_vr, 0.2, 24, 360 },
{ optispark_lt1_friendly_name, optispark_lt1, 3.0, 720, 720 },
{ twelve_minus_three_friendly_name, twelve_minus_three, 0.4, 48, 360 },
{ thirty_six_minus_two_two_two_friendly_name, thirty_six_minus_two_two_two, 0.6, 72, 360 },
{ thirty_six_minus_two_two_two_with_cam_friendly_name, thirty_six_minus_two_two_two_with_cam, 0.6, 144, 720 },
{ fourty_two_hundred_wheel_friendly_name, fourty_two_hundred_wheel, 0.6, 72, 360 },
{ thirty_six_minus_one_with_cam_fe3_friendly_name, thirty_six_minus_one_with_cam_fe3, 0.6, 144, 720 },
{ six_g_seventy_two_with_cam_friendly_name, six_g_seventy_two_with_cam, 0.6, 144, 720 },
{ buell_oddfire_cam_friendly_name, buell_oddfire_cam, 0.33333, 80, 720 },
{ gm_ls1_crank_and_cam_friendly_name, gm_ls1_crank_and_cam, 6.0, 720, 720 },
{ lotus_thirty_six_minus_one_one_one_one_friendly_name, lotus_thirty_six_minus_one_one_one_one, 0.6, 72, 360 },
{ honda_rc51_with_cam_friendly_name, honda_rc51_with_cam, 0.2, 48, 720 },
{ thirty_six_minus_one_with_second_trigger_friendly_name, thirty_six_minus_one_with_second_trigger, 0.6, 144, 720 },
{ thirty_six_minus_one_plus_one_with_cam_ngc4_friendly_name, thirty_six_minus_one_plus_one_with_cam_ngc4, 3.0, 720, 720 },
{ weber_iaw_with_cam_friendly_name, weber_iaw_with_cam, 1.2, 144, 720 },
{ fiat_one_point_eight_sixteen_valve_with_cam_friendly_name, fiat_one_point_eight_sixteen_valve_with_cam, 3.0, 720, 720 },
{ three_sixty_nissan_cas_friendly_name, three_sixty_nissan_cas, 3.0, 720, 720 },
{ twenty_four_minus_two_with_second_trigger_friendly_name, twenty_four_minus_two_with_second_trigger, 0.3, 72, 720 },
{ yamaha_eight_tooth_with_cam_friendly_name, yamaha_eight_tooth_with_cam, 0.26667, 64, 720 },
{ gm_four_tooth_with_cam_friendly_name, gm_four_tooth_with_cam, 0.06666, 8, 720 },
{ gm_six_tooth_with_cam_friendly_name, gm_six_tooth_with_cam, 0.1, 12, 720 },
{ gm_eight_tooth_with_cam_friendly_name, gm_eight_tooth_with_cam, 0.13333, 16, 720 },
{ volvo_d12acd_with_cam_friendly_name, volvo_d12acd_with_cam, 4.0, 480, 720 },
{ mazda_thirty_six_minus_two_two_two_with_six_tooth_cam_friendly_name, mazda_thirty_six_minus_two_two_two_with_six_tooth_cam, 1.5, 360, 720 },
{ mitsubishi_4g63_4_2_friendly_name, mitsubishi_4g63_4_2, 0.6, 144, 720 },
{ audi_135_with_cam_friendly_name, audi_135_with_cam, 1.5, 1080, 720 },
{ honda_d17_no_cam_friendly_name, honda_d17_no_cam, 0.6, 144, 720 },
{ mazda_323_au_friendly_name, mazda_323_au, 1, 30, 720 },
{ daihatsu_3cyl_friendly_name, daihatsu_3cyl, 0.8, 144, 360 },
{ miata_9905_friendly_name, miata_9905, 0.6, 144, 720 },
{ twelve_with_cam_friendly_name, twelve_with_cam, 0.6, 144, 720 },
{ twenty_four_with_cam_friendly_name, twelve_with_cam, 0.6, 144, 720 },
{ subaru_six_seven_name_friendly_name, subaru_six_seven, 3.0, 720, 720 },
{ gm_seven_x_friendly_name, gm_seven_x, 1.502, 180, 720 },
{ four_twenty_a_friendly_name, four_twenty_a, 0.6, 144, 720 },
{ ford_st170_friendly_name, ford_st170, 0.6, 720, 720 },
{ mitsubishi_3A92_friendly_name, mitsubishi_3A92, 0.6, 144, 720 },
};

/* Initialization */
void setup() {
serialSetup();
loadConfig();

Serial.begin(9600);
uint16_t ID = tft.readID();
tft.begin(ID);
Serial.print("TFT ID = 0x");
Serial.println(ID, HEX);
tft.setRotation(1);
tft.fillScreen(BLACK);
tft.drawRect(0, 0, 479, 320, CYAN);
tft.drawRect(5, 228, 469, 87, CYAN);
tft.fillRect(5, 228, 469, 4, CYAN);
tft.fillRect(5, 256, 469, 2, CYAN);
tft.fillRect(0, 0, 479, 5, CYAN);

tft.setTextSize(3);
tft.setCursor(257,234);
tft.setTextColor(WHITE);
tft.print("I N V E R T");
tft.setCursor(257,234);
tft.setTextColor(CYAN);
tft.print(" . . . . . ");

tft.drawTriangle(424,130,424,160,457,147,WHITE);
tft.drawTriangle(414,130,414,160,380,146,WHITE);

tft.setTextSize(2);
tft.setCursor(16,237);
tft.setTextColor(WHITE);
tft.print("MODE");

DetectButtons();
draw_BoxNButtons();
Statusbox();

LCD_Update(0);
LCD_Update(1);

cli(); // stop interrupts

/* Configuring TIMER1 (pattern generator) */
// Set timer1 to generate pulses
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;

// Set compare register to sane default
OCR1A = 1000; /* 8000 RPM (60-2) */

// Turn on CTC mode
TCCR1B |= (1 << WGM12); // Normal mode (not PWM)
// Set prescaler to 1
TCCR1B |= (1 << CS10); /* Prescaler of 1 */
// Enable output compare interrupt for timer channel 1 (16 bit)
TIMSK1 |= (1 << OCIE1A);

// Set timer2 to run sweeper routine
TCCR2A = 0;
TCCR2B = 0;
TCNT2 = 0;

// Set compare register to sane default
OCR2A = 249; /* With prescale of x64 gives 1ms tick */

// Turn on CTC mode
TCCR2A |= (1 << WGM21); // Normal mode (not PWM)
// Set prescaler to x64
TCCR2B |= (1 << CS22); /* Prescaler of 64 */
// Enable output compare interrupt for timer channel 2
TIMSK2 |= (1 << OCIE2A);

/* Configure ADC as per Sign in - Google Accounts */
// clear ADLAR in ADMUX (0x7C) to right-adjust the result
// ADCL will contain lower 8 bits, ADCH upper 2 (in last two bits)

// Set REFS1..0 in ADMUX (0x7C) to change reference voltage to the
// proper source (01)
ADMUX = B01000101;

// Clear MUX3..0 in ADMUX (0x7C) in preparation for setting the analog
// input

// Set MUX3..0 in ADMUX (0x7C) to read from AD8 (Internal temp)
// Do not set above 15! You will overrun other parts of ADMUX. A full
// list of possible inputs is available in Table 24-4 of the ATMega328
// datasheet
// ADMUX |= 8;
// ADMUX |= B00001000; // Binary equivalent

// Set ADEN in ADCSRA (0x7A) to enable the ADC.
// Note, this instruction takes 12 ADC clocks to execute
ADCSRA |= B10000000;

// Set ADATE in ADCSRA (0x7A) to enable auto-triggering.
ADCSRA |= B00100000;

// Clear ADTS2..0 in ADCSRB (0x7B) to set trigger mode to free running.
// This means that as soon as an ADC has finished, the next will be
// immediately started.
ADCSRB &= B11111000;

// Set the Prescaler to 128 (16000KHz/128 = 125KHz)
// Above 200KHz 10-bit results are not reliable.
ADCSRA |= B00000111;

// Set ADIE in ADCSRA (0x7A) to enable the ADC interrupt.
// Without this, the internal interrupt will not trigger.
ADCSRA |= B00001000;

// pinMode(7, OUTPUT); /* Debug pin for Saleae to track sweep ISR execution speed */
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(28, INPUT);
pinMode(pri_out, OUTPUT);
pinMode(sec_out, OUTPUT);
pinMode(sec_out2, OUTPUT);
pinMode(sec_out3, OUTPUT);
pinMode(sync_out, OUTPUT);
#if defined(AVR_ATmega1280) || defined(AVR_ATmega2560)
pinMode(53, OUTPUT);
pinMode(52, OUTPUT);
#endif

sei(); // Enable interrupts
// Set ADSC in ADCSRA (0x7A) to start the ADC conversion
ADCSRA |= B01000000;
/* Make sure we are using the DEFAULT RPM on startup */
reset_new_OCR1A(wanted_rpm);

} // End setup

//! ADC ISR for alternating between ADC pins 0 and 1
/*!

  • Reads ADC ports 0 and 1 alternately. Port 0 is RPM, Port 1 is for
  • future fun (possible wheel selection)
    /
    ISR(ADC_vect){
    uint16_t adc_conv;
    if (analog_port == 0)
    {
    adc5 = ADCL | (ADCH << 8);
    adc5_read_complete = true;
    adc_conv = ADCL | (ADCH << 8);
    //ADMUX |= B00000001;
    //analog_port = 1;
    /
    Trigger another conversion /
    //ADCSRA |= B01000000;
    return;
    }
    // if (analog_port == 1)
    // {
    // adc1 = ADCL | (ADCH << 8);
    // adc1_read_complete = true;
    // /
    Flip to channel 0 /
    // /
    Tell it to read ADC0, clear MUX0..3 /
    // ADMUX &= B11110000;
    // analog_port = 0;
    // /
    Trigger another conversion */
    // ADCSRA |= B01000000;
    // return;
    // }
    }

/* This is the "low speed" 1000x/second sweeper interrupt routine

  • who's sole purpose in life is to reset the output compare value
  • for timer zero to change the output RPM. In cases where the RPM
  • change per ISR is LESS than one LSB of the counter a set of modulus
  • variabels are used to handle fractional values.
    /
    ISR(TIMER2_COMPA_vect) {
    // PORTD = (1 << 7);
    if ( mode != LINEAR_SWEPT_RPM)
    {
    // PORTD = (0 << 7);
    return;
    }
    if (sweep_lock) // semaphore to protect around changes/critical sections
    {
    // PORTD = (0 << 7);
    return;
    }
    sweep_lock = true;
    if (sweep_reset_prescaler)
    {
    sweep_reset_prescaler = false;
    reset_prescaler = true;
    prescaler_bits = SweepSteps[sweep_stage].prescaler_bits;
    last_prescaler_bits = prescaler_bits;
    }
    /
    Sweep code /
    if (sweep_direction == ASCENDING)
    {
    oc_remainder += SweepSteps[sweep_stage].remainder_per_isr;
    /
    IF the total is over the threshold we increment the TCNT factor
    • for each multiple it is over by
      /
      while (oc_remainder > FACTOR_THRESHOLD)
      {
      fraction++;
      oc_remainder -= FACTOR_THRESHOLD;
      }
      if (new_OCR1A > SweepSteps[sweep_stage].ending_ocr)
      {
      new_OCR1A -= (SweepSteps[sweep_stage].tcnt_per_isr + fraction);
      fraction = 0;
      }
      else /
      END of the stage, find out where we are /
      {
      sweep_stage++;
      oc_remainder = 0;
      if (sweep_stage < total_sweep_stages)
      {
      /
      Toggle when changing stages /
      //PORTD &= ~(1<<7); /
      turn DBG pin off /
      //PORTD |= (1<<7); /
      Turn DBG pin on /
      new_OCR1A = SweepSteps[sweep_stage].beginning_ocr;
      if (SweepSteps[sweep_stage].prescaler_bits != last_prescaler_bits)
      sweep_reset_prescaler = true;
      }
      else /
      END of line, time to reverse direction */
      {
      sweep_stage--; /*Bring back within limits /
      sweep_direction = DESCENDING;
      new_OCR1A = SweepSteps[sweep_stage].ending_ocr;
      if (SweepSteps[sweep_stage].prescaler_bits != last_prescaler_bits)
      sweep_reset_prescaler = true;
      PORTD |= 1 << 7; /
      Debugginga, ascending /
      }
      /
      Reset fractionals or next round /
      }
      }
      else /
      Descending /
      {
      oc_remainder += SweepSteps[sweep_stage].remainder_per_isr;
      while (oc_remainder > FACTOR_THRESHOLD)
      {
      fraction++;
      oc_remainder -= FACTOR_THRESHOLD;
      }
      if (new_OCR1A < SweepSteps[sweep_stage].beginning_ocr)
      {
      new_OCR1A += (SweepSteps[sweep_stage].tcnt_per_isr + fraction);
      fraction = 0;
      }
      else /
      End of stage */
      {
      sweep_stage--;
      oc_remainder = 0;
      if (sweep_stage >= 0)
      {
      new_OCR1A = SweepSteps[sweep_stage].ending_ocr;
      if (SweepSteps[sweep_stage].prescaler_bits != last_prescaler_bits)
      sweep_reset_prescaler = true;
      }
      else /*End of the line */
      {
      sweep_stage++; /*Bring back within limits */
      sweep_direction = ASCENDING;
      new_OCR1A = SweepSteps[sweep_stage].beginning_ocr;
      if (SweepSteps[sweep_stage].prescaler_bits != last_prescaler_bits)
      sweep_reset_prescaler = true;
      PORTD &= ~(1<<7); /*Descending turn pin off */
      }
      }
      }
      sweep_lock = false;
      //wanted_rpm = get_rpm_from_tcnt(&SweepSteps[sweep_stage].beginning_ocr, &SweepSteps[sweep_stage].prescaler_bits);
      // PORTD = (0 << 7);
      }

/* Pumps the pattern out of flash to the port

  • The rate at which this runs is dependent on what OCR1A is set to
  • the sweeper in timer2 alters this on the fly to alow changing of RPM
  • in a very nice way
    */
    ISR(TIMER1_COMPA_vect) {
    uint8_t aux;
    aux = output_invert_mask ^ pgm_read_byte(&Wheels[selected_wheel].edge_states_ptr[edge_counter]);

switch(aux)
{
case 0:
digitalWrite(pri_out, LOW);
digitalWrite(sec_out, LOW);
digitalWrite(sec_out2, LOW);
digitalWrite(sec_out3, LOW);
break;
case 1:
digitalWrite(pri_out, HIGH);
digitalWrite(sec_out, LOW);
digitalWrite(sec_out2, LOW);
digitalWrite(sec_out3, LOW);
break;
case 2:
digitalWrite(pri_out, LOW);
digitalWrite(sec_out, HIGH);
digitalWrite(sec_out2, LOW);
digitalWrite(sec_out3, LOW);
break;
case 3:
digitalWrite(pri_out, HIGH);
digitalWrite(sec_out, HIGH);
digitalWrite(sec_out2, LOW);
digitalWrite(sec_out3, LOW);
break;
case 4:
digitalWrite(pri_out, LOW);
digitalWrite(sec_out, LOW);
digitalWrite(sec_out2, HIGH);
digitalWrite(sec_out3, LOW);
break;
case 5:
digitalWrite(pri_out, HIGH);
digitalWrite(sec_out, LOW);
digitalWrite(sec_out2, HIGH);
digitalWrite(sec_out3, LOW);
break;
case 6:
digitalWrite(pri_out, LOW);
digitalWrite(sec_out, HIGH);
digitalWrite(sec_out2, HIGH);
digitalWrite(sec_out3, LOW);
break;
case 7:
digitalWrite(pri_out, HIGH);
digitalWrite(sec_out, HIGH);
digitalWrite(sec_out2, HIGH);
digitalWrite(sec_out3, LOW);
break;
case 8:
digitalWrite(pri_out, LOW);
digitalWrite(sec_out, LOW);
digitalWrite(sec_out2, LOW);
digitalWrite(sec_out3, HIGH);
break;
default: break;
}
if (normal)
{
edge_counter++;
if (edge_counter == Wheels[selected_wheel].wheel_max_edges) {
edge_counter = 0;
}
}
else
{
if (edge_counter == 0)
edge_counter = Wheels[selected_wheel].wheel_max_edges;
edge_counter--;
}
/* The tables are in flash so we need pgm_read_byte() */

/* Reset Prescaler only if flag is set /
if (reset_prescaler)
{
TCCR1B &= ~((1 << CS10) | (1 << CS11) | (1 << CS12)); /
Clear CS10, CS11 and CS12 /
TCCR1B |= prescaler_bits;
reset_prescaler = false;
}
if(edge_counter<2)
digitalWrite(sync_out, HIGH);
else
digitalWrite(sync_out, LOW);
/
Reset next compare value for RPM changes /
OCR1A = new_OCR1A; /
Apply new "RPM" from Timer2 ISR, i.e. speed up/down the virtual "wheel" */
}

void loop()
{
uint16_t tmp_rpm = 0;
/* Just handle the Serial UI, everything else is in

  • interrupt handlers or callbacks from SerialUI.
    */

if(Serial.available() > 0) { commandParser(); }

if(mode == POT_RPM)
{
if (adc5_read_complete == true)
{
adc5_read_complete = false;
tmp_rpm = adc5 << TMP_RPM_SHIFT;
if (tmp_rpm > TMP_RPM_CAP) { tmp_rpm = TMP_RPM_CAP; }
wanted_rpm = tmp_rpm;
reset_new_OCR1A(tmp_rpm);
}
}
if(mode == POT_RPM) LCD_Update(1);

if(serial_upd)
{
LCD_Update(0);
LCD_Update(1);
serial_upd = false;
}
}

void reset_new_OCR1A(uint32_t new_rpm)
{
uint32_t tmp;
uint8_t bitshift;
uint8_t tmp_prescaler_bits;
tmp = (uint32_t)(8000000.0/(Wheels[selected_wheel].rpm_scaler * (float)(new_rpm < 10 ? 10:new_rpm)));
/* mySUI.print(F("new_OCR1a: "));
mySUI.println(tmpl);
/
get_prescaler_bits(&tmp,&tmp_prescaler_bits,&bitshift);
/

mySUI.print(F("new_OCR1a: "));
mySUI.println(tmp2);
*/
new_OCR1A = (uint16_t)(tmp >> bitshift);
prescaler_bits = tmp_prescaler_bits;
reset_prescaler = true;
}

uint8_t get_bitshift_from_prescaler(uint8_t *prescaler_bits)
{
switch (*prescaler_bits)
{
case PRESCALE_1024:
return 10;
case PRESCALE_256:
return 8;
case PRESCALE_64:
return 6;
case PRESCALE_8:
return 3;
case PRESCALE_1:
return 0;
}
return 0;
}

//! Gets RPM from the TCNT value
/*!

  • Gets the RPM value based on the passed TCNT and prescaler
  • \param tcnt pointer to Output Compare register value
  • \param prescaler_bits point to prescaler bits enum
    */
    uint16_t get_rpm_from_tcnt(uint16_t *tcnt, uint8_t prescaler_bits)
    {
    bitshift = get_bitshift_from_prescaler(prescaler_bits);
    return (uint16_t)((float)(8000000 >> bitshift)/(Wheels[selected_wheel].rpm_scaler
    (*tcnt)));
    }

//! Gets prescaler enum and bitshift based on OC value
void get_prescaler_bits(uint32_t *potential_oc_value, uint8_t *prescaler, uint8_t *bitshift)
{
if (*potential_oc_value >= 16777216)
{
*prescaler = PRESCALE_1024;
*bitshift = 10;
}
else if (*potential_oc_value >= 4194304)
{
*prescaler = PRESCALE_256;
*bitshift = 8;
}
else if (*potential_oc_value >= 524288)
{
*prescaler = PRESCALE_64;
*bitshift = 6;
}
else if (*potential_oc_value >= 65536)
{
*prescaler = PRESCALE_8;
*bitshift = 3;
}
else
{
*prescaler = PRESCALE_1;
*bitshift = 0;
}
}

//! Builds the SweepSteps[] structure
/*!

  • For sweeping we cannot just pick the TCNT value at the beginning and ending
  • and sweep linearily between them as it'll result in a VERY slow RPM change
  • at the low end and a VERY FAST change at the high end due to the inverse
  • relationship between RPM and TCNT. So we compromise and break up the RPM
  • range into octaves (doubles of RPM), and use a linear TCNT change between
  • those two points. It's not perfect, but computationally easy
  • \param low_rpm_tcnt pointer to low rpm OC value, (not prescaled!)
  • \param high_rpm_tcnt pointer to low rpm OC value, (not prescaled!)
  • \param total_stages pointer to tell the number of structs to allocate
  • \returns pointer to array of structures for each sweep stage.
    */
    sweep_step *build_sweep_steps(uint32_t *low_rpm_tcnt, uint32_t *high_rpm_tcnt, uint8_t *total_stages)
    {
    sweep_step *steps;
    uint8_t prescaler_bits;
    uint8_t bitshift;
    uint32_t tmp = low_rpm_tcnt;
    /
    DEBUG
    mySUI.print(*low_rpm_tcnt);
    mySUI.print(F("<->"));
    mySUI.println(*high_rpm_tcnt);
    */

steps = (sweep_step )malloc(sizeof(sweep_step)(*total_stages));

#ifdef MORE_LINEAR_SWEEP
for (uint8_t i = 0; i < (*total_stages); i+=2)
#else
for (uint8_t i = 0; i < (total_stages); i++)
#endif
{
/
The low rpm value will ALWAYS have the highed TCNT value so use that
to determine the prescaler value
*/
get_prescaler_bits(&tmp, &steps[i].prescaler_bits, &bitshift);

steps[i].beginning_ocr = (uint16_t)(tmp >> bitshift);
if ((tmp >> 1) < (*high_rpm_tcnt))
  steps[i].ending_ocr = (uint16_t)((*high_rpm_tcnt) >> bitshift);
else
  steps[i].ending_ocr = (uint16_t)(tmp >> (bitshift + 1)); // Half the begin value
tmp = tmp >> 1; /* Divide by 2 */
/* DEBUG
mySUI.print(steps[i].beginning_ocr);
mySUI.print(F("<->"));
mySUI.println(steps[i].ending_ocr);
*/

}
return steps;
}
void LCD_Update(bool line)
{
char buf[30];

if(!line)
{
strncpy_P(buf,Wheels[selected_wheel].decoder_name,30);
tft.setFont();
tft.setCursor(10,185);
tft.setTextColor(WHITE,BLACK);
tft.setTextSize(3);
tft.print(" ");
tft.setCursor(10,185);
tft.print(buf);

tft.setFont(&FreeSmallFont);
tft.setCursor(8,60);                                                                                           
tft.setTextColor(RED);     //POWER
tft.setTextSize(4);     
tft.print("POWER"); 
  
tft.setFont(&FreeSmallFont);
tft.setTextColor(GREENYELLOW);
tft.setTextSize(4);
tft.setCursor(8,115);
tft.print("SPEED");    //SPEED

tft.setFont(&FreeSmallFont);
tft.setTextColor(GREENYELLOW);
tft.setTextSize(2);
tft.setCursor(425,95);
tft.print("RPM"); 

tft.setFont(&FreeSmallFont);
tft.setCursor(8,170);                                                                                           
tft.setTextColor(CYAN,BLACK);       
tft.setTextSize(4);                 
tft.print("WHEEL");            
tft.setTextColor(CYAN,BLACK);

tft.setFont();
tft.setCursor(200,135);                  
tft.setTextSize(4);                   
tft.print(selected_wheel); 
tft.setCursor(105, 288);           tft.setTextSize(2);  
tft.setTextColor(CYAN,BLACK); 
tft.print(selected_wheel);   

}

else //update line 1
{
switch(mode)
{ case POT_RPM:
sprintf(buf," %5d",wanted_rpm);
break;
case LINEAR_SWEPT_RPM:
sprintf(buf,"SWP %5d %5d",sweep_low_rpm,sweep_high_rpm);
break;
case FIXED_RPM:
sprintf(buf," %5d",wanted_rpm);
break;

}  
tft.setFont();
tft.setTextColor(GREENYELLOW,BLACK);
tft.setTextSize(5);
tft.setCursor(155,75);
tft.print(buf);

}
}

void draw_BoxNButtons() {
tft.drawRoundRect(10, 280, 70, 30, 12, WHITE); tft.setTextColor(WHITE); tft.setCursor(16,262);
tft.drawRoundRect(14, 284, 62, 22, 10, GREEN); tft.setTextSize(2); //POWER
tft.fillRect(21, 288, 48, 14, BLACK); tft.print("POWER");

tft.drawRoundRect(88, 280, 70, 30, 4, WHITE); tft.setTextColor(WHITE); tft.setCursor(95,262);
tft.drawRoundRect(92, 284, 62, 22, 4, CYAN); tft.setTextSize(2); tft.print("WHEEL");
tft.fillRect(92, 285, 61, 2, CYAN); //WHEEL
tft.fillRect(92, 303, 61, 2, CYAN); tft.setCursor(93, 288); tft.setTextColor(CYAN,BLACK);
tft.setTextSize(2); tft.print("[ ]");

tft.drawRoundRect(166, 280, 70, 30, 12, WHITE); tft.setTextColor(WHITE); tft.setCursor(179,262);
tft.drawRoundRect(170, 284, 62, 22, 10, MAGENTA); tft.setTextSize(2); //MODE
tft.fillRoundRect(177, 288, 48, 14, 10, MAGENTA); tft.print("MODE");

tft.drawRoundRect(244, 280, 70, 30, 12, WHITE); tft.setTextColor(WHITE); tft.setCursor(260,262);
tft.drawRoundRect(248, 284, 62, 22, 10, RED); tft.setTextSize(2); //INVERT CKP
tft.fillRect(255, 288, 48, 14, BLACK); tft.print("CKP");

tft.drawRoundRect(322, 280, 70, 30, 12, WHITE); tft.setTextColor(WHITE); tft.setCursor(328,262);
tft.drawRoundRect(326, 284, 62, 22, 10, BLUE); tft.setTextSize(2); //INVERT CMP.A
tft.fillRect(333, 288, 48, 14, BLACK); tft.print("CMP.A");

tft.drawRoundRect(400, 280, 70, 30, 12, WHITE); tft.setTextColor(WHITE); tft.setCursor(406,262);
tft.drawRoundRect(404, 284, 62, 22, 10, YELLOW); tft.setTextSize(2); //INVERT CMP.B
tft.fillRect(411, 288, 48, 14, BLACK); tft.print("CMP.B");}

void Statusbox () {
if(!sts1)
{ tft.drawRoundRect(10, 280, 70, 30, 12, WHITE); tft.setTextColor(GREEN,BLACK); tft.setCursor(200,20);
tft.drawRoundRect(14, 284, 62, 22, 10, GREEN); tft.setTextSize(4);
tft.fillRoundRect(21, 288, 48, 14, 10, GREEN); tft.print("ON ");
}
else
{ tft.drawRoundRect(10, 280, 70, 30, 12, WHITE); tft.setTextColor(RED,BLACK); tft.setCursor(200,20);
tft.drawRoundRect(14, 284, 62, 22, 10, GREEN); tft.setTextSize(4);
tft.fillRect(21, 288, 48, 14, BLACK); tft.print("OFF");
}
if(!sts2)
{tft.drawRoundRect(166, 280, 70, 30, 12, WHITE); tft.setTextColor(WHITE,BLACK); tft.setCursor(80,237);
tft.drawRoundRect(170, 284, 62, 22, 10, MAGENTA); tft.setTextSize(2);
tft.fillRect(177, 288, 48, 14, BLACK); tft.print("MANUAL");
}
else
{tft.drawRoundRect(166, 280, 70, 30, 12, WHITE); tft.setTextColor(WHITE,BLACK); tft.setCursor(80,237);
tft.drawRoundRect(170, 284, 62, 22, 10, MAGENTA); tft.setTextSize(2);
tft.fillRoundRect(177, 288, 48, 14, 10, MAGENTA); tft.print("ANALOG");
}
if(!sts3)
{ tft.drawRoundRect(244, 280, 70, 30, 12, WHITE);
tft.drawRoundRect(248, 284, 62, 22, 10, RED);
tft.fillRoundRect(255, 288, 48, 14, 10, RED);
}
else
{ tft.drawRoundRect(244, 280, 70, 30, 12, WHITE);
tft.drawRoundRect(248, 284, 62, 22, 10, RED);
tft.fillRect(255, 288, 48, 14, BLACK);
}
if(!sts4)
{ tft.drawRoundRect(322, 280, 70, 30, 12, WHITE);
tft.drawRoundRect(326, 284, 62, 22, 10, BLUE);
tft.fillRoundRect(333, 288, 48, 14, 10, BLUE);
}
else
{ tft.drawRoundRect(322, 280, 70, 30, 12, WHITE);
tft.drawRoundRect(326, 284, 62, 22, 10, BLUE);
tft.fillRect(333, 288, 48, 14, BLACK);
}
if(!sts5)
{ tft.drawRoundRect(400, 280, 70, 30, 12, WHITE);
tft.drawRoundRect(404, 284, 62, 22, 10, YELLOW);
tft.fillRoundRect(411, 288, 48, 14, 10, YELLOW);
}
else
{ tft.drawRoundRect(400, 280, 70, 30, 12, WHITE);
tft.drawRoundRect(404, 284, 62, 22, 10, YELLOW);
tft.fillRect(411, 288, 48, 14, BLACK);
}
}

void DetectButtons()
{
if (Y>22 && Y<55)
{
if (X>437 && X<500)
{ sts1= !sts1;}
if (X>270 && X<334)
{sts2= !sts2;}
if (X>195 && X<253)
{sts3= !sts3;}
if (X>111 && X<172)
{ sts4= !sts4;}
if (X>30 && X<92)
{ sts5= !sts5;}
}
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.