Replacement for the Ricor K526S controller

Tags:

I have a bunch of Ricor K526S cryocoolers. In this note I describe a controller replacement for one of them, which had the built-in controller die.

Interface

Electrically speaking, a K526S cryocooler is simply a BLDC motor with Hall sensors. It is very easy to drive one, and the most complicated part is determining the pinout. Here is the interposer board it has inside, labelled with pin numbers (that I’ve arbitrarily assigned):

The pinout is as follows (phases A, B, C are ordered clockwise, looking from the BLDC drive end):

Pin # Wire color Function
1 (none) BLDC drive supply
2 (none) Spreading confusion*
3 Blue Hall sensor supply
4 Yellow Phase A
5 Orange Phase C
6 Brown Phase B
7 Green Ground
U Red Phase A
V White Phase B
W Black Phase C

* Not actually connected anywhere, but still runs across the board and through two vias for some reason.

It is not known what Hall sensors exactly are used, but they appear to be of the common type, compatible with e.g. US5881. They tolerate at least 5 V of supply voltage, and have an open-drain NMOS output.

Controller logic

The following Silego SLG46620V gateware, implemented based on Microchip AN587 can drive the cryocooler at its maximum speed for the supplied drive voltage:

bldc.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
module top(
        (* LOC="P3" *) output uh,
        (* LOC="P4" *) output ul,
        (* LOC="P5" *) output vh,
        (* LOC="P6" *) output vl,
        (* LOC="P7" *) output wh,
        (* LOC="P8" *) output wl,
        (* LOC="P14", PULLUP="10k" *) input us,
        (* LOC="P16", PULLUP="10k" *) input vs,
        (* LOC="P18", PULLUP="10k" *) input ws,
    );

    reg [5:0] drivers;
    always @(*) begin
        drivers <= 6'b000000;
        case({us, vs, ws})
            3'b101: drivers <= 6'b100100;
            3'b001: drivers <= 6'b000110;
            3'b011: drivers <= 6'b010010;
            3'b010: drivers <= 6'b011000;
            3'b110: drivers <= 6'b001001;
            3'b100: drivers <= 6'b100001;
        endcase
    end

    wire ui, vi, wi;
    assign {ui, ul, vi, vl, wi, wl} = drivers;

    // assign {uh, vh, wh} = ~{ui, vi, wi};
    assign {uh, vh} = ~{ui, vi};
    GP_2LUT #(.INIT(4'b0001)) lut (.IN0(wi), .OUT(wh));

endmodule

It can be built and run with:

build.sh
1
2
3
4
5
6
7
#!/bin/sh -ex

yosys -q \
  -p "read_verilog -noautowire bldc.v" \
  -p "synth_greenpak4 -json bldc.json"
gp4par -q bldc.json -o bldc.txt
gp4prog -q -e bldc.txt -v 5 -n 1,3,4,5,6,7,8,14,16,18

The connections from the SLG46620V to the MOSFETs and sensors are as follows:

SLG46620V pin # K526S connection
3 U high side driver
4 U low side driver
5 V high side driver
6 V low side driver
7 W high side driver
8 W low side driver
14 4
16 6
18 5
1 (supply) 3
11 (ground) 7

When writing this note I’ve used Vishay Si4564DY MOSFETs, which seem to perform satisfactorily. At no load (with the crankshaft exposed to atmosphere) rotation accelerates until about 8 V, and after that point only current grows. Current under load is to be determined.

Phase order

There are three possible mappings of Hall sensor phases to coil phases. The rotor will spin regardless of how good the match is, as it has a fair amount of inertia (in fact, once spinning, it’ll keep spinning even if one of the coils is completely disconnected). Thus, it is not obvious what the correct mapping is. I’ve measured the natural frequency for all three combinations, at 8 V coil supply:

Phase mapping Period
A:4 B:6 C:5 19 ms
A:5 B:4 C:6 24 ms
A:6 B:5 C:4 19 ms

The waveforms measured at U, W, V differ considerably:

I’ve also tried stepping the coils using the following gateware:

stepbldc.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
module top(
        (* LOC="P3" *) output uh,
        (* LOC="P4" *) output ul,
        (* LOC="P5" *) output vh,
        (* LOC="P6" *) output vl,
        (* LOC="P7" *) output wh,
        (* LOC="P8" *) output wl,
        (* LOC="P14", PULLUP="10k" *) input us,
        (* LOC="P16", PULLUP="10k" *) input vs,
        (* LOC="P18", PULLUP="10k" *) input ws,
    );

    wire clk;
    GP_LFOSC #(
        .AUTO_PWRDN(0)
    ) lfosc (
        .CLKOUT(clk)
    );

    localparam DIVIDER = 400;
    reg  [13:0] divcnt = DIVIDER;
    always @(posedge clk)
        if(divcnt == 0)
            divcnt <= DIVIDER;
        else
            divcnt <= divcnt - 1;

    wire stepclk = (divcnt == 0);

    reg [5:0] drivers;
    always @(posedge stepclk) begin
        case({us, vs, ws})
            3'b101: drivers <= 6'b100100;
            3'b001: drivers <= 6'b000110;
            3'b011: drivers <= 6'b010010;
            3'b010: drivers <= 6'b011000;
            3'b110: drivers <= 6'b001001;
            3'b100: drivers <= 6'b100001;
        endcase
    end

    wire ui, vi, wi;
    assign {ui, ul, vi, vl, wi, wl} = drivers;

    // assign {uh, vh, wh} = ~{ui, vi, wi};
    assign {uh, vh} = ~{ui, vi};
    GP_2LUT #(.INIT(4'b0001)) lut (.IN0(wi), .OUT(wh));

endmodule

The mapping A:4 B:6 C:5 runs the fastest, with the waveforms closest to a perfect sine, and steps without unexpected abrupt jumps, so it seems that it is the correct mapping.


Want to discuss this note? Drop me a letter.