Class: OrigenSpi::Driver

Inherits:
Object
  • Object
show all
Includes:
Origen::Model
Defined in:
lib/origen_spi/driver.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Driver

options hash can configure

Examples:

options = {
  sclk_pin: dut.pin(:p1),
  mosi_pin: dut.pin(:p2),
  miso_pin: dut.pin(:p3),
  ss_pin: dut.pin(:p4),
  clk_format: :rl,
  ss_active: 0,
  clk_wait_time: {time_in_cycles: 2},
  clk_multiple: 2,
  miso_compare_cycle: 1,
  data_order: :msb0
}
spi = OrigenSpi::Driver.new(options)


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
# File 'lib/origen_spi/driver.rb', line 87

def initialize(options = {})
  options = {
    sclk_pin:      nil,
    mosi_pin:      nil,
    miso_pin:      nil,
    ss_pin:        nil,
    clk_format:    :nr,
    ss_active:     0,
    clk_wait_time: { time_in_us: 0 },
    clk_multiple:  2,
    data_order:    :msb0
  }.merge(options)

  @sclk_pin = options[:sclk_pin]
  @mosi_pin = options[:mosi_pin]
  @miso_pin = options[:miso_pin]
  @ss_pin = options[:ss_pin]
  @clk_format = options[:clk_format]
  @ss_active = options[:ss_active]
  @clk_wait_time = options[:clk_wait_time]
  @clk_multiple = options[:clk_multiple]
  @miso_compare_cycle = options[:miso_compare_cycle] ? options[:miso_compare_cycle] : @clk_multiple - 1
  @data_order = options[:data_order]
  @settings_validated = false
end

Instance Attribute Details

#clk_formatObject

clock format

available options are:

:rl   # return low - data changes while sclk is low, latches on rising edge
:rh   # return high

Examples:

spi_instance.clk_format = :rl


35
36
37
# File 'lib/origen_spi/driver.rb', line 35

def clk_format
  @clk_format
end

#clk_multipleObject

number of tester cycles per spi clock



53
54
55
# File 'lib/origen_spi/driver.rb', line 53

def clk_multiple
  @clk_multiple
end

#clk_wait_timeObject

time between ss_active and the first spi clock

hash containing the wait time

Examples:

spi_instance.clk_wait_time = {time_in_us: 0}        # no delay
spi_instance.clk_wait_time = {time_in_ms: 1}        # 1ms delay
spi_instance.clk_wait_time = {time_in_cycles: 2}    # 2 cycle delay


50
51
52
# File 'lib/origen_spi/driver.rb', line 50

def clk_wait_time
  @clk_wait_time
end

#data_orderObject

data order

available options are:

:msb0 - MSB is shifted first
:lsb0

Examples:

spi_instance.data_order = :lsb0


66
67
68
# File 'lib/origen_spi/driver.rb', line 66

def data_order
  @data_order
end

#miso_compare_cycleObject

cycle on which miso compares are placed (0 is the first cycle)



56
57
58
# File 'lib/origen_spi/driver.rb', line 56

def miso_compare_cycle
  @miso_compare_cycle
end

#miso_pinObject

Dut pin that serves as the master in slave out

Examples:

spi_instance.miso_pin = dut.pin(:p3)


18
19
20
# File 'lib/origen_spi/driver.rb', line 18

def miso_pin
  @miso_pin
end

#mosi_pinObject

Dut pin that serves as the master out slave in pin

Examples:

spi_instance.mosi_pin = dut.pin(:p2)


13
14
15
# File 'lib/origen_spi/driver.rb', line 13

def mosi_pin
  @mosi_pin
end

#sclk_pinObject

Dut pin that serves as the spi clock

Examples:

spi_instance.sclk_pin = dut.pin(:p1)


8
9
10
# File 'lib/origen_spi/driver.rb', line 8

def sclk_pin
  @sclk_pin
end

#settings_validatedObject (readonly)

internal attribute



69
70
71
# File 'lib/origen_spi/driver.rb', line 69

def settings_validated
  @settings_validated
end

#ss_activeObject

pin state corresponding to slave select active

Examples:

spi_instance.ss_active = 0


40
41
42
# File 'lib/origen_spi/driver.rb', line 40

def ss_active
  @ss_active
end

#ss_pinObject

Dut pin that serves as the slave select

Examples:

spi_instance.ss_pin = dut.pin(:p4)
spi_instance.ss_pin = nil   # no ss pin


25
26
27
# File 'lib/origen_spi/driver.rb', line 25

def ss_pin
  @ss_pin
end

Instance Method Details

#build_input_packet(options) ⇒ Object

Build the input packet

This is an internal method used by the shift method



333
334
335
336
337
338
339
340
341
342
343
344
# File 'lib/origen_spi/driver.rb', line 333

def build_input_packet(options)
  in_reg = Origen::Registers::Reg.dummy(options[:size])
  if options[:master_in].respond_to?(:data)
    in_reg.copy_all(options[:master_in])
  else
    unless options[:master_in].nil?
      in_reg.write options[:master_in]
      in_reg.read
    end
  end
  in_reg
end

#build_output_packet(options) ⇒ Object

Build the shift out packet

This is an internal method used by the shift method



320
321
322
323
324
325
326
327
328
# File 'lib/origen_spi/driver.rb', line 320

def build_output_packet(options)
  out_reg = Origen::Registers::Reg.dummy(options[:size])
  if options[:master_out].respond_to?(:data)
    out_reg.copy_all(options[:master_out])
  else
    out_reg.write options[:master_out]
  end
  out_reg
end

#cycle(overlay_options = {}) ⇒ Object

Internal method

Issue a tester cycle, conditionally with overlay options supplied



313
314
315
# File 'lib/origen_spi/driver.rb', line 313

def cycle(overlay_options = {})
  overlay_options == {} ? tester.cycle : (tester.cycle overlay: overlay_options)
end

#handle_miso(c, bit) ⇒ Object

Internal method

Set the state of miso



299
300
301
302
303
304
305
306
307
308
# File 'lib/origen_spi/driver.rb', line 299

def handle_miso(c, bit)
  unless @miso_pin.nil?
    if c == @miso_compare_cycle
      @miso_pin.assert bit.data if bit.is_to_be_read?
      tester.store_next_cycle @miso_pin if bit.is_to_be_stored?
    else
      @miso_pin.dont_care
    end
  end
end

#sclk_cycleObject

Run a spi clock cycle

This method can be used to clock the spi port without specifying shift data



213
214
215
216
217
218
219
220
221
222
# File 'lib/origen_spi/driver.rb', line 213

def sclk_cycle
  validate_settings
  cc 'OrigenSpi::Driver - Issue a clock cycle'
  @sclk_pin.restore_state do
    @sclk_pin.drive @clk_format == :rl ? 0 : 1
    @half_cycle.times { tester.cycle }
    @sclk_pin.drive @clk_format == :rl ? 1 : 0
    @half_cycle.upto(@clk_multiple - 1) { tester.cycle }
  end
end

#shift(options = {}) ⇒ Object

Shift a spi packet

Overlay and capture is specified through reg.overlay and reg.store

Examples:

spi_instance.shift master_out: out_reg, master_in: in_cmp_reg
spi_instance.shift master_out: 0x7a, size: 32
spi_instance.shift master_in: in_cmp_reg


234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/origen_spi/driver.rb', line 234

def shift(options = {})
  options = {
    master_out: 0
  }.merge(options)

  validate_settings
  options = validate_options(options)
  out_reg = build_output_packet(options).bits
  in_reg = build_input_packet(options).bits

  # reverse bit order if :msb0
  if @data_order == :msb0
    out_reg = out_reg.reverse
    in_reg = in_reg.reverse
  end

  # set ss active
  @ss_pin.drive @ss_active unless @ss_pin.nil?

  # apply wait time if requested
  tester.wait @clk_wait_time unless @clk_wait_time == { time_in_us: 0 }

  # now do the shifting
  0.upto(out_reg.size - 1) do |bit|
    # park the clock
    @sclk_pin.drive @clk_format == :rl ? 0 : 1
    @miso_pin.dont_care unless @miso_pin.nil?

    # setup the bit to be driven, prep for overlay if requested
    overlay_options = {}
    unless @mosi_pin.nil?
      @mosi_pin.drive out_reg[bit].data
      if out_reg[bit].has_overlay?
        overlay_options[:pins] = @mosi_pin
        overlay_options[:overlay_str] = out_reg[bit].overlay_str
      end
    end

    # advance to clock active edge
    @half_cycle.times do |c|
      handle_miso c, in_reg[bit]
      cycle overlay_options
      overlay_options[:change_data] = false unless overlay_options == {}
    end

    # drive the clock to active
    @sclk_pin.drive @clk_format == :rl ? 1 : 0

    # advance to the end of the sclk cycle checking for appropriate miso compare placement
    @half_cycle.upto(@clk_multiple - 1) do |c|
      handle_miso c, in_reg[bit]
      cycle overlay_options
    end
  end

  # park the clock, mask miso, clear ss
  @sclk_pin.drive @clk_format == :rl ? 0 : 1
  @miso_pin.dont_care unless @miso_pin.nil?
  @mosi_pin.drive 0 unless @mosi_pin.nil?
  @ss_pin.drive @ss_active == 1 ? 0 : 1 unless @ss_pin.nil?
end

#validate_options(options) ⇒ Object

Internal method that logs errors in options passed to the shift method



347
348
349
350
351
352
353
354
355
356
357
358
359
360
# File 'lib/origen_spi/driver.rb', line 347

def validate_options(options)
  # check that size of the packet can be determined
  unless options[:size]
    options[:size] = options[:master_in].size if options[:master_in].respond_to?(:data)
  end
  unless options[:size]
    options[:size] = options[:master_out].size if options[:master_out].respond_to?(:data)
  end
  unless options[:size]
    Origen.log.error "OrigenSpi::Driver can't determine the packet size"
    exit
  end
  options
end

#validate_settingsObject

Check settings



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/origen_spi/driver.rb', line 176

def validate_settings
  unless @settings_validated
    settings_valid = true

    # check that clock and miso are provided
    unless @sclk_pin.is_a?(Origen::Pins::Pin)
      settings_valid = false
      Origen.log.error 'OrigenSpi::Driver.sclk_pin must be an Origen pin object'
    end

    unless @clk_format == :rl || @clk_format == :rh
      settings_valid = false
      Origen.log.error 'OrigenSpi::Driver.clk_format must be one of :rl, :rh'
    end

    unless @ss_active == 0 || @ss_active == 1
      settings_valid = false
      Origen.log.error 'OrigenSpi::Driver.ss_active must be either 0 or 1'
    end

    @clk_multiple = 1 if @clk_multiple < 1
    @half_cycle = @clk_multiple / 2

    @miso_compare_cycle = @clk_multiple - 1 if @miso_compare_cycle > @clk_multiple - 1

    unless @data_order == :msb0 || @data_order == :lsb0
      settings_valid = false
      Origen.log.error 'OrigenSpi::Driver.data_order must be either :msb0 or :lsb0'
    end

    @settings_validated = settings_valid
  end
end