ATmega1284 TWI i2c

My sketch works using ATmega328p, but after changing to ATmega1284 my sketch hangs at startup, im using mightycore dip40 pinout

my sketch has this line

// Digipot initial settings, saved in its EEPROM.
    // Depends on i2c_init(). Hangs setup if no pot present..........
    pot_init();

the sketch also uses a file called HW_I@CMaster.h

/* TWI hardware is used. You have to use
 * the standard SDA/SCL pins (and, of course, the chip needs to support
 * this).

Anyone know why i2c isn't working with ATmega1284 ?

HW_I@CMaster.h File

/* Based on :
 *  
 * Arduino SoftI2C library. Uses only the HW implementation.
 *
 * Version 1.4
 *
 * Copyright (C) 2013, Bernhard Nebel and Peter Fleury
 *
 * This is a very fast and very light-weight software I2C-master library 
 * written in assembler. It is based on Peter Fleury's I2C software
 * library: http://homepage.hispeed.ch/peterfleury/avr-software.html
 * Recently, the hardware implementation has been added to the code,
 * which can be enabled by defining I2C_HARDWARE.
 *
 * This Library 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.
 *
 * This Library 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 the Arduino I2cMaster Library.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

/* TWI hardware is used. You have to use
 * the standard SDA/SCL pins (and, of course, the chip needs to support
 * this).
 *
 * You can also define the following constants (see also below):
 * - I2C_CPUFREQ, when changing CPU clock frequency dynamically
 * - I2C_MAXWAIT = 0..32767 number of retries in i2c_start_wait. 0 means never stop.
 */

#ifndef HW_I2CM_H
#define HW_I2CM_H


#ifndef __AVR_ARCH__
#error "Not an AVR MCU! Use 'SlowSoftI2CMaster'!"
#endif

#include <avr/io.h>
#include <Arduino.h>
#include <util/twi.h>


// You can set I2C_CPUFREQ independently of F_CPU if you 
// change the CPU frequency on the fly. If you do not define it,
// it will use the value of F_CPU
#ifndef I2C_CPUFREQ
#define I2C_CPUFREQ F_CPU
#endif


// I2C_MAXWAIT can be set to any value between 0 and 32767. 
// 0 means no time out.
#define I2C_MAXWAIT 500

#define SCL_CLOCK 100000UL


/* Init function. Needs to be called once in the beginning.
 * Returns false if SDA or SCL are low, which probably means 
 * a I2C bus lockup or that the lines are not pulled up.
 */
bool i2c_init(void)
{
  digitalWrite(SDA, 0);
  digitalWrite(SCL, 0);

  TWSR = (1<<TWPS0); // prescaler is 4
  TWBR = ((I2C_CPUFREQ/SCL_CLOCK)-16)/8;

  return (digitalRead(SDA) != 0 && digitalRead(SCL) != 0);
}


/* Start transfer function: <addr> is the 8-bit I2C address (including the R/W bit). 
 * Return: true if the slave replies with an "acknowledge", false otherwise
 */
bool  i2c_start(uint8_t addr)
{
  uint8_t   twst;

  // send START condition
  TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

  // wait until transmission completed
  while(!(TWCR & (1<<TWINT))) {}

  // check value of TWI Status Register. Mask prescaler bits.
  twst = TW_STATUS & 0xF8;
  if ( (twst != TW_START) && (twst != TW_REP_START)) return false;
  
  // send device address
  TWDR = addr;
  TWCR = (1<<TWINT) | (1<<TWEN);
  
  // wail until transmission completed and ACK/NACK has been received
  while(!(TWCR & (1<<TWINT))) { }
  
  // check value of TWI Status Register. Mask prescaler bits.
  twst = TW_STATUS & 0xF8;
  if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return false;
  
  return true;
}


/* Similar to start function, but wait for an ACK! Will timeout if I2C_MAXWAIT > 0.
 */
bool  i2c_start_wait(uint8_t addr)
{
  uint8_t   twst;
  uint16_t  maxwait = I2C_MAXWAIT;
  
  while (true) {
    // send START condition
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    
    // wait until transmission completed
    while(!(TWCR & (1<<TWINT))) {}
    
    // check value of TWI Status Register. Mask prescaler bits.
    twst = TW_STATUS & 0xF8;
    if ( (twst != TW_START) && (twst != TW_REP_START)) continue;
    
    // send device address
    TWDR = addr;
    TWCR = (1<<TWINT) | (1<<TWEN);
    
    // wail until transmission completed
    while(!(TWCR & (1<<TWINT))) {}
    
    // check value of TWI Status Register. Mask prescaler bits.
    twst = TW_STATUS & 0xF8;
    if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) ) {    	    
      // device busy, send stop condition to terminate write operation
      TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
	
      // wait until stop condition is executed and bus released
      while(TWCR & (1<<TWSTO)) {}

      if (maxwait)
        if (--maxwait == 0)
          return false;
	
      continue;
    }
    //if( twst != TW_MT_SLA_ACK) return 1;
    return true;
  }
}


/* Issue a stop condition, freeing the bus.
 */
void i2c_stop(void)
{
  // send stop condition
  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
  
  // wait until stop condition is executed and bus released
  while(TWCR & (1<<TWSTO)) {}
}

/* Write one byte to the slave chip that had been addressed
 * by the previous start call. <value> is the byte to be sent.
 * Return: true if the slave replies with an "acknowledge", false otherwise
 */
bool i2c_write(uint8_t value)
{	
  uint8_t   twst;

  // send data to the previously addressed device
  TWDR = value;
  TWCR = (1<<TWINT) | (1<<TWEN);
  
  // wait until transmission completed
  while(!(TWCR & (1<<TWINT))) {}
  
  // check value of TWI Status Register. Mask prescaler bits
  twst = TW_STATUS & 0xF8;
  if( twst != TW_MT_DATA_ACK) return false;
  return true;
}


/* Read one byte. If <last> is true, we send a NAK after having received 
 * the byte in order to terminate the read sequence. 
 */
uint8_t i2c_read(bool last)
{
  TWCR = (1<<TWINT) | (1<<TWEN) | (last ? 0 : (1<<TWEA));
  while(!(TWCR & (1<<TWINT))) {}
  
  return TWDR;
}

#endif

Main sketch


/*  Copyright 2020 Perttu Haimi

    This file is part of FVduino.

    FVduino 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.

    FVduino 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 FVduino.  If not, see <https://www.gnu.org/licenses/>.

  My Changes

  1. Swapped fast / select buttons, short press encoder = select
  2. Set fast for pots 1-3
  3. Long press encoder for save
  4. Made select button more responsive
  5. Removed fast
  6. NeoPixel for Presets
  7. Turn off NoePixel if bypass fsw on tiny85 is off
  8. Replaced OLED with IPS TFT 1.54" 240x240
  ******1284 TFT IPS Breadboard Version******
*/

#include <Arduino.h>
//#include <Bounce2.h>
#include <EEPROM.h>
#include <ButtonEvents.h>
#include  <avr/power.h>

typedef unsigned char PROGMEM prog_uchar;

#include "HW_I2CMaster.h"
#include "font.h"

const uint16_t MARKED = 0x3000; //0x0020
const uint16_t NONE   = 0xFFFF; // this is used for rectangle inner color when not used

#define BypassFSW A0
#undef min
#define min(a,b) ((a)<(b)?(a):(b))
////////////////////////////////////////////////////////////////////////////////////////////////
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Arduino_ST7789_Fast.h>
#define TFT_DC  A2
#define TFT_RST 1
#define SCR_WD   240
#define SCR_HT   240
Arduino_ST7789 tft = Arduino_ST7789(TFT_DC, TFT_RST);
////////////////////////////////////////////////////////////////////////////////////////////////


// ----------------------------------------NEOPIXEL---------------------------------------------
#include <Adafruit_NeoPixel.h>
#define PIXEL_PIN     23
#define PIXEL_COUNT   1

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);


// Yellow Preset 1
int r0 = 170;
int g0 = 170;
int b0 = 0;

// Green Preset 2
int r1 = 0;
int g1 = 170;
int b1 = 0;

// Red Preset 3
int r2 = 170;
int g2 = 0;
int b2 = 0;

// Grey Preset 4
int r3 = 86;
int g3 = 86;
int b3 = 86;

// Blue Preset 5
int r4 = 0;
int g4 = 0;
int b4 = 170;

// Magenta Preset 6
int r5 = 170;
int g5 = 0;
int b5 = 170;

// Orange Preset 7
int r6 = 154;
int g6 = 54;
int b6 = 0;

// Cyan Preset 8
int r7 = 0;
int g7 = 170;
int b7 = 170;

// ----------------------------------------NEOPIXEL---------------------------------------------


// Pin configuration

// Digital potentiometer uses hardware I2C (TWI), pins A4 and A5
const uint8_t POT_ENABLE_PIN = A3;
//const uint8_t POT_SDA_PIN = A4; (17) ATmega1284 SDA pin is pin 17
//const uint8_t POT_SCL_PIN = A5; (16) ATmega1284 SCL pin is pin 16

// Three PWM outputs
const uint8_t PAR1_PWM_PIN = 13;
const uint8_t PAR2_PWM_PIN = 14;
const uint8_t PAR3_PWM_PIN = 15;

// Two buttons.
const uint8_t PresetFSW = 8; // Preset Footswitch
const uint8_t buttonPin = 0;   // Select/Save Encoder Button, Encoder SW

//ButtonEvents myButton; // create an instance of the ButtonEvents class to attach to our button

// Encoder
const uint8_t ENC1_PIN = 10;
const uint8_t ENC2_PIN = A1;

// EEPROM emulation and FV-1 program switching
const uint8_t PC_NOTIFY_PIN = 4;
const uint8_t I2C_EEPROM_EMUL_SDA_PIN = 18;
const uint8_t I2C_EEPROM_EMUL_SCL_PIN = 19;
const uint8_t EEPROM_EMUL_ADDR = 0x50;

// OLED display commununication
// For reference here, oled code uses port and bit banging
//const uint8_t OLED_DATA_PIN = 13;
//const uint8_t OLED_CS_PIN   = 12;
//const uint8_t OLED_CLK_PIN  = 11;

// Digipot address
const uint8_t DS1881_BASE_I2C_ADDR = 0x28;
const uint8_t DS1881_write_address = DS1881_BASE_I2C_ADDR << 1;
const uint8_t DS1881_read_address = (DS1881_BASE_I2C_ADDR << 1) | _BV(0);


/*********** FV-1 algorithm data structures ***********/

// The eeprom data is in 16 * 32 byte banks (total 512 bytes)
// They are compressed by LZ algorithm (compress.py) to approx.
// half the size. Include the algorithm data blocks here.

#include "spinsemi.h"



// Strings for describing the algorithm and parameters
typedef struct {
  char algoname [14];
  char par1name [10];
  char par2name [10];
  char par3name [10];
} Description;

// Sensible default settings for each algorithm
typedef struct {
  uint8_t vol;
  uint8_t mix;
  uint8_t par1;
  uint8_t par2;
  uint8_t par3;
} Default;

// Keep everything together in a single array
typedef struct {
  Description desc;
  Default def;
  uint8_t* const prog_addr;
} AlgoDatum;

const AlgoDatum algodata [] PROGMEM = {

  {{"Hall Reverb",   "Pre-delay", "Time", "Dampen" }, {15, 10, 128, 128, 128}, (uint8_t *)K3_V1_0_Hall},
  {{"Room Reverb",   "Pre-delay", "Time", "Dampen" }, {15, 10, 128, 128, 128}, (uint8_t *)K3_V1_1_Room},
  {{"Plate Reverb",  "Pre-delay", "Time", "Dampen" }, {15, 10, 128, 128, 128}, (uint8_t *)K3_V1_2_PLATE},
  {{"Rep Echo/Rev",  "Delay", "Repeats",   "Reverb"}, {15, 10, 128, 128, 128}, (uint8_t *)K3_V1_4_ECHO_REV},
  {{"Chor Reverb",   "Width", "Sweep", "Reverb"}, {15, 20, 128, 128, 128}, (uint8_t *)K3_V1_6_CHOR_REV},
  {{"FlangerVerb",   "Reverb", "Rate",  "Depth"}, {15, 20, 128, 128, 128}, (uint8_t *)GA_DEMO_FLANGE},
  {{"Phaser Verb",    "Reverb", "Rate",  "Width"}, {15, 20, 128, 128, 128}, (uint8_t *)GA_DEMO_PHASE},
  {{"Vibrato Verb",   "Reverb", "Speed", "Depth"}, {15, 20, 128, 128, 128}, (uint8_t *)GA_DEMO_VIBRATO},
  {{"Filter Verb",   "Reverb", "Sens", "Depth"},  {15, 20, 128, 128, 128}, (uint8_t *)GA_DEMO_WAH},
  {{"Tremolo+Rev",   "Reverb", "Rate",  "Tremolo" }, {15, 10, 128, 128, 128}, (uint8_t *)rom_trem_rev},
 
  {{"Spring+Trem",   "Reverb", "Rate", "Depth"},  {15, 10, 128, 128, 128}, (uint8_t *)spring_verb},
  {{"Reverse Dly",   "Bit", "Feedback", "Delay"}, {15, 10, 128, 128, 128}, (uint8_t *)afx},
  {{"Abbey Verb",    "Reverb", "Feedback", "Damp"}, {15, 20, 128, 128, 128}, (uint8_t *)abbeyverb},
  {{"Choirsaw",      "Delay", "Width", "Tremolo"},  {15, 10, 128, 128, 128}, (uint8_t *)choirsaw},
  {{"Binson",        "Mix", "Prog", "Feedback"}, {15, 10, 128, 128, 128}, (uint8_t *)bluenebula},
  {{"Shimmer",       "Dwell", "Pitch", "Mix"},   {15, 10, 128, 128, 128}, (uint8_t *)glimmer},
  {{"Flanger",       "Speed", "Depth", "Feedback"}, {15, 10, 128, 128, 128}, (uint8_t *)flanger},
  {{"Dual Pitch",     "Pitch1", "Mix", "Pitch2"},      {15, 10, 128, 128, 128}, (uint8_t *)dualpitch},
  {{"Daydream",       "Time", "Feedback", "Filter"},   {15, 10, 128, 128, 128}, (uint8_t *)daydream},
  {{"Glitch Dly",     "Speed", "Time", "Random"},      {15, 10, 128, 128, 128}, (uint8_t *)greenwood},
 
  {{"Bit Crusher",    "Crush", "Filter", "Detune"},    {15, 10, 128, 128, 128}, (uint8_t *)crusher},
  {{"Chorus Dual",    "Rate1", "Rate2", "Depth"},      {15, 10, 128, 128, 128}, (uint8_t *)chorusdualrate},
  {{"Space Delay",      "Time", "Filter", "Feedback"},   {15, 10, 128, 128, 128}, (uint8_t *)spacedelay},
  {{"Sample&Hold",            "Time", "Feedback", "Mod"},      {15, 10, 128, 128, 128}, (uint8_t *)sh},
  {{"Ring Pitch",     "Rate", "Blend", "Pitch"},       {15, 10, 128, 128, 128}, (uint8_t *)ringpitchulator},
  {{"ReverseVerb",   "Pre-delay", "Decay", "Damp"},     {15, 10, 128, 128, 128}, (uint8_t *)RevRev},
  {{"Dual Gl3",       "Speed", "Reson", "Feedback"},   {15, 10, 128, 128, 128}, (uint8_t *)dualglitch3},
  {{"Starfield",      "Time", "Feedback", "Phaser"},   {15, 10, 128, 128, 128}, (uint8_t *)starfield2},
  {{"Filter Trem",    "Speed", "Reson", "Gain"},       {15, 10, 128, 128, 128}, (uint8_t *)bass6},
  {{"Trem Dly",       "Pitch", "Speed", "Regen"},      {15, 10, 128, 128, 128}, (uint8_t *)bass7},

  {{"Dr.Bohm",        "Reverb", "Feedback", "Speed"},  {17, 20, 128, 128, 128}, (uint8_t *)Cathedral},
  {{"Rotor",          "Reverb", "Depth", "Speed"},     {17, 20, 128, 128, 128}, (uint8_t *)Rotor},
  {{"Solina",         "Reverb", "Blend", "Treble"},    {17, 20, 128, 128, 128}, (uint8_t *)Ensemble},
  {{"Fading",         "D-mix", "Depth", "Reson"},      {17, 20, 128, 128, 128}, (uint8_t *)Fading},
  {{"PolySixChor",    "Reverb", "Blend", "Treble"},    {17, 20, 128, 128, 128}, (uint8_t *)PolySixChor},
  {{"Rototrem",       "Reverb", "Warp", "Speed"},      {17, 20, 128, 128, 128}, (uint8_t *)Tremolo},
  {{"Leslie",         "Reverb", "Filter", "Speed"},    {17, 20, 128, 128, 128}, (uint8_t *)Leslie},
  {{"EQ/Width",       "Bass", "Treble", "Width"},      {17, 20, 128, 128, 128}, (uint8_t *)EQstereoWidth},
  {{"Para EQ",        "Freq", "Q-Band", "Q-Peak"},     {15, 10, 128, 128, 128}, (uint8_t *)para_eq},
  {{"Parallax",       "Time", "Feedback", "Trem"},     {15, 10, 128, 128, 128}, (uint8_t *)parallax},
};

// The space for printing algo number on screen is two characters
// In practice, about 80 algorithms is the max that fits on atmega328 32k memory
const uint8_t NALGO = min(99, sizeof(algodata) / sizeof(AlgoDatum));
// Algorithm will be copied to RAM before sending because PROGMEM is too slow
uint8_t algo_buffer[512];

// The strings of the currently visible algorithm are copied to ram
Description current_algo_strings;

/************** Patch data structures *****************/

typedef struct {
  uint8_t algorithm; // index
  uint8_t vol;
  uint8_t mix;
  uint8_t par1;
  uint8_t par2;
  uint8_t par3;
} Patch;

// 5 RGB 565 colours for each patch, from dark to light
const uint16_t patch_colors [][5] = {
  {0x5940, 0xD1A0, 0xFC20, 0xFD80, 0xFE85},   // Amber
  {0x0220, 0x0C80, 0x3640, 0x4F29, 0xA7D4},   // Green
  {0x7820, 0xE060, 0xFA8A, 0xFBCF, 0xFDD7},   // Red
  {0x31E8, 0x4ACC, 0x638F, 0xA577, 0xC639},   // Gray
  {0x00C9, 0x0230, 0x0457, 0x965B, 0xDF5E},   // Blue
  {0x3807, 0x8811, 0xF81F, 0xFC5F, 0xFEDF},   // Mag
  {0x8285, 0x9307, 0xBBE9, 0xD52D, 0xFFFF},   // Brown
  {0x1112, 0x73FD, 0xBD5F, 0x36BC, 0xAFDF},   // Cyan
};

const uint8_t NPATCH = sizeof(patch_colors) / sizeof(patch_colors[0]);

Patch patch_data[NPATCH]; // Keep all patch data in memory, store and restore in EEPROM

const uint16_t P_IN_USE_EE_ADDR = 0;
const uint16_t PATCH_EE_ADDR = 1;
const uint16_t ALGO_EE_ADDR = 512;

uint8_t changed[NPATCH];        // to keep track of patch edit

// State machine for user interface
enum EditState {None, Select, Change};

EditState es = None;
uint8_t selection = 0;            // default start from line 5
uint8_t patches_in_use = 2;
uint8_t current_patch = 0;
uint16_t bg_col = BLACK;          // bg_col will be different if patch is edited but not saved


/************** Digipot code ****************/


/* Calculate actual pot positions from vol and mix values

   vol goes from 0 to 20
   17 is unity gain (corresponding to pot volume 60)

   mix goes from 0 to 20
   10 is 1:1 mix max wet - max dry
   below 10 is less wet - max dry
   above 10 is max wet  - less dry
*/
uint8_t dry_from(uint8_t vol, uint8_t mix)
{
  if (mix > 20)
    mix = 20;

  if (vol > 20)
    vol = 20;

  if (vol == 0 || mix == 20)
    return 0;  // dry is muted

  uint8_t nominal_vol = 43 + vol; // Max 63

  if (mix <= 10)
    return nominal_vol; // dry is maxed

  uint8_t vol_adjustment = mix - 10;
  if (vol_adjustment > nominal_vol)
    return 0;           // dry is muted

  return nominal_vol - vol_adjustment;
}

uint8_t wet_from(uint8_t vol, uint8_t mix)
{

  if (mix > 20)
    mix = 20;

  if (vol > 20)
    vol = 20;

  if (vol == 0 || mix == 0)
    return 0;  // wet is muted

  uint8_t nominal_vol = 43 + vol; // Max 63

  if (mix >= 10)
    return nominal_vol; // wet is maxed

  uint8_t vol_adjustment = 10 - mix;
  if (vol_adjustment > nominal_vol)
    return 0;           // wet is muted

  return nominal_vol - vol_adjustment;
}


/* Run only once during factory default setup.

*/
bool pot_init()
{
  digitalWrite(POT_ENABLE_PIN, LOW); // enable pot communication

  if (!i2c_start(DS1881_write_address))
    return false; // no reply from device

  i2c_write(0b10000010);       // Nonvolatile writes: Zero crossing, 63 values + mute
  i2c_stop();
  //delay(20); // wait for EEPROM write to finish
  delay(10); // half delay when clocking nano to 8 MHz

  i2c_start(DS1881_write_address);
  i2c_write(0b10000110);       // Go back to volatile writes
  i2c_stop();
  //delay(20); // wait for EEPROM write to finish
  delay(10); // half delay when clocking nano to 8 MHz

  digitalWrite(POT_ENABLE_PIN, HIGH);

  return true;
}

/* Set the digipot to given value.
   Min volume 0: -80db attenuation,
   Max volume 63:  0db attenuation
*/
bool pot_set(uint8_t pot, uint8_t val)
{
  val &= 0b00111111; // only the low 6 bits matter

  val = 63 - val;    // invert the value.
  // pot acts as attenuator: 0 - no attenuation (max volume)
  // we want larger number to mean louder

  if (pot)
    val |= 0b01000000; // set the pot bit;

  digitalWrite(POT_ENABLE_PIN, LOW); // enable pot communication

  if (!i2c_start(DS1881_write_address))
    return false;  // no reply from device

  bool res = i2c_write(val);
  i2c_stop();

  digitalWrite(POT_ENABLE_PIN, HIGH);

  return res;
}


/*************** User Interface code **********************/
using Bounce2::Button;

Button footswitch = Button();

ButtonEvents myButton; // create an instance of the ButtonEvents class to attach to our button

void draw_selection(const uint16_t* colors, uint8_t pos, bool emph)
{
  uint8_t y = pos * 35;
  uint16_t col = emph ? colors[4] : colors[2];

  draw_rect(0 , y, SCR_WD , 30, GREEN, NONE, false); // Selection box, was col
}


void clear_selection(uint8_t pos)
{
  uint8_t y = pos * 35;

  draw_rect(0 , y, SCR_WD , 30, bg_col, NONE, false);
}


void draw_patch ()
{
  tft.fillRect(1, 1, SCR_WD, 27, bg_col);
  //  tft.fillRect(1, 210, SCR_WD, 25, bg_col); // clear algorithm name area with background color
  char buff[3];              // 3 chars + \0
  buff[0] =  ' ';            // put spaces in tens and hundreds position

  byte algo = patch_data[current_patch].algorithm + 1;
  btoa(algo, buff + 3); // give pointer to just after buffer (end)

  // Print algo number

  //tft.drawFastHLine(3, 27, 237, WHITE);

  tft.setCursor(214, 2);
  //  tft.setCursor(200, 6 * 35 + 1);
  tft.setTextColor(WHITE);
  tft.setTextSize(2);
  tft.print(buff); // Algo number

  // Print algo name

  tft.setCursor(2, 2);
  //  tft.setCursor(2, 6 * 35 + 1);
  tft.setTextColor(WHITE);
  tft.setTextSize(3);
  tft.print(current_algo_strings.algoname); // Algo name

  const uint16_t * palette = patch_colors[current_patch];

  clear_selection(1);
  draw_volume(palette, bg_col, 1, patch_data[current_patch].vol);
  clear_selection(2);
  draw_mix(palette, bg_col, 2, patch_data[current_patch].mix);
  clear_selection(3);
  draw_parameter(palette, bg_col, current_algo_strings.par1name, 3, patch_data[current_patch].par1);
  clear_selection(4);
  draw_parameter(palette, bg_col, current_algo_strings.par2name, 4, patch_data[current_patch].par2);
  clear_selection(5);
  draw_parameter(palette, bg_col, current_algo_strings.par3name, 5, patch_data[current_patch].par3);
}

void draw_panel()
{
  uint8_t boxlen = SCR_WD / NPATCH; // Preset boxes

  //tft.drawRect(1, 6 * 35 + 1, 238, 25, bg_col);
  tft.fillRect(1, 6 * 35 + 1, 238, 25, bg_col);
  //  tft.drawRect(1, 1, 238, 25, bg_col);
  //  tft.fillRect(1, 1, 238, 25, bg_col);

  for (uint8_t i = 0; i < patches_in_use; ++i) {
    if (i == current_patch) {
      //tft.drawRect(boxlen * i , 6 * 35 + 1, boxlen - 2, 25, patch_colors[i][2]);
      tft.fillRect(boxlen * i + 1, 6 * 35 + 1, boxlen - 3, 25, patch_colors[i][3]);
      //      tft.drawRect(boxlen * i , 1, boxlen - 2, 25, patch_colors[i][2]);
      //      tft.fillRect(boxlen * i , 1, boxlen - 2, 25, patch_colors[i][3]);
    } else {
      //tft.drawRect(boxlen * i , 6 * 35 + 1, boxlen - 2, 25, bg_col);
      tft.fillRect(boxlen * i + 1, 6 * 35 + 10, boxlen - 3, 15, patch_colors[i][3]);
      //      tft.drawRect(boxlen * i , 1, boxlen - 2, 25, bg_col);
      //      tft.fillRect(boxlen * i , 1, boxlen - 2, 25, patch_colors[i][0]);
    }
  }
}


void change_selection(const uint16_t * palette, int8_t dir)
{
  if (dir < -1) dir = -1;
  if (dir > 1) dir = 1;

  uint8_t oldsel = selection;
  selection += dir + 7;
  selection %= 7;
  clear_selection(oldsel);
  draw_selection(palette, selection, false);
}

void set_patch()
{
  // Turn digipots
  uint8_t dry = dry_from(patch_data[current_patch].vol, patch_data[current_patch].mix);
  uint8_t wet = wet_from(patch_data[current_patch].vol, patch_data[current_patch].mix);

  pot_set(0, dry);
  pot_set(1, wet);

  // Set analog signal to FV-1
  analogWrite(PAR1_PWM_PIN, patch_data[current_patch].par1);
  analogWrite(PAR2_PWM_PIN, patch_data[current_patch].par2);
  analogWrite(PAR3_PWM_PIN, patch_data[current_patch].par3);
}

void change_patch(int8_t dir)
{
  current_patch += dir + patches_in_use;
  current_patch %= patches_in_use;

  bg_col = changed[current_patch] ? MARKED : BLACK;

  // Save active patch to EEPROM?
  // 100000 writes promised -> 1000 days 100 patch changes per day
  // Maybe not worth it...

  send_algo();
  set_patch();

  // copy current patch strings for ui
  uint8_t algo = patch_data[current_patch].algorithm;
  memcpy_P(&current_algo_strings, &(algodata[algo].desc), sizeof current_algo_strings);

  // print changed gui
  draw_panel();
  draw_patch();

}

// Valid values for dir are -1 and 1
void edit_algo(int8_t dir)
{

  patch_data[current_patch].algorithm += dir + NALGO;
  patch_data[current_patch].algorithm %= NALGO;

  uint8_t algo = patch_data[current_patch].algorithm;

  // Copy current patch strings for ui
  memcpy_P(&current_algo_strings, &(algodata[algo].desc), sizeof current_algo_strings);

  // Set params to default values. Copy 5 bytes from EEPROM
  Default tmp;
  EEPROM.get(ALGO_EE_ADDR + algo * sizeof(Default),  tmp);

  patch_data[current_patch].vol  = tmp.vol;
  patch_data[current_patch].mix  = tmp.mix;
  patch_data[current_patch].par1 = tmp.par1;
  patch_data[current_patch].par2 = tmp.par2;
  patch_data[current_patch].par3 = tmp.par3;

  changed[current_patch] = true;

  send_algo();
  set_patch();

  // print updated elements
  draw_patch();

  const uint16_t * palette = patch_colors[current_patch];
  draw_selection(palette, selection, true);
}


void edit_vol(int8_t dir, const uint8_t pos)
{
  uint8_t vol = patch_data[current_patch].vol;

  if (vol == 0 && dir < 0)
    return; // At minimum
  if (vol == 20 && dir > 0)
    return; // Maxed out

  vol += dir;

  // Change the patch
  patch_data[current_patch].vol = vol;
  changed[current_patch] = true;

  // Turn the digipots.
  uint8_t dry = dry_from(vol, patch_data[current_patch].mix);
  uint8_t wet = wet_from(vol, patch_data[current_patch].mix);
  pot_set(0, dry);
  pot_set(1, wet);

  // Draw the change
  const uint16_t * palette = patch_colors[current_patch];
  draw_volume(palette, bg_col, pos, vol);
}

void edit_mix(int8_t dir, const uint8_t pos)
{
  uint8_t mix = patch_data[current_patch].mix;

  if (mix ==  0 && dir < 0)
    return;  // At minimum
  if (mix == 20 && dir > 0)
    return;  // At maximum

  mix += dir;

  // Change the patch
  patch_data[current_patch].mix = mix;
  changed[current_patch] = true;

  // Turn the digipots.
  uint8_t dry = dry_from(patch_data[current_patch].vol, mix);
  uint8_t wet = wet_from(patch_data[current_patch].vol, mix);
  pot_set(0, dry);
  pot_set(1, wet);

  // Draw the change
  const uint16_t * palette = patch_colors[current_patch];
  draw_mix(palette, bg_col, pos, mix);
}

// Valid values for dir are -1 and 1
//void edit_par(int8_t dir, bool fast, uint8_t pin, uint8_t &val, const char *parname, const uint8_t pos)
void edit_par(int8_t dir, uint8_t pin, uint8_t &val, const char *parname, const uint8_t pos)
{
  // if (fast)
  dir *= 10;

  if (dir < 0 && val < -dir)
    val = 0;
  else if (dir > 0 && (255 - val) < dir)
    val = 255;
  else
    val += dir;

  const uint16_t * palette = patch_colors[current_patch];

  changed[current_patch] = true;

  analogWrite(pin, val);
  draw_parameter(palette, bg_col, parname, pos, val);
}

void edit_menubar(int8_t dir)
{
  if (dir < -1) dir = -1;
  if (dir > 1) dir = 1;

  // patches_in_use must be in [2, NPATCH]
  if (patches_in_use <= 2 && dir < 0)
    return;
  if (patches_in_use >= NPATCH && dir > 0)
    return;

  const uint16_t * palette = patch_colors[current_patch];

  patches_in_use += dir;

  if (current_patch >= patches_in_use) {
    change_patch(-1);  // move to previous patch since current is not in use
    draw_selection(palette, selection, true);
  } else {
    draw_panel();
    draw_selection(palette, selection, true);
  }

  // write number of patches in use to eeprom
  EEPROM.put(P_IN_USE_EE_ADDR, patches_in_use);
}

//void edit_patch(uint8_t sel, int8_t dir, bool fast)
void edit_patch(uint8_t sel, int8_t dir)
{
  switch (sel) {
    case 0 : edit_algo(-dir);     break;  // Changed dir
    case 1 : edit_vol(-dir, sel); break;
    case 2 : edit_mix(-dir, sel); break;
    case 3 : edit_par(-dir, PAR1_PWM_PIN, patch_data[current_patch].par1, current_algo_strings.par1name, sel); break;
    case 4 : edit_par(-dir, PAR2_PWM_PIN, patch_data[current_patch].par2, current_algo_strings.par2name, sel); break;
    case 5 : edit_par(-dir, PAR3_PWM_PIN, patch_data[current_patch].par3, current_algo_strings.par3name, sel); break;
    case 6 : edit_menubar(-dir); break;
  }
}

void save_current_patch()
{
  uint16_t eeAddress = PATCH_EE_ADDR + current_patch * sizeof(Patch);
  Patch curr = patch_data[current_patch];

  EEPROM.put(eeAddress, curr);

  // Save to algo defaults also so that next time they can be used

  eeAddress = ALGO_EE_ADDR + curr.algorithm * sizeof(Default);
  Default tmp = {curr.vol, curr.mix, curr.par1, curr.par2, curr.par3};

  EEPROM.put(eeAddress, tmp);

  changed[current_patch] = false;
  bg_col = BLACK;
  draw_panel();
  draw_patch();             // Redraw the whole screen
}



/********** 24LC32A EEPROM emulation */

/* Compression algorithm based on
   http://excamera.com/sphinx/article-compression.html

   With small modifications.
*/
class Flashbits {
  public:

    void begin(prog_uchar *s)
    {
      src = s;
      mask = curr_byte = 0x00;
    }

    uint8_t get1(void)
    {
      if (!mask) {
        mask = 0x80;
        curr_byte = pgm_read_byte_near(src++);
      }

      uint8_t r = (curr_byte & mask) != 0;
      mask >>= 1;

      return r;
    }

    uint16_t getn(uint8_t n)
    {
      uint16_t r = 0;
      while (n--) {
        r <<= 1;
        r |= get1();
      }
      return r;
    }

  private:
    prog_uchar *src;
    uint8_t mask;
    uint8_t curr_byte;
};

Flashbits bits;

void decompress(uint8_t *dst, prog_uchar *src)
{
  bits.begin(src);
  uint8_t O = bits.getn(4);
  uint8_t L = bits.getn(4);
  uint8_t M = bits.getn(2);

  uint8_t *end = dst + bits.getn(16);

  while (dst != end) {
    if (bits.get1() == 0) {
      *dst++ = bits.getn(8);
    } else {
      int offset = -bits.getn(O) - 1;
      int length = bits.getn(L) + M;
      while (length--) {
        *dst = *(dst + offset);
        dst++;
      }
    }
  }
}

void send_algo()
{
  // Copy FV-1 algorithm from PROGMEM to ram buffer.
  // Progmem is too slow in the send loop.
  // Since we will anyway have to copy from PROGMEM,
  // it makes sense to compress the algorithms and get
  // space savings (almost 2x).

  uint8_t algo = patch_data[current_patch].algorithm;
  decompress(algo_buffer, (prog_uchar *)pgm_read_word(&(algodata[algo].prog_addr)));

  // Set up everything to be ready
  const uint8_t sda_mask = (1 << PIND5);
  const uint8_t clk_mask = (1 << PIND6);
  uint8_t prev_clk = clk_mask;

  DDRD &= ~(clk_mask);   // clk pin as input
  DDRD &= ~(sda_mask);   // sda pin as input
  PORTD &= ~(sda_mask);  // SDA pin is pulled low or floated up
  // -> we need to set pin low only once.
  //    Toggling is done by setting pin to
  //    input (let float high) or output (pull low).
  //    FV-1 internal pullups are ok (tested).

  uint16_t pos = 0;
  uint8_t curr_byte = algo_buffer[pos];
  uint8_t bit_mask = 0b10000000;
  uint8_t clk_count = 0;

  // Undivided attention for FV-1 requests
  noInterrupts();

  // Notify FV-1 of patch change by toggling the notify pin
  PIND = _BV(4);   // Toggle pin 4

  while (clk_count < 37)             // Handle the header
  {
    uint8_t clk = PIND & clk_mask;

    if (!clk && prev_clk) {          // scl went down

      switch (clk_count)
      {
        case 8:
        case 17:
        case 26:
        case 36:
          DDRD  |= sda_mask;         // send ACK - pull sda pin low
          break;
        default:
          DDRD &= ~(sda_mask);       // Release
          break;
      }
      clk_count++;
    }
    prev_clk = clk;
  }

  clk_count = 0;
  while (pos < 512)                  // Send the data
  {
    uint8_t clk = PIND & clk_mask;

    if (!clk && prev_clk) {          // scl went down

      if (clk_count != 8) {          // Sending byte

        if (curr_byte & bit_mask) {
          DDRD &= ~(sda_mask);       // Send 1 = Let High
        } else {
          DDRD  |= sda_mask;         // Send 0 = Pull Low
        }
        bit_mask >>= 1;
        clk_count++;

      } else {                       // Let reciever ACK

        DDRD &= ~(sda_mask);         // Release
        clk_count = 0;
        bit_mask = 0b10000000;
        pos++;
        curr_byte = algo_buffer[pos];
      }
    }
    prev_clk = clk;
  }

  interrupts();

}


void setup()
{

  // ----------------------------------------NEOPIXEL---------------------------------------------
  pixels.begin();
  pixels.setPixelColor(0, 255, 255, 0);
  pixels.show();
  // ----------------------------------------NEOPIXEL---------------------------------------------

  // set up pins

  // Use high frequency PWM
  TCCR1A = (TCCR1A & 0b11111100) | 0b00000001;    // set timer 1 to 8 bit mode
  TCCR1B = (TCCR1B & 0b11100000) | 0b00001001;    // set timer 1 to fast PWM, divisor to 1 for PWM frequency of 31372.55 Hz

  TCCR2A = (TCCR2A & 0b11111100) | 0b00000011;    // set timer 2 to fast PWM
  TCCR2B = (TCCR2B & 0b11111000) | 0b00000001;    // set timer 2 divisor to 1 for PWM frequency of 31372.55 Hz

  // PWM outputs
  pinMode(PAR1_PWM_PIN, OUTPUT);
  pinMode(PAR2_PWM_PIN, OUTPUT);
  pinMode(PAR3_PWM_PIN, OUTPUT);

  // 24LC32 EEPROM emulation
  pinMode(PC_NOTIFY_PIN, OUTPUT);
  pinMode(I2C_EEPROM_EMUL_SDA_PIN, INPUT);
  pinMode(I2C_EEPROM_EMUL_SCL_PIN, INPUT);



  // Buttons and encoder

  pinMode(buttonPin, INPUT_PULLUP);
  myButton.attach(buttonPin);
  myButton.activeHigh();
  myButton.debounceTime(15); //apply 5ms debounce
  myButton.holdTime(750); // require button to be held for 1000ms before triggering a hold event
  footswitch.attach(PresetFSW, INPUT);
  footswitch.interval(5);

  pinMode(ENC1_PIN, INPUT_PULLUP);
  pinMode(ENC2_PIN, INPUT_PULLUP);

  pinMode(BypassFSW, INPUT_PULLUP);

  // SoftI2C is used for digipot control
  pinMode(POT_ENABLE_PIN, OUTPUT);
  i2c_init(); // Uses hardware I2C (pins A4 and A5)


  // Write factory defaults to EEPROM if requested
  // Footswitch pressed at boot for 1 sec

  unsigned long startTime = millis();
  unsigned long heldTime = 0;

  while (digitalRead(PresetFSW) == HIGH)

  {
    heldTime = millis() - startTime;
    if (heldTime > 1000)
      break;
  }

  if (heldTime > 1000) {

    // Digipot initial settings, saved in its EEPROM.
    // Depends on i2c_init(). Hangs setup if no pot present..........Hangs setup if no pot present..........Hangs setup if no pot present..........
    pot_init();

    // Write algorithm default settings
    Default tmp_d;
    for (uint8_t i = 0; i < NALGO; ++i) {
      memcpy_P(&tmp_d, &(algodata[i].def), sizeof(Default));
      EEPROM.put(ALGO_EE_ADDR + i * sizeof(Default), tmp_d);
      delay(10);
    }

    // Write empty patches using the first algorithm and default settings
    memcpy_P(&tmp_d, &(algodata[0].def), sizeof(Default));
    Patch tmp_p = {0, tmp_d.vol, tmp_d.mix, tmp_d.par1, tmp_d.par2, tmp_d.par3};

    for (uint8_t i = 0; i < NPATCH; ++i) {
      EEPROM.put(PATCH_EE_ADDR + i * sizeof(Patch), tmp_p);
      delay(10);
    }

    // Set 8 patches as default
    EEPROM.put(P_IN_USE_EE_ADDR, (uint8_t)8);

    rainbow(2);
    pixels.show();

  }

  // load patch settings from EEPROM
  uint16_t eeAdress = PATCH_EE_ADDR;
  for (uint8_t i = 0; i < NPATCH; ++i) {
    EEPROM.get(eeAdress, patch_data[i]);
    if (patch_data[i].algorithm >= NALGO) {
      patch_data[i].algorithm = 0;   // something wrong with algo index, set to zero
      changed[i] = true;             // user will have to edit and save
    }
    if (patch_data[i].vol > 20)
      patch_data[i].vol = 20;
    if (patch_data[i].mix > 100)
      patch_data[i].mix = 100;
    eeAdress += sizeof(Patch);
  }

  current_patch = 0;

  // get patches_in_use from EEPROM
  EEPROM.get(P_IN_USE_EE_ADDR, patches_in_use);
  if (patches_in_use < 2)
    patches_in_use = 2;
  if (patches_in_use >= NPATCH)
    patches_in_use = NPATCH;

  // copy current patch strings for ui
  uint8_t algo = patch_data[current_patch].algorithm;
  memcpy_P(&current_algo_strings, &(algodata[algo].desc), sizeof current_algo_strings);

  // send current patch algorithm to FV-1
  send_algo();
  set_patch();

  // TFT Display setup
  delay(200);
  tft.init();
  tft.setRotation(1);
  //tft.setRotation(0);  // Pins at bottom
  tft.fillScreen(BLACK); // Black
  delay(200);

  // print initial gui
  draw_panel();
  draw_patch();

}


/* Rotary encoder handling code from:
   https://www.best-microcontroller-projects.com/rotary-encoder.html
*/
uint8_t prevNextCode = 0;
uint16_t store = 0;

// A valid CW or CCW move returns 1 or -1, invalid returns 0.
int8_t read_rotary() {
  const int8_t rot_enc_table[] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0};

  prevNextCode <<= 2;
  if (digitalRead(ENC1_PIN)) prevNextCode |= 0x02;
  if (digitalRead(ENC2_PIN)) prevNextCode |= 0x01;
  prevNextCode &= 0x0f;

  // If valid then store as 16 bit data.
  if  (rot_enc_table[prevNextCode] ) {
    store <<= 4;
    store |= prevNextCode;
    if ((store & 0xff) == 0x2b) return -1;
    if ((store & 0xff) == 0x17) return 1;
  }
  return 0;

}


void loop()
{
  if (digitalRead(BypassFSW) == HIGH)
  {
    if (current_patch == 0) {
      pixels.setPixelColor(0, r0, g0, b0); // Yellow
      pixels.show();
    }
    if (current_patch == 1) {
      pixels.setPixelColor(0, r1, g1, b1); // Green
      pixels.show();
    }
    if (current_patch == 2) {
      pixels.setPixelColor(0, r2, g2, b2);  // Red
      pixels.show();
    }
    if (current_patch == 3) {
      pixels.setPixelColor(0, r3, g3, b3); // Grey
      pixels.show();
    }
    if (current_patch == 4) {
      pixels.setPixelColor(0, r4, g4, b4); // Blue
      pixels.show();
    }
    if (current_patch == 5) {
      pixels.setPixelColor(0, r5, g5, b5); // Magenta
      pixels.show();
    }
    if (current_patch == 6) {
      pixels.setPixelColor(0, r6, g6, b6); // Orange
      pixels.show();
    }
    if (current_patch == 7) {
      pixels.setPixelColor(0, r7, g7, b7); // Cyan
      pixels.show();
    }
  }
  if (digitalRead(BypassFSW) == LOW)
  {
    pixels.setPixelColor(0, 0, 0, 0); // Off
    pixels.show();

  }
  const uint16_t * palette = patch_colors[current_patch];
  if (myButton.rose() == true) {
    if (es == None) {
      es = Select;
      draw_selection(palette, selection, false);
    } else if (es == Select) {
      es = Change;
      // emphasize bar that is being edited
      draw_selection(palette, selection, true);
    } else if (es == Change) {
      es = None;
      if (changed[current_patch]) {
        bg_col = MARKED;
        draw_panel();
        draw_patch();             // Redraw the whole screen
      }
      clear_selection(selection);
    }
  }



  int8_t dir = read_rotary();

  if (myButton.update() == true) {
    switch (myButton.event()) {

      // things to do if the button was held (Hold = Save)
      case (hold) : {
          if (changed[current_patch]) {
            save_current_patch();
            es = None;                               // Go to default mode
            clear_selection(selection);

            rainbow(1);
            pixels.show();
          }
          break;
        }
    }
  }

  footswitch.update();

  // Encoder turned
  if (dir) {
    if (es == None) { // first movement activates Select mode
      es = Select;
      draw_selection(palette, selection, false);
    } else if (es == Select) {
      change_selection(palette, dir);  // Move selection
    } else if (es == Change) {
      //  bool fast = (fast_button.read() == HIGH);
      edit_patch(selection, -dir);       // Change parameter
    }
  }

  // Footswitch pressed
  if (footswitch.pressed()) {
    if (es == Select) {
      clear_selection(selection);
      es = None;

    }
    if (es != Change) {  // Patch change disabled during editing
      change_patch(1);

    }
  }
}

void rainbow(int wait) {
  for (long firstPixelHue = 0; firstPixelHue < 1 * 65536; firstPixelHue += 256) {
    for (int i = 0; i < pixels.numPixels(); i++) {
      int pixelHue = firstPixelHue + (i * 65536L / pixels.numPixels());
      pixels.setPixelColor(i, pixels.gamma32(pixels.ColorHSV(pixelHue)));
    }
    pixels.show(); // Update strip with new contents
    delay(wait);  // Pause for a moment
    pixels.setPixelColor(0, 0, 0, 0);
    pixels.show(); // Update strip with new contents
  }
}

// - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / - / -



// Draw a rectangle in foreground colour optionally filled another colour
void draw_rect (uint8_t x, uint8_t y, uint8_t w, uint8_t h,
                uint16_t edgecol, uint16_t fillcol, boolean filled)
{
  if (w == 0 || h == 0)
    return;

  uint8_t e_red   = (edgecol & 0xf800) >> 10;
  uint8_t e_green = (edgecol & 0x07e0) >> 5;
  uint8_t e_blue  = (edgecol & 0x001f) << 1;

  uint8_t f_red   = (fillcol & 0xf800) >> 10;
  uint8_t f_green = (fillcol & 0x07e0) >> 5;
  uint8_t f_blue  = (fillcol & 0x001f) << 1;

  tft.drawRect(x, y, w, h, edgecol);

  if (filled)                             // filled rectangles take time to draw
    tft.fillRect(x, y, w, h, edgecol);
}

// Graphics **********************************************

// Clear display
void clear_display()
{
  tft.clearScreen();
  //  PINB = 1 << cs;                         // cs low
  //  Send(0x25);                             // Clear Window
  //  Send(0); Send(0); Send(95); Send(63);
  //  PINB = 1 << cs;                         // cs high
  //  delayMicroseconds(900);
  //delayMicroseconds(450);                 // half delay when clocking nano to 8 MHz
}

// Draw line to (x,y) in given colour
void draw_line (uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint16_t col)
{
  uint8_t red   = (col & 0xf800) >> 10;
  uint8_t green = (col & 0x07e0) >> 5;
  uint8_t blue  = (col & 0x001f) << 1;

  tft.drawLine(x0, y0, x1, y1, col);
  //  PINB = 1 << cs;                         // cs low
  //  Send(0x21);                             // Draw Line
  //  Send(x0); Send(y0); Send(x1); Send(y1);
  //  Send(red); Send(green); Send(blue);
  //  PINB = 1 << cs;                         // cs high
}

// Plot a point at (x,y)
void plot_point (uint8_t x, uint8_t y, uint16_t col)
{
  draw_line(x, y, x, y, col);
}



// Plot character in given colour
void plot_char (uint8_t x, uint8_t y, uint8_t ch, uint16_t col, uint8_t scale)
{
  uint8_t red   = (col & 0xf800) >> 10;
  uint8_t green = (col & 0x07e0) >> 5;
  uint8_t blue  = (col & 0x001f) << 1;

  //  PINB = 1 << cs;                         // cs low
  for (uint8_t c = 0 ; c < 5; c++) {      // Column range
    uint8_t bits = pgm_read_byte(&font[ch - 32][c]);
    uint8_t r = 0;
    while (bits) {
      while ((bits & 1) == 0) {
        r++;
        bits = bits >> 1;
      }
      uint8_t on = (7 - r) * scale;
      while ((bits & 1) != 0) {
        r++;
        bits = bits >> 1;
      }
      uint8_t off = (7 - r) * scale + 1;
      for (int i = 0; i < scale; i++) {
        uint8_t h = x + c * scale + i;
        //        Send(0x21);                         // Draw line
        //        Send(h); Send(y + on); Send(h); Send(y + off);
        //        Send(red); Send(green); Send(blue);
      }
    }
  }
  //  PINB = 1 << cs;                           // cs high
}

// Plot text
void plot_text(uint8_t x, uint8_t y, const char* text, uint16_t col, uint8_t scale)
{
  while (1) {
    char c = *(text++);
    if (c == 0) return;
    plot_char(x, y, c, col, scale);
    x += 6;
  }
}

// Higher level functions for drawing ui elements

// convert unsigned byte to char array
// *s points to end() of buffer
char *btoa(uint8_t x, char *s)
{
  *--s = 0;
  if (!x) *--s = '0';
  for (; x; x /= 10)
    * --s = '0' + x % 10;
  return s;
}


// Master volume: -10 db - +4 db
// Mix: 0 - 50% - 100% (Not all values are possible, map to pot values)
// Valid values for dir are -1 and 1


// Draw volume -15 ------ 0 --- +4db / Mute
// Values given are 0-20.
void draw_volume(const uint16_t* palette, const uint16_t bg, const uint8_t pos, const uint8_t val)
{
  uint8_t start = pos * 35 + 1;
  uint8_t len = map(val, 0, 20, 0, 238);
  uint16_t barcol  = palette[3];
  uint16_t textcol = palette[3];

  tft.fillRect(1 , start + 18, 238, 8, bg);       // Erase old bar
  tft.fillRect(1 , start + 18, len, 8, barcol);   // Draw new bar

  tft.fillRect(178 , start, 34, 14, bg);        // Erase old value

  tft.setCursor(2, start);
  tft.setTextColor(textcol);
  tft.setTextSize(2);
  tft.print("Volume");

  // The code for constructing these on the fly
  // takes as much space, but the array is simpler.
  static const char db[21][4] = {"-18",
                                 "-16", "-15", "-14", "-13",
                                 "-12", "-11", "-10", " -9",
                                 " -8", " -7", " -6", " -5",
                                 " -4", " -3", " -2", " -1",
                                 " +0", " +1", " +2", " +3"
                                };


  tft.setCursor(178, start);
  tft.print(db[val]);

  tft.setCursor(215, start);
  tft.print("db");
}

// Draw mix as Dry ---  50% ---- Wet
// Values given are 0-20.
void draw_mix(const uint16_t* palette, const uint16_t bg, const uint8_t pos, const uint8_t val)
{
  uint8_t start = pos * 35 + 1;
  uint8_t len = map(val, 0, 20, 0, 238);
  uint16_t barcol  = palette[3];
  uint16_t textcol = palette[3];

  tft.fillRect(1 , start + 18, 238, 8, bg);        // Erase old bar
  tft.fillRect(1 , start + 18, len, 8, barcol);   // Draw new bar

  tft.setCursor(2, start);
  tft.setTextColor(textcol);
  tft.setTextSize(2);
  tft.print("Mix");

  char buff[4];                  // 3 chars + \0
  buff[0] = buff[1] = ' ';       // put spaces in tens and hundreds position

  btoa(val * 5, buff + 4); // give pointer to just after buffer (end)


  tft.fillRect(203 , start, 34, 14, bg);        // Erase old value
  tft.setCursor(203, start);
  tft.print(buff);
}


//  Draws bar with name and value
// Parameter values shown as 0-100%
void draw_parameter(const uint16_t* palette, const uint16_t bg, const char* text, const uint8_t pos, const uint8_t val)
{
  uint8_t start = pos * 35 + 1;
  uint8_t len = map(val, 0, 255, 0, 238);
  uint8_t perc = map(val, 0, 255, 0, 100);
  uint16_t barcol  = palette[3];
  uint16_t textcol = palette[3];

  tft.fillRect(1 , start + 18, 238, 8, bg);        // Erase old bar
  tft.fillRect(1 , start + 18, len, 8, barcol);   // Draw new bar
  tft.fillRect(2 , start, 110, 16, bg);        // Erase old part names
  tft.setCursor(2, start);
  tft.setTextColor(textcol);
  tft.setTextSize(2);
  tft.print(text);

  char buff[4];                  // 3 chars + \0 // add percent mark?
  buff[0] = buff[1] = ' ';       // put spaces in tens and hundreds position

  btoa(perc, buff + 4); // give pointer to just after buffer (end)

  // we want right justified, give buff instead of res
  tft.fillRect(203 , start, 34, 14, bg);        // Erase old value
  tft.setCursor(203, start);
  tft.print(buff);
}

Have you tried the Arduino standard Wire library?

Never had problems with the standard Wire library on an ATmega1284P here ...............

Anyone know why the sketch works using a 328p but freezes at startup when using a 1284 ?

If the HW in the filename = Hardware, then why does the comment at the start of the file indicate that it's a software I2C library?

What's wrong with using the hardware I2C and the standard Wire library as @DrDiettrich said in #2.

Maybe that particular I2C library is not compatible with the ATmega1284P ?

Post a query where you downloaded the library from perhaps ?

I didn’t write the sketch, I’m just changing the PIN numbers to use the 1284

Says based on, But uses HW part, I tried converting the sketch to use wire based on the digipot example, didn’t work either

My attempt to convert sketch to use wire, how do I fix the error?

/Users/lee/Desktop/fvduino tft 1284 breadboard/fvduino/fvduino.ino: In function 'bool pot_set(uint8_t, uint8_t)':
fvduino:390:30: error: could not convert 'Wire.TwoWire::beginTransmission(80)' from 'void' to 'bool'
if (!Wire.beginTransmission(DS1881_write_address))
~~^~
fvduino:390:51: error: in argument to unary !
if (!Wire.beginTransmission(DS1881_write_address))
^

/* Run only once during factory default setup.

*/
bool pot_init()
{
  digitalWrite(POT_ENABLE_PIN, LOW); // enable pot communication

  if (!Wire.beginTransmission(DS1881_write_address))
    return false; // no reply from device

  Wire.write(0b10000010);       // Nonvolatile writes: Zero crossing, 63 values + mute
  Wire.endTransmission();
  delay(20); // wait for EEPROM write to finish
  //delay(10); // half delay when clocking nano to 8 MHz

  Wire.beginTransmission(DS1881_write_address);
  Wire.write(0b10000110);       // Go back to volatile writes
  Wire.endTransmission();
  delay(20); // wait for EEPROM write to finish
  //delay(10); // half delay when clocking nano to 8 MHz

  digitalWrite(POT_ENABLE_PIN, HIGH);

  return true;
}

/* Set the digipot to given value.
   Min volume 0: -80db attenuation,
   Max volume 63:  0db attenuation
*/
bool pot_set(uint8_t pot, uint8_t val)
{
  val &= 0b00111111; // only the low 6 bits matter

  val = 63 - val;    // invert the value.
  // pot acts as attenuator: 0 - no attenuation (max volume)
  // we want larger number to mean louder

  if (pot)
    val |= 0b01000000; // set the pot bit;

  digitalWrite(POT_ENABLE_PIN, LOW); // enable pot communication

  if (!Wire.beginTransmission(DS1881_write_address))
    return false;  // no reply from device

  bool res = Wire.write(val);
  Wire.endTransmission();

  digitalWrite(POT_ENABLE_PIN, HIGH);

  return res;
}

Wire.beginTransmission is a void, it does not return a value. As a quick search throught the Wire.cpp code would show.

So;

Wire.beginTransmission(DS1881_write_address);

Next problem: The Wire library uses bare slave addresses, adds the read/write bit automagically. Use DS1881_BASE_I2C_ADDR instead.

Still hangs at startup

bool pot_init()
{
  digitalWrite(POT_ENABLE_PIN, LOW); // enable pot communication

  //  if (!i2c_start(DS1881_write_address))
  //    return false; // no reply from device
  Wire.beginTransmission(DS1881_BASE_I2C_ADDR);

  Wire.write(0b10000010);       // Nonvolatile writes: Zero crossing, 63 values + mute
  Wire.endTransmission();
   delay(20); // wait for EEPROM write to finish
  //delay(10); // half delay when clocking nano to 8 MHz

  Wire.beginTransmission(DS1881_BASE_I2C_ADDR);
  Wire.write(0b10000110);       // Go back to volatile writes
  Wire.endTransmission();
  delay(20); // wait for EEPROM write to finish
  //delay(10); // half delay when clocking nano to 8 MHz

  digitalWrite(POT_ENABLE_PIN, HIGH);

  return true;
}

/* Set the digipot to given value.
   Min volume 0: -80db attenuation,
   Max volume 63:  0db attenuation
*/
bool pot_set(uint8_t pot, uint8_t val)
{
  val &= 0b00111111; // only the low 6 bits matter

  val = 63 - val;    // invert the value.
  // pot acts as attenuator: 0 - no attenuation (max volume)
  // we want larger number to mean louder

  if (pot)
    val |= 0b01000000; // set the pot bit;

  digitalWrite(POT_ENABLE_PIN, LOW); // enable pot communication

  Wire.beginTransmission(DS1881_BASE_I2C_ADDR);
  //  if (!i2c_start(DS1881_write_address))
  //    return false;  // no reply from device

  bool res = Wire.write(val);
  Wire.endTransmission();

  digitalWrite(POT_ENABLE_PIN, HIGH);

  return res;
}

That's where the entire transfer is done. Check the returned error code.

I don’t have a returned error code

You do:
https://www.arduino.cc/en/Reference/WireEndTransmission

I can’t see any error codes anywhere

image

still don't know why I need to see that, my sketch compiles/uploads, then freezes,
I don't receive any error codes anywhere

Are you sure it is freezing during i2c transactions? If so, you are probably getting noise on the line and the default behavior of the library is to wait indefinitely in a couple of places for the HW to be in the proper state.
Recently, the library got a timeout feature, but it is disabled by default. You have to call
Wire.setWireTimeout() and then getWireTimeoutFlag() to see if you timed out.

// I2C Digital Potentiometer with timeout
// originally
// by Nicholas Zambetti <http://www.zambetti.com>
// and Shawn Bonkowski <http://people.interaction-ivrea.it/s.bonkowski/>

// Demonstrates use of the Wire library with timeout
// Controls AD5171 digital potentiometer via I2C/TWI

// Created 7 July 2020

// This example code is in the public domain.

const uint32_t timeout = 5000;  // microseconds, 0 = infinite, default = 25000
const bool reset = true;    // true = force TWI reset if timeout occurs, default = false

#include <Wire.h>

void setup() {
  Wire.begin(); // join i2c bus (address optional for master)
  Wire.setWireTimeout( timeout, reset );
}

byte val = 0;
int count = 0;

void loop() {
  Wire.beginTransmission(44); // transmit to device #44 (0x2c)
  // device address is specified in datasheet
  Wire.write(byte(0x00));            // sends instruction byte
  Wire.write(val);             // sends potentiometer value byte
  Wire.endTransmission();     // stop transmitting

  if ( Wire.getWireTimeoutFlag() ) {
    // handle timeout
    Wire.clearWireTimeoutFlag();
    count++;
  }

  val++;        // increment value
  if (val == 64) { // if reached 64th position (max)
    val = 0;    // start over from lowest value
  }
  delay(500);
}

The standard AVR library has that call now, but does not appear to be in Megacore for Atmega1284P.