Написание своей библиотеки, что не так?

Не это?

void EpdIf::SpiTransfer(unsigned char data) {
    digitalWrite(CS_PIN, LOW);
    SPI.transfer(data);
    digitalWrite(CS_PIN, HIGH);
}

Самая низкоуровневая функция в библиотеках для e-paper от китайцев.
Вот выше уровнем:

/**
 *  @brief: basic function for sending commands
 */
void Epd::SendCommand(unsigned char command) {
    DigitalWrite(dc_pin, LOW);
    SpiTransfer(command);
}

/**
 *  @brief: basic function for sending data
 */
void Epd::SendData(unsigned char data) {
    DigitalWrite(dc_pin, HIGH);
    SpiTransfer(data);
}

Вот ещё выше:

void Epd::TurnOnDisplay_Base(void)
{
	SendCommand(0x22); //Display Update Control
	SendData(0xF4);
	SendCommand(0x20); //Activate Display Update Sequence
	ReadBusy();
}

На этом уровни - всё.

Можно

https://docs.arduino.cc/tutorials/communication/SPITransaction/

Понятно, осталось проверить на совместимость…

void drawFoto(int x,int y, const uint8_t *bitmap,int w,int h) {//функция вывода фотокартинки
if(x<0||x+w>128||y<0||y+h>160){return;} 
 tft.setAddrWindow(x,y,x+w-1,y+h-1);
 SPI.beginTransaction(SPISettings(40000000, MSBFIRST, SPI_MODE0));
  digitalWrite(TFT_DC, HIGH);
  digitalWrite(TFT_CS, LOW); 
 for(int j=0; j<h; j++) {
    for(int i=0; i<2*w; i=i+2) {
    SPI.transfer(bitmap[i+1+j*2*w]);SPI.transfer(bitmap[i+j*2*w]);
  // SPI.transfer(pgm_read_byte(bitmap+i+1+j*2*w));SPI.transfer(pgm_read_byte(bitmap+i+j*2*w)); 
    }
  }
  digitalWrite(TFT_CS, HIGH);
  SPI.endTransaction();
 ///  
}

Вообще наверное можно уходить от библиотечных универсальностей к частным функциям.

как только ты вторгаешься в общий физический процесс, не соблюдая элементарной очереди, Ватсон, получишь большую дыню )))

Нет.
Экземпляров класса не может быть больше, чем контроллеров SPI. Собственно, экземпляр класса, это именно контроллер, а не подключенное устройство.
Соответственно, при работе с разными устройствами следует перестраивать режим контроллера.

Рискованное занятие. Я такого себе не позволяю. Но, если очень нужно, можно разрулить сами прерывания.
А вообще, принято выбирать контроллер, исходя из задачи. МК с двумя контроллерами SPI - не редкость.

И он может “думать, что работает” с одним устройством, хотя их много.

ну да, в прерывании выставлять флаг и не более того )))

Блин, ну этот случай прямо описан в библиотеке SPI. Вы, что не читали её?

// If SPI is used from within an interrupt, this function registers
// that interrupt with the SPI library, so beginTransaction() can
// prevent conflicts. The input interruptNumber is the number used
// with attachInterrupt. If SPI is used from a different interrupt
// (eg, a timer), interruptNumber should be 255.

Прекратите самодеятельность! Я же Вам ещё утром сказал - есть транзакции и правильно делать именно через них! Вот и делайте!

я так и делаю, надеюсь )))
PS я жеж неграмотный, свистеть на ихнем, даже бегло, это всегда пожалуйста, но читать, я же грамоте не обучен )))
PPS прочитал через переводчик, круто, ну я так и использую…
PPPS помню дракула для работы с таймерами посоветовал костыль в ядре прописать, а тут всё по человечески

void MCP4xxxx::writeValue(const int& value) {
    SPI.beginTransaction(SPISettings(speedW, MSBFIRST, spimode));
    digitalWrite(CSpin, LOW);
    MSb = 0x11;         // 0b00010001 ; where x = 0, command bits for write
    LSb = value & 0xFF; // No value greater than 255 ; send 0x0 otherwise
    uint16_t transmission = MSb << 8 | LSb;
    SPI.transfer16(transmission);
    digitalWrite(CSpin, HIGH); // Disable chip select
    SPI.endTransaction();
}