File: spi_core_3000.cpp

package info (click to toggle)
uhd 4.3.0.0%2Bds1-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 175,384 kB
  • sloc: cpp: 271,145; ansic: 103,960; python: 95,906; vhdl: 55,838; tcl: 14,117; xml: 8,535; makefile: 2,706; sh: 2,432; pascal: 230; javascript: 120; csh: 94; asm: 20; perl: 11
file content (134 lines) | stat: -rw-r--r-- 3,762 bytes parent folder | download | duplicates (3)
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//
// Copyright 2013-2014 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
// Copyright 2019 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: GPL-3.0-or-later
//

#include <uhd/exception.hpp>
#include <uhdlib/usrp/cores/spi_core_3000.hpp>
#include <chrono>
#include <memory>
#include <mutex>
#include <thread>

namespace {
constexpr double DEFAULT_DIVIDER = 30.0;
}

using namespace uhd;

spi_core_3000::~spi_core_3000(void)
{
    /* NOP */
}

class spi_core_3000_impl : public spi_core_3000
{
public:
    spi_core_3000_impl(poke32_fn_t&& poke32_fn,
        peek32_fn_t&& peek32_fn,
        const size_t base,
        const size_t reg_offset,
        const size_t readback)
        : _poke32(std::move(poke32_fn))
        , _peek32(std::move(peek32_fn))
        , _spi_div_addr(base + 0 * reg_offset)
        , _spi_ctrl_addr(base + 1 * reg_offset)
        , _spi_data_addr(base + 2 * reg_offset)
        , _readback_addr(readback)
    {
        this->set_divider(DEFAULT_DIVIDER);
    }

    uint32_t transact_spi(int which_slave,
        const spi_config_t& config,
        uint32_t data,
        size_t num_bits,
        bool readback) override
    {
        std::lock_guard<std::mutex> lock(_mutex);

        // load SPI divider
        size_t spi_divider = _div;
        if (config.use_custom_divider) {
            // The resulting SPI frequency will be f_system/(2*(divider+1))
            // This math ensures the frequency will be equal to or less than the target
            spi_divider = (config.divider - 1) / 2;
        }

        // conditionally send SPI divider
        if (spi_divider != _divider_cache) {
            _poke32(_spi_div_addr, spi_divider);
            _divider_cache = spi_divider;
        }

        // load control word
        uint32_t ctrl_word = 0;
        ctrl_word |= ((which_slave & 0xffffff) << 0);
        ctrl_word |= ((num_bits & 0x3f) << 24);
        if (config.mosi_edge == spi_config_t::EDGE_FALL)
            ctrl_word |= (1 << 31);
        if (config.miso_edge == spi_config_t::EDGE_RISE)
            ctrl_word |= (1 << 30);

        // conditionally send control word
        if (_ctrl_word_cache != ctrl_word) {
            _poke32(_spi_ctrl_addr, ctrl_word);
            _ctrl_word_cache = ctrl_word;
        }

        // load data word (must be in upper bits)
        const uint32_t data_out = data << (32 - num_bits);

        // send data word
        _poke32(_spi_data_addr, data_out);

        // conditional readback
        if (readback) {
            return _peek32(_readback_addr);
        }

        return 0;
    }

    void set_divider(const double div) override
    {
        _div = size_t((div / 2) - 0.5);
    }

private:
    poke32_fn_t _poke32;
    peek32_fn_t _peek32;
    const size_t _spi_div_addr;
    const size_t _spi_ctrl_addr;
    const size_t _spi_data_addr;
    const size_t _readback_addr;
    uint32_t _ctrl_word_cache = 0;
    std::mutex _mutex;
    size_t _div;
    size_t _divider_cache = 0;
};

spi_core_3000::sptr spi_core_3000::make(
    wb_iface::sptr iface, const size_t base, const size_t readback)
{
    return std::make_shared<spi_core_3000_impl>(
        [iface](
            const uint32_t addr, const uint32_t value) { iface->poke32(addr, value); },
        [iface](const uint32_t addr) { return iface->peek32(addr); },
        base,
        4,
        readback);
}

spi_core_3000::sptr spi_core_3000::make(spi_core_3000::poke32_fn_t&& poke32_fn,
    spi_core_3000::peek32_fn_t&& peek32_fn,
    const size_t base,
    const size_t reg_offset,
    const size_t readback)
{
    return std::make_shared<spi_core_3000_impl>(
        std::move(poke32_fn), std::move(peek32_fn), base, reg_offset, readback);
}