2 Kanal Dimmer auf STM32 Basis zur Diskussion

Entwicklung und Bau von Hardware aller Art, die im HM-Umfeld eingesetzt werden kann

Moderator: Co-Administratoren

Jack01
Beiträge: 128
Registriert: 01.02.2017, 17:08
Hat sich bedankt: 49 Mal
Danksagung erhalten: 9 Mal

Re: 2 Kanal Dimmer auf STM32 Basis zur Diskussion

Beitrag von Jack01 » 03.12.2019, 18:12

Sehr merkwürdig :oops:
Habe das EEPROM schon einmal gewechselt. Habe noch ein drittes und werde das morgen mal probieren. Die Pullups habe ich drin und die elektrischen Verbindungen habe ich auch gescheckt (und PIN1 ist ja hoffentlich beim Punkt auf dem Gehäuse :wink: ).
Vielen Dank für den tollen Support.

Gruß

Hans-Jürgen
Dateianhänge
No EEPROM.JPG
Raspberrymatic als VM auf Proxmox (Fujitsu Esprimo) mit HB-RF-USB und 34 Geräte (18 x Eigenbau)
4 x Amazon Alexa, ioBroker
Remote Control via TinyMatic und VPN
Motion Eye und ioBroker auf Proxmox

jp112sdl
Beiträge: 12108
Registriert: 20.11.2016, 20:01
Hat sich bedankt: 848 Mal
Danksagung erhalten: 2148 Mal
Kontaktdaten:

Re: 2 Kanal Dimmer auf STM32 Basis zur Diskussion

Beitrag von jp112sdl » 03.12.2019, 18:15

Jack01 hat geschrieben:
03.12.2019, 18:12
(und PIN1 ist ja hoffentlich beim Punkt auf dem Gehäuse ).
Fotos vom Aufbau sind auch immer sehr hilfreich

VG,
Jérôme ☕️

---
Support for my Homebrew-Devices: Download JP-HB-Devices Addon

papa
Beiträge: 705
Registriert: 22.05.2018, 10:23
Hat sich bedankt: 24 Mal
Danksagung erhalten: 120 Mal

Re: 2 Kanal Dimmer auf STM32 Basis zur Diskussion

Beitrag von papa » 03.12.2019, 20:43

Ich kann die Probleme mit den EEPROM nicht nachvollziehen. Hatte nur einmal am Anfang Probleme - da hatte ich die Pullups vergessen. Welche EEPROMs hast Du genau ? Bitte den den Typ angeben. Ich kann mich noch an einen Fall erinnern, dass ein extra Delay für einen anderen EEPROM geholfen hat. Das hat dann aber irgendwie nicht mehr den Weg in den Code gefunden. Muss mal die Beiträge hier und im FHEM-Forum absuchen.

Edit: Habs gefunden - schau mal hier https://forum.fhem.de/index.php/topic,101177.0.html

Wenn das hilft, können wir das in den Code einpflegen.
Anfragen zur AskSin++ werden nur im Forum beantwortet

der-pw
Beiträge: 435
Registriert: 26.01.2019, 13:39
Wohnort: Wolfenbüttel
Hat sich bedankt: 126 Mal
Danksagung erhalten: 100 Mal
Kontaktdaten:

Re: 2 Kanal Dimmer auf STM32 Basis zur Diskussion

Beitrag von der-pw » 04.12.2019, 08:08

Jack01 hat geschrieben:
03.12.2019, 18:12
und PIN1 ist ja hoffentlich beim Punkt auf dem Gehäuse
Wenn du von "Punkt" sprichst hast du eine aktuellere Boardversion (als ich sie habe) herstellen lassen.
Der Punkt kam nämlich später noch dazu. Aber Ja, Pin1 liegt am Punkt

Anbei nochmal Screenshots in den Details.

at24cs32.jpg
sdl-sca.jpg
Edit:
Was ich damit aber sagen wollte:
An den I2C-Bahnen zum EEPROM habe ich nichts mehr revidiert. Da kann der Fehler eigentlich auch nicht stecken.
Grüße,
Patrick

https://github.com/der-pw

Jack01
Beiträge: 128
Registriert: 01.02.2017, 17:08
Hat sich bedankt: 49 Mal
Danksagung erhalten: 9 Mal

Re: 2 Kanal Dimmer auf STM32 Basis zur Diskussion

Beitrag von Jack01 » 04.12.2019, 13:14

Die Bezeichnung der EEPROMS lautet: ATMTC 085, 24C32N, SU27D. Es ist also kein "CS" Typ wie in der Schaltung angegeben (habe ich auch jetzt erst gesehen). Ich hab die Datenblätter mal verglichen. Auf den ersten Blick kann ich keinen Unterschied (außer der vorprogrammierten Seriennummer beim CS Typ).
Den Beitrag im FHEM-Forum werde ich mal durcharbeiten. Ich melde mich dann wieder.
Ich habe mal einen Testaufbau mit einem Arduino Mini Pro gemacht und das I2C Test Sketch laufen lassen. Hier das Ergebnis:
an Pro mini mit I2c Scanner.JPG
Test mit Arduino Mini Pro
Dateianhänge
IMG_20191204_114201.jpg
Messungen von den EEPROMS nach den Pins B6 und B7
IMG_20191204_114028.jpg
Messung Pullups von Pin1 (VCC) nach den Pins SDA und SCL
IMG_20191204_113557.jpg
Aufbau auf Platine
IMG_20191204_114535.jpg
Test mit Arduino Mini Pro
Raspberrymatic als VM auf Proxmox (Fujitsu Esprimo) mit HB-RF-USB und 34 Geräte (18 x Eigenbau)
4 x Amazon Alexa, ioBroker
Remote Control via TinyMatic und VPN
Motion Eye und ioBroker auf Proxmox

jp112sdl
Beiträge: 12108
Registriert: 20.11.2016, 20:01
Hat sich bedankt: 848 Mal
Danksagung erhalten: 2148 Mal
Kontaktdaten:

Re: 2 Kanal Dimmer auf STM32 Basis zur Diskussion

Beitrag von jp112sdl » 04.12.2019, 13:29

Jack01 hat geschrieben:
04.12.2019, 13:14
Ich habe mal einen Testaufbau mit einem Arduino Mini Pro gemacht und das I2C Test Sketch laufen lassen. Hier das Ergebnis:
Und genau das sollte beim STM32 auch ausgegeben werden...

VG,
Jérôme ☕️

---
Support for my Homebrew-Devices: Download JP-HB-Devices Addon

Jack01
Beiträge: 128
Registriert: 01.02.2017, 17:08
Hat sich bedankt: 49 Mal
Danksagung erhalten: 9 Mal

Re: 2 Kanal Dimmer auf STM32 Basis zur Diskussion

Beitrag von Jack01 » 04.12.2019, 13:49

@papa: wenn ich den Beitrag richtig verstanden habe. soll ich in der "Storage.h" folgenden Code eingeben:

Code: Alles auswählen

#ifdef EEPROMDELAY
  void _eeprom_delay() { _delay_ms(EEPROMDELAY); }
#else
  void _eeprom_delay() {}
#endif
Kannst Du mir sagen, ab welcher Zeilennummer?
Anschließend vor allen endTransmission ein _eeprom_delay() eingeben.
Etwa so:?

Code: Alles auswählen

  bool present () {
    Wire.beginTransmission(ID);
    Wire.write(0);  //high addr byte
    Wire.write(0);  //low addr byte
	__eeprom_delay()
    return Wire.endTransmission() == 0;
  }
Raspberrymatic als VM auf Proxmox (Fujitsu Esprimo) mit HB-RF-USB und 34 Geräte (18 x Eigenbau)
4 x Amazon Alexa, ioBroker
Remote Control via TinyMatic und VPN
Motion Eye und ioBroker auf Proxmox

papa
Beiträge: 705
Registriert: 22.05.2018, 10:23
Hat sich bedankt: 24 Mal
Danksagung erhalten: 120 Mal

Re: 2 Kanal Dimmer auf STM32 Basis zur Diskussion

Beitrag von papa » 04.12.2019, 13:58

Zum Testen einfach

Code: Alles auswählen

_delay_ms(1);
vor alle

Code: Alles auswählen

Wire.endTransmission()
Zeilen einfügen. Den offiziellen Teil können wir dann später machen.
Anfragen zur AskSin++ werden nur im Forum beantwortet

Jack01
Beiträge: 128
Registriert: 01.02.2017, 17:08
Hat sich bedankt: 49 Mal
Danksagung erhalten: 9 Mal

Re: 2 Kanal Dimmer auf STM32 Basis zur Diskussion

Beitrag von Jack01 » 05.12.2019, 09:58

Es läuft!
habe wie von @papa vorgeschlagen, die storage.h angepasst.
Vielen Dank für Eure Geduld für meine Spielerei, und ich freue mich schon auf noch viele weitere Projekte mit Euch.

Gruß

Hans-Jürgen
IMG_20191205_093402.jpg
nach Anpassung storage.JPG

Code: Alles auswählen

//- -----------------------------------------------------------------------------------------------------------------------
// AskSin++
// 2016-10-31 papa Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
//- -----------------------------------------------------------------------------------------------------------------------

#ifndef __STORAGE_H__
#define __STORAGE_H__

#include "Debug.h"

#ifdef ARDUINO_ARCH_STM32F1
  #include "flash_stm32.h"
#endif

namespace as {

class InternalEprom {

#ifdef ARDUINO_ARCH_STM32F1
  #if MCU_STM32F103CB
    #define FlashPageSize 0x400
    #define FlashStartAddress 0x0801fc00  // Page127
  #elif defined(MCU_STM32F103C8)
    #define FlashPageSize 0x400
    #define FlashStartAddress 0x0800fc00  // Page63
  #else
    #error Unknown CPU type
  #endif

  // we mirror 1 Flash Page into RAM
  uint8_t data[FlashPageSize];

  void eeprom_read_block(void* buf,const void* addr,size_t size) {
    uintptr_t offset = (uintptr_t)addr;
    if( offset + size < sizeof(data) ) {
      memcpy(buf,&data[offset],size);
    }
  }
  void eeprom_write_block(const void* buf,void* addr,size_t size) {
    uintptr_t offset = (uintptr_t)addr;
    if( offset + size < sizeof(data) ) {
      memcpy(&data[offset],buf,size);
    }
  }
#endif

#ifndef ARDUINO
  // we mirror 1 Flash Page into RAM
  uint8_t data[1024];

  inline void memcpy(void* dest,const void* src,size_t size) {
    uint8_t* d = (uint8_t*)dest;
    const uint8_t* s = (const uint8_t*)src;
    for( size_t i=0; i<size; ++i ) {
      *d++ = *s++;
    }
  }

  void eeprom_read_block(void* buf,const void* addr,size_t size) {
    uintptr_t offset = (uintptr_t)addr;
    if( offset + size < sizeof(data) ) {
      memcpy(buf,&data[offset],size);
    }
  }
  void eeprom_write_block(const void* buf,void* addr,size_t size) {
    uintptr_t offset = (uintptr_t)addr;
    if( offset + size < sizeof(data) ) {
      memcpy(&data[offset],buf,size);
    }
  }
#endif

public:
  InternalEprom () {
#ifdef ARDUINO_ARCH_STM32F1
    // copy data from FLASH into RAM
    uint16_t* towrite = (uint16_t*)data;
    uint16_t *toread = (uint16_t*)(uintptr_t)FlashStartAddress;
    for( size_t i=0; i<sizeof(data)/2; ++i ) {
      *(towrite + i) = *(toread + i);
    }
#endif
  }

  bool present () {
    return true;
  }

  uint16_t size () {
    return 1024;
  }

  void store () {
#ifdef ARDUINO_ARCH_STM32F1
    // copy data from RAM to FLASH
    FLASH_Unlock(); //unlock flash writing
    FLASH_ErasePage(FlashStartAddress);
    uint16_t* toread = (uint16_t*)data;
    for( size_t i=0; i<sizeof(data)/2; ++i ) {
      FLASH_ProgramHalfWord(FlashStartAddress+i+i,*(toread+i));
    }
    FLASH_Lock();
#endif
  }

  uint8_t getByte (uint16_t addr) {
    uint8_t b = 0;
    eeprom_read_block(&b,(void*)(uintptr_t)addr,1);
    return b;
  }

  bool setByte (uint16_t addr, uint8_t d) {
    uint8_t b = d;
    eeprom_write_block(&b,(void*)(uintptr_t)addr,1);
    return true;
  }

  bool setData (uint16_t addr,uint8_t* buf,uint16_t size) {
    eeprom_write_block(buf,(void*)(uintptr_t)addr,size);
    return true;
  }

  bool getData (uint16_t addr,uint8_t* buf,uint16_t size) {
    eeprom_read_block(buf,(const void*)(uintptr_t)addr,size);
    return true;
  }

  bool clearData (uint16_t addr, uint16_t size) {
    for( uint16_t i=0; i<size; ++i) {
      setByte(addr+i,0);
    }
    return true;
  }
};


#if defined(TwoWire_h) || defined(_WIRE_H_) || defined(_TWOWIRE_H_) || defined(_WIREBASE_H_)

// with help of https://github.com/JChristensen/extEEPROM

template <uint8 ID,uint16_t PAGES,uint8_t PAGESIZE>
class at24cX {
public:
  at24cX () {}

  bool present () {
    Wire.beginTransmission(ID);
    Wire.write(0);  //high addr byte
    Wire.write(0);  //low addr byte
	_delay_ms(1);
    return Wire.endTransmission() == 0;
  }

  uint16_t size () {
    return PAGES * PAGESIZE;
  }

  void store () {}

  uint8 getByte (uint16_t addr) {
    uint8 b = 0;
    Wire.beginTransmission(ID);
    Wire.write(addr >> 8);
    Wire.write(addr & 0xff);
	_delay_ms(1);
    if( Wire.endTransmission() == 0 ) {
      Wire.requestFrom(ID,(uint8_t)1);
      b = Wire.read();
    }
    return b;
  }

  bool setByte (uint16_t addr, uint8 d) {
    bool success = true;
    Wire.beginTransmission(ID);
    Wire.write(addr >> 8);
    Wire.write(addr & 0xff);
    Wire.write(d);
	_delay_ms(1);
    success = Wire.endTransmission() == 0;
    // wait for write operation finished
    if( success == true ) {
      success = waitComplete();
    }
    return success;
  }

  uint16_t calcBlockSize(uint16_t addr, uint16_t size) {
    uint16_t block = PAGESIZE - (addr % PAGESIZE);
    // BUFFER_LENGTH from Wire.h - 2 byte address
    block = (BUFFER_LENGTH - 2) < block ? BUFFER_LENGTH - 2 : block;
    return (size < block) ? size : block;
  }


  bool setData (uint16_t addr,uint8* buf,uint16_t size) {
    // DPRINT("setData: ");DHEX(addr);DPRINT(" ");DDECLN(size);
    bool success = true;
    while( success == true && size > 0 ) {
      uint16_t towrite = calcBlockSize(addr, size);
      // DPRINT("  write: ");DHEX(addr);DPRINT(" ");DDECLN(towrite);
      Wire.beginTransmission(ID);
      Wire.write(addr >> 8);
      Wire.write(addr & 0xff);
      uint8_t done = 0;
      while( done < towrite ) {
        done++;
        Wire.write(*buf++);
      }
	  _delay_ms(1);
      success = Wire.endTransmission() == 0;
      // wait for write operation finished
      if( success == true ) {
        success = waitComplete();
      }
      else {
        DPRINTLN(F("ERROR EEPROM WRITE"));
      }
      size -= towrite;
      addr += towrite;
    }
    return success;
  }

  bool getData (uint16_t addr,uint8* buf,uint16_t size) {
    bool success = true;
    while( success == true && size > 0 ) {
      uint16_t toread = calcBlockSize(addr, size);
      //DPRINT("Read: ");DHEX(addr);DPRINT(" ");DHEXLN(toread);
      Wire.beginTransmission(ID);
      Wire.write(addr >> 8);
      Wire.write(addr & 0xff);
	  _delay_ms(1);
      success = Wire.endTransmission() == 0;
      if( success == true ) {
        Wire.requestFrom(ID,(uint8_t)toread);
        uint8_t done = 0;
        while( done < toread ) {
          done++;
          *buf++ = (uint8_t)Wire.read();
        }
      }
      size -= toread;
      addr += toread;
    }
    return success;
  }

  bool clearData (uint16_t addr, uint16_t size) {
    // DPRINT("clearData: ");DHEX(addr);DPRINT(" ");DDECLN(size);
    bool success = true;
    while( success == true && size > 0 ) {
      uint16_t towrite = calcBlockSize(addr, size);
      // DPRINT("  clear: ");DHEX(addr);DPRINT(" ");DDECLN(towrite);
      Wire.beginTransmission(ID);
      Wire.write(addr >> 8);
      Wire.write(addr & 0xff);
      uint8_t done = 0;
      while( done < towrite ) {
        done++;
        Wire.write(0);
      }
	  _delay_ms(1);
      success = Wire.endTransmission() == 0;
      // wait for write operation finished
      if( success == true ) {
        success = waitComplete();
      }
      else {
        DPRINTLN(F("ERROR EEPROM CLEAR"));
      }
      size -= towrite;
      addr += towrite;
    }
//    DPRINTLN("clearData done");
    return success;
  }

  bool waitComplete () {
    //wait up to 50ms for the write to complete
    for (uint8_t i=50; i; --i) {
      _delay_ms(1); //no point in waiting too fast
      if( present() == true ) {
        return true;
      }
    }
    DPRINTLN(F("ERROR EEPROM WAIT"));
    return false;
  }

};

template <uint8_t ID,uint16_t PAGES,uint8_t PAGESIZE>
class CachedAt24cX : public at24cX<ID,PAGES,PAGESIZE> {
  uint8_t  pagecache[PAGESIZE];
  uint16_t pageaddr;
  bool     dirty;
public:
  typedef at24cX<ID,PAGES,PAGESIZE> Base;
  CachedAt24cX () : pageaddr(0xffff), dirty(false) {}

  void store () {
    writecache();
  }

protected:
  void writecache () {
    if( pageaddr != 0xffff && dirty == true ) {
      // DPRINT("WRITECACHE "); DHEXLN(pageaddr);
      Base::setData(pageaddr, pagecache, PAGESIZE);
      dirty = false;
    }
  }

  uint8_t* fillcache(uint16_t addr) {
    uint16_t paddr = addr & ~(PAGESIZE-1);
    if( pageaddr != paddr ) {
      writecache();
      pageaddr = paddr;
      // DPRINT("FILLCACHE "); DHEXLN(pageaddr);
      Base::getData(pageaddr,pagecache,PAGESIZE);
      dirty = false;
    }
    return pagecache;
  }

  void clearcache () {
    writecache();
    // DPRINT("CLEARCACHE\n");
    pageaddr = 0xffff;
  }

public:
  uint8_t getByte (uint16_t addr) {
    fillcache(addr);
    return pagecache[addr - pageaddr];
  }

  bool setByte (uint16_t addr, uint8_t d) {
    fillcache(addr);
    pagecache[addr - pageaddr] = d;
    dirty = true;
    return true;
  }

  bool getData (uint16_t addr,uint8_t* buf,uint16_t size) {
    writecache();
    return Base::getData(addr, buf, size);
  }

  bool setData (uint16_t addr,uint8_t* buf,uint16_t size) {
    clearcache();
    return Base::setData(addr, buf, size);
  }

  bool clearData (uint16_t addr, uint16_t size) {
    clearcache();
    return Base::clearData(addr, size);
  }

};

// define some known EEPROM types
typedef CachedAt24cX<0x50,128,32> at24c32;
typedef CachedAt24cX<0x50,256,32> at24c64;

#endif


template <class DRIVER=InternalEprom>
class StorageWrapper : public DRIVER {

public:
  StorageWrapper () {}

  bool setup (uint16_t checksum=0) {
    bool firststart = false;
    uint32_t mem;
    DRIVER::getData(0x0,(uint8_t*)&mem,4);
    uint32_t magic = 0xCAFE0000 | checksum;
    if(magic != mem) {
      DHEXLN(mem);
      DPRINT(F("Init Storage: "));
      DHEXLN(magic);
      // init eeprom
      DRIVER::setData(0x0,(uint8_t*)&magic,4);
      firststart = true;
    }
    return firststart;
  }

  bool setBits (uint16_t addr, uint8_t bits) {
    DRIVER::setByte(addr,DRIVER::getByte(addr) | bits);
    return true;
  }

  bool clearBits (uint16_t addr, uint8_t bits) {
    DRIVER::setByte(addr,DRIVER::getByte(addr) & ~bits);
    return true;
  }

  bool setData (uint16_t addr,uint8_t* buf,uint16_t size) {
    return DRIVER::setData(addr,buf,size);
  }

  template <class T>
  bool setData (uint16_t addr,const T& obj) {
    return DRIVER::setData(addr,(uint8_t*)&obj,sizeof(T));
  }

  bool getData (uint16_t addr,uint8_t* buf,uint16_t size) {
    return DRIVER::getData(addr,buf,size);
  }

  template <class T>
  bool getData (uint16_t addr,T* obj) {
    return DRIVER::getData(addr,(uint8_t*)obj,sizeof(T));
  }

  bool clearData (uint16_t addr, uint16_t size) {
    return DRIVER::clearData(addr,size);
  }

  void reset () {
    // clear magic
    clearData(0x0,4);
  }

  void dump (uint16_t start, uint16_t num) {
    for( uint16_t i=0; i<num; ++i, ++start ) {
      DHEX(DRIVER::getByte(start));
      DPRINT(F(" "));
    }
    DPRINT(F("\n"));
  }

};

#ifndef STORAGEDRIVER
#define STORAGEDRIVER InternalEprom
#endif

extern void* __gb_store;

class Storage : public StorageWrapper<STORAGEDRIVER > {
public:
  Storage () {
    __gb_store = this;
  }
};


static inline Storage& storage () {
  return *((Storage*)__gb_store);
}

#define STORAGE_CFG_START 0x04
class StorageConfig {
  uint8_t  size;
public:
  StorageConfig (uint8_t s) : size(s) {}

  uint8_t checksum () const {
    uint8_t sum = 0x5e;
    for( uint8_t i=0; i<size-1; ++i ) {
      sum ^= getByte(i);
    }
    return sum;
  }

  void validate () {
    setByte(size-1,checksum());
  }

  bool valid () const {
    return getByte(size-1) == checksum();
  }

  void clear () {
    storage().clearData(STORAGE_CFG_START, size);
  }

  uint8_t getSize () const {
    return size-1;
  }

  uint8_t getByte (uint8_t offset) const {
    return storage().getByte(STORAGE_CFG_START+offset);
  }

  void setByte(uint8_t offset,uint8_t data) {
    storage().setByte(STORAGE_CFG_START+offset,data);
  }

};

}

#endif
Raspberrymatic als VM auf Proxmox (Fujitsu Esprimo) mit HB-RF-USB und 34 Geräte (18 x Eigenbau)
4 x Amazon Alexa, ioBroker
Remote Control via TinyMatic und VPN
Motion Eye und ioBroker auf Proxmox

jp112sdl
Beiträge: 12108
Registriert: 20.11.2016, 20:01
Hat sich bedankt: 848 Mal
Danksagung erhalten: 2148 Mal
Kontaktdaten:

Re: 2 Kanal Dimmer auf STM32 Basis zur Diskussion

Beitrag von jp112sdl » 05.12.2019, 11:07

Hast du den FreqTest mal laufen lassen?

Deinem seriellen Log zufolge wird zumindest keine Freq aus dem EEPROM gelesen.

EDIT: Angelernt war zu dem Zeitpunkt auch noch nicht, oder? Der Status wird nach dem Start zumindest an 000000 gesendet.

VG,
Jérôme ☕️

---
Support for my Homebrew-Devices: Download JP-HB-Devices Addon

Antworten

Zurück zu „Hardwareentwicklung und Selbstbau von Aktoren und Sensoren“