-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathnrf51.rb
174 lines (132 loc) · 4.76 KB
/
nrf51.rb
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
require 'adiv5'
require 'armv7'
require 'register'
require 'log'
class NRF51 < ARMv7 # not actually true, it's and armv6 cortex m0 device.
def detect
@dap.IDR.to_i == 0x4770021
end
def initialize(bkend, magic_halt=false)
super(bkend)
cpuid = @dap.read(0xE000ED00)
if cpuid != 0x410CC200
raise RuntimeError, "not a Cortex M0"
end
@nvmc = NRF51::NVMC.new(@dap)
@ficr = NRF51::FICR.new(@dap)
@sector_size = @ficr.CODEPAGESIZE
@ramsize = 0
@ficr.NUMRAMBLOCK.times do |i|
@ramsize += @ficr.SIZERAMBLOCK[i]
end
@flashsize = @ficr.CODESIZE * @ficr.CODEPAGESIZE
self.probe!
end
class NVMC # Non-Volatile Memory Controller
include Peripheral
default_address 0x4001E000
# from NRF51 Reference Manual p15.
register :READY, 0x400 do
bool :ready, [0x0,0], :desc => "NVMC is ready."
end
register :CONFIG, 0x504 do # Configuration register
#A RW WEN Program memory access mode. It is strongly recommended to only activate erase and write modes when they are actively used.
enum :WEN, [0x00, 1..0], {
:REN => 0, # Read only access.
:WEN => 1, # Write Enabled.
:EEN => 2 # Erase enabled.
}
end
unsigned :ERASEPAGE, 0x508 # Register for erasing a page in code region 1
unsigned :ERASEPCR1, 0x508 # Register for erasing a page in code region 1. Equivalent to ERASEPAGE.
unsigned :ERASEPCR0, 0x510 # Register for erasing a page in code region 0
unsigned :ERASEALL, 0x50C # Register for erasing all non-volatile user memory. Write 1 to erase all.
unsigned :ERASEUICR, 0x514 # Register for erasing User Information Configuration Registers // not available unless preprogramed factory code present.
def mass_erase
self.CONFIG.WEN = :EEN # enable erase
if self.CONFIG.WEN != :EEN
raise RuntimeError, "can't set flash to erase"
end
self.ERASEALL = 1
while !self.READY.ready
Log(:nrf51, 1){ "waiting for flash erase completion" }
sleep 0.01
end
self.CONFIG.WEN = :REN # enable read
if self.CONFIG.WEN != :REN
raise RuntimeError, "can't set flash to read"
end
end
def write(addr, data)
self.CONFIG.WEN = :EEN
if addr < 0x10000000
# We only erase flash pages proper
if self.CONFIG.WEN != :EEN
raise RuntimeError, "can't set flash to erase"
end
self.ERASEPAGE = addr
while !self.READY.ready
Log(:nrf51, 1){ "waiting for flash erase completion" }
sleep 0.01
end
end
self.CONFIG.WEN = :WEN
if self.CONFIG.WEN != :WEN
raise RuntimeError, "can't set flash to write"
end
@backing.write(addr, data)
while !self.READY.ready
Log(:nrf51, 1){ "waiting for flash write completion" }
sleep 0.01
end
self.CONFIG.WEN = :REN
if self.CONFIG.WEN != :REN
raise RuntimeError, "can't set flash to read"
end
end
end
class FICR # Factory Information Configuration Registers
include Peripheral
# from NRF51 Reference Manual p18.
default_address 0x10000000
unsigned :CODEPAGESIZE, 0x010, :desc => "Code memory page size"
unsigned :CODESIZE, 0x014, :desc => "Code memory size"
unsigned :CLENR0, 0x028, :desc => "Length of code region 0 in bytes"
unsigned :PPFC, 0x02C, :desc => "Pre-programmed factory code present"
unsigned :NUMRAMBLOCK, 0x034, :desc => "Number of individually controllable RAM blocks"
unsigned :SIZERAMBLOCK, 0x038, :vector => 4, :desc => "Size of RAM block n in bytes"
end
#0x10001000 UICR UICR User Information Configuration Registers
def mass_erase
@nvmc.mass_erase
end
def program_sector(addr, data)
if String === data
data = (data + "\0"*3).unpack('L*')
end
if data.size != @sector_size / 4 || (addr & (@sector_size - 1) != 0)
raise RuntimeError, "invalid data size or alignment"
end
Log(:nrf51, 2){ "flashing addr %08x, size %#x" % [addr, data.size*4] }
@nvmc.write(addr, data)
end
def program_section(addr, data)
super(addr, data, @sector_size)
end
def mmap_ranges
Log(:nrf51, 1){ "#{@ficr.NUMRAMBLOCK} ram blocks, ramsize #{@ramsize}, flashsize #{@flashsize}" }
super +
[
{:type => :flash, :start => 0, :length => @flashsize, :blocksize => @sector_size},
{:type => :flash, :start => 0x10001000, :length => 0x100, :blocksize => 0x100},
{:type => :ram, :start => 0x20000000, :length => @ramsize}
]
end
end
if $0 == __FILE__
require 'backend-driver'
bkend = BackendDriver.from_string(ARGV[0])
k = NRF51.new(bkend)
#r = k.program_sector(0x00014000, "\xa5"*1024)
puts Log.hexary(k.read_mem(0x000000, 1024).unpack('L*'))
end