FM80 solar charge controller datalogger

Thread Starter

nsaspook

Joined Aug 27, 2009
16,487
Time to wrap this thing up. Hardware, software and the system interactions are operational and stable.
1767984346220.png
1767984361758.png
1767984390361.png
1767984418069.png
1767984444362.png
1767999672228.png

https://github.com/nsaspook/mqtt_comedi
https://github.com/nsaspook/mqtt_comedi/blob/main/daq_bmc/daq_bmc.c
Code:
[    7.046099] spibmc spi1.1: spi link version 1.4
[    7.046128] spibmc spi1.1: BMCboard default: do_conf=1, di_conf=1, daqbmc_conf=0
[    7.046801] comedi comedi0: bmc protocol version 0.98
[    7.046816] comedi comedi0: 4 cpu(s) online for threads
[    7.046825] comedi comedi0: BMCBoard using chip select : 0x 1
[    7.046833] comedi comedi0: BMCboard device detection started
[    7.046847] comedi comedi0: Probing for PIC18Fx7Q84 DAQ device, SPI slave mode
[    7.046856] comedi comedi0: BMCboard SPI setup: spi cs 1: 8000000 Hz: mode 0x3: probing for controller device PICSL12
[    7.046866] comedi comedi0: 16 bit and less device buffers set to 16 bits
[    7.048069] comedi comedi0: Calibration data downloaded from board
[    7.049004] comedi comedi0: Calibration data downloaded from board
[    7.049013] comedi comedi0: Analog Out channels 1, Analog In channels 16 : Q84 config code 0x0
[    7.049021] comedi comedi0: PIC18F57Q84 DAQ device setup complete
[    7.049027] comedi comedi0: DISPLAY, RS232/TTL and device serial TX/RX channels 8
[    7.049033] comedi comedi0: Digital Out channels 16
[    7.049039] comedi comedi0: Digital In channels 24
[    7.049305] comedi comedi0: ao device thread start
[    7.088331] comedi comedi0: driver 'daq_bmc' has successfully auto-configured 'BMCboard'.
https://github.com/nsaspook/mqtt_comedi/blob/main/bmc/bmc_mqtt.c

Software for the Linux SPI protocol driver link for Comedi API DAQ for the solar devices, BMC control program in C using MQTT for Home Assistant devices and entities, and the firmware for the 57Q84.
Hardware PCB design files using Eagle
Matter over Thread router for IoT device control and monitoring on the Orange PI Zero 3 4G

1767985035680.png

1767985061457.png
 
Last edited:

Thread Starter

nsaspook

Joined Aug 27, 2009
16,487
Added more battery storage to the system for a total of 15KWh of energy storage. 10 for direct Solar storage and 5 for the energy buffer.
1776788980684.png
3/0 AWG battery wiring. Glad I dumpster dived that wiring long ago, it's expensive now.

Starting to use vscode a little more for the project.
1776789725527.png
1776789238746.png

Cleaning up the SPI slave code a bit to optimize processing time between master data bytes to increase throughput a bit.

Yellow: MASTER data request bytes spacing
Blue: SLAVE processing time per received data byte
1776794067273.png
1776794129179.png
1776789424887.png
1776789441246.png
Orange Pi Zero 3 4G kernel 6.1.31+

1776795507879.png
1776795524845.png
RPi Zero W kernel 6.12.75-v8+
 
Last edited:

Thread Starter

nsaspook

Joined Aug 27, 2009
16,487
First nice day since the BSS was upgraded.
1777078544510.png
Charged until the controller switched to float mode and then started feeding some of that energy into the house and the dump load battery bank.

1777078518330.png
 

Thread Starter

nsaspook

Joined Aug 27, 2009
16,487
@nsaspook, I thought you were insane.

Then, I saw this:

https://youtube.com/shorts/uh6yYJWHGsA
That's nice! A little too much for me (I use PVC for home electrical, custom control boards and C programming instead of PLCs) but making your home like you want and are very familiar with) is the point.
1785095198529.png
1785094963207.png
1785094985342.png
CT circuits for home energy use monitoring and control.

1785095794002.png
1785095931065.png
1785094426468.png
Industrial level piping and electrical seems natural after several decades of work if you can get the materials for little or no cost.
 
Last edited:

Thread Starter

nsaspook

Joined Aug 27, 2009
16,487
Cleaning up the documentation fro this project.

9 byte SPI linux driver to Q84 DAQ protocol and processing timing.
1790357885737.png
1: Q84 slave processing time
[2..4]: SPI data and SCK

1790357997957.png
1790358055571.png
10S persistence to see timing jitter. Slave processing time for each byte of SPI data from the Linux master. ~10us
1790358507013.png
https://raw.githubusercontent.com/nsaspook/mqtt_comedi/refs/heads/opifixes/Q84/bmc_slave.X/slaveo.c
C:
static int32_t bmc_spi_packet(struct spi_device *spi, struct bmc_packet_type * packet, ktime_t slower)
{
    int32_t ret = 0;

    if (spi == NULL) {
        ret = -ESHUTDOWN;
        return ret;
    }

    spi_message_init_with_transfers(packet->m, &packet->one_t, 1); //one transfer per message
    spi_bus_lock(spi->controller);
    ret = spi_sync_locked(spi, packet->m);
    spi_bus_unlock(spi->controller);
    __set_current_state(TASK_INTERRUPTIBLE);
    schedule_hrtimeout_range(&slower, 0, HRTIMER_MODE_REL_PINNED);

    return ret;
}

static const uint32_t SPI_GAP_LONG = 12000; // time for the Q84 to process each received SPI byte

static int32_t bmc_spi_exchange(struct comedi_device *dev, struct bmc_packet_type * packet)
{
    struct comedi_subdevice *s = dev->read_subdev;
    struct spi_param_type *spi_data = s->private;
    struct spi_device *spi = spi_data->spi;
    int32_t ret = 0;
    ktime_t slower = ns_to_ktime(SPI_GAP_LONG);

    if (spi == NULL) {
        ret = -ESHUTDOWN;
        return ret;
    }

    /*
     * use nine spi transfers for the complete SPI transaction
     * we need the inter-byte processing time on the slave side
     * with only a two byte FIFO on the Q84
     */
    packet->one_t.speed_hz = spi->max_speed_hz;

    /*
     * send the cmd and 4-bit channel data
     */
    packet->one_t.tx_buf = &packet->bmc_byte_t[BMC_CMD];
    packet->one_t.rx_buf = &packet->bmc_byte_r[BMC_CMD];
    packet->one_t.cs_change = false;
    packet->one_t.len = 1;
    ret = bmc_spi_packet(spi, packet, slower);

// more code
}
Linux driver SPI timing.

Code:
/*
 * transfers one 16 bit value to the DAC device
 */
static void daqbmc_ao_put_sample(struct comedi_device *dev,
    struct comedi_subdevice *s,
    uint16_t value)
{
    const struct daqbmc_board *board = dev->board_ptr;
    struct daqbmc_private *devpriv = dev->private;
    uint32_t chan, range;

    struct bmc_packet_type *packet = kzalloc(sizeof(*packet), GFP_KERNEL | GFP_NOWAIT | GFP_ATOMIC | GFP_DMA);
    if (!packet) {
        return;
    }

    mutex_lock(&devpriv->drvdata_lock);
    chan = devpriv->ao_chan & board->n_aochan_mask;
    range = devpriv->ao_range;

    /* use single transfer for all bytes of the complete SPI transaction */
    packet->bmc_byte_t[BMC_CMD] = CMD_DAC_GO;
    packet->bmc_byte_t[BMC_D0] = (uint8_t) (value & 0xff);
    packet->bmc_byte_t[BMC_D1] = (uint8_t) ((value >> 8)&0xff);
    packet->bmc_byte_t[BMC_D2] = (uint8_t) (value & 0xff);
    packet->bmc_byte_t[BMC_D3] = BMC_D3;
    packet->bmc_byte_t[BMC_D4] = BMC_D4;
    packet->bmc_byte_t[BMC_EXT] = (uint8_t) range;
    packet->bmc_byte_t[BMC_CKSUM] = CHECKBYTE;
    packet->bmc_byte_t[BMC_DUMMY] = CHECKBYTE;
    bmc_spi_exchange(dev, packet);

    s->readback[chan] = value;
    devpriv->ao_count++;
    mutex_unlock(&devpriv->drvdata_lock);
    smp_mb__after_atomic();
    kfree(packet);
}
1790358127524.png
Slave ISR latency from SPI byte received interrupt from Linux master, ~2us until slave processing starts.

1790359121067.png
1790359169008.png
1790359300553.png
 
Last edited:
Top