mirror of
https://github.com/MikronMIK32/mik32-uploader.git
synced 2026-01-01 13:37:03 +03:00
Прототип загрузки программы в spifi через драйвер
This commit is contained in:
parent
8e056e25a4
commit
5f1d57016b
11
.gitignore
vendored
11
.gitignore
vendored
@ -1,8 +1,15 @@
|
||||
__pycache__
|
||||
.vscode
|
||||
openocd
|
||||
*.hex
|
||||
*.code-workspace
|
||||
dist
|
||||
build
|
||||
mik32_upload.spec
|
||||
/upload_drivers/jtag_spifi/.pio/build/mik32v2/hal_core
|
||||
/upload_drivers/jtag_spifi/.pio/build/mik32v2/hal_peripherals
|
||||
/upload_drivers/jtag_spifi/.pio/build/mik32v2/hal_utilities
|
||||
*.a
|
||||
*.o
|
||||
*.checksum
|
||||
*.dblite
|
||||
*.elf
|
||||
*.map
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import datetime
|
||||
from enum import Enum
|
||||
import os
|
||||
import pathlib
|
||||
@ -209,23 +210,7 @@ def get_segments_list(pages_offsets: List[int], segment_size: int) -> List[int]:
|
||||
return list(segments)
|
||||
|
||||
|
||||
def check_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, use_quad_spi=False, use_chip_erase=False):
|
||||
result = 0
|
||||
|
||||
openocd.halt()
|
||||
init(openocd)
|
||||
|
||||
# Сбрасываем микросхему в режиме QPI из всех состояний в нормальный SPI режим.
|
||||
generic_flash.chip_reset_qpi(openocd)
|
||||
|
||||
# Сбрасываем микросхему в режиме SPI из всех состояний в нормальный SPI режим.
|
||||
generic_flash.chip_reset(openocd)
|
||||
|
||||
JEDEC_ID = send_command(openocd, generic_flash.JEDEC_ID_COMMAND,
|
||||
Frameform.OPCODE_NOADDR, Fieldform.ALL_SERIAL, 3)
|
||||
|
||||
print(f"JEDEC ID = {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}")
|
||||
|
||||
def dma_config(openocd: OpenOcdTclRpc) -> dma.DMA:
|
||||
dma_instance = dma.DMA(openocd)
|
||||
dma_instance.init()
|
||||
|
||||
@ -267,6 +252,28 @@ def check_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, use_quad_sp
|
||||
dma_instance.channels[1].read_request = dma.ChannelRequest.SPIFI_REQUEST
|
||||
dma_instance.channels[1].read_ack = dma.ChannelAck.DISABLE
|
||||
|
||||
return dma_instance
|
||||
|
||||
|
||||
def check_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, use_quad_spi=False, use_chip_erase=False):
|
||||
result = 0
|
||||
|
||||
openocd.halt()
|
||||
init(openocd)
|
||||
|
||||
# Сбрасываем микросхему в режиме QPI из всех состояний в нормальный SPI режим.
|
||||
generic_flash.chip_reset_qpi(openocd)
|
||||
|
||||
# Сбрасываем микросхему в режиме SPI из всех состояний в нормальный SPI режим.
|
||||
generic_flash.chip_reset(openocd)
|
||||
|
||||
JEDEC_ID = send_command(openocd, generic_flash.JEDEC_ID_COMMAND,
|
||||
Frameform.OPCODE_NOADDR, Fieldform.ALL_SERIAL, 3)
|
||||
|
||||
print(f"JEDEC ID = {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}")
|
||||
|
||||
dma_instance = dma_config(openocd)
|
||||
|
||||
if (use_quad_spi):
|
||||
print("Using Quad SPI")
|
||||
generic_flash.quad_enable(openocd)
|
||||
@ -321,46 +328,7 @@ def write_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, use_quad_sp
|
||||
|
||||
print(f"JEDEC ID = {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}")
|
||||
|
||||
dma_instance = dma.DMA(openocd)
|
||||
dma_instance.init()
|
||||
|
||||
dma_instance.channels[0].write_buffer = 0
|
||||
|
||||
dma_instance.channels[0].channel = dma.ChannelIndex.CHANNEL_0
|
||||
dma_instance.channels[0].priority = dma.ChannelPriority.VERY_HIGH
|
||||
|
||||
dma_instance.channels[0].read_mode = dma.ChannelMode.MEMORY
|
||||
dma_instance.channels[0].read_increment = dma.ChannelIncrement.ENABLE
|
||||
dma_instance.channels[0].read_size = dma.ChannelSize.WORD
|
||||
dma_instance.channels[0].read_burst_size = 2
|
||||
dma_instance.channels[0].read_request = dma.ChannelRequest.SPIFI_REQUEST
|
||||
dma_instance.channels[0].read_ack = dma.ChannelAck.DISABLE
|
||||
|
||||
dma_instance.channels[0].write_mode = dma.ChannelMode.PERIPHERY
|
||||
dma_instance.channels[0].write_increment = dma.ChannelIncrement.DISABLE
|
||||
dma_instance.channels[0].write_size = dma.ChannelSize.WORD
|
||||
dma_instance.channels[0].write_burst_size = 2
|
||||
dma_instance.channels[0].write_request = dma.ChannelRequest.SPIFI_REQUEST
|
||||
dma_instance.channels[0].write_ack = dma.ChannelAck.DISABLE
|
||||
|
||||
dma_instance.channels[1].write_buffer = 0
|
||||
|
||||
dma_instance.channels[1].channel = dma.ChannelIndex.CHANNEL_1
|
||||
dma_instance.channels[1].priority = dma.ChannelPriority.VERY_HIGH
|
||||
|
||||
dma_instance.channels[1].write_mode = dma.ChannelMode.MEMORY
|
||||
dma_instance.channels[1].write_increment = dma.ChannelIncrement.ENABLE
|
||||
dma_instance.channels[1].write_size = dma.ChannelSize.WORD
|
||||
dma_instance.channels[1].write_burst_size = 2
|
||||
dma_instance.channels[1].write_request = dma.ChannelRequest.SPIFI_REQUEST
|
||||
dma_instance.channels[1].write_ack = dma.ChannelAck.DISABLE
|
||||
|
||||
dma_instance.channels[1].read_mode = dma.ChannelMode.PERIPHERY
|
||||
dma_instance.channels[1].read_increment = dma.ChannelIncrement.DISABLE
|
||||
dma_instance.channels[1].read_size = dma.ChannelSize.WORD
|
||||
dma_instance.channels[1].read_burst_size = 2
|
||||
dma_instance.channels[1].read_request = dma.ChannelRequest.SPIFI_REQUEST
|
||||
dma_instance.channels[1].read_ack = dma.ChannelAck.DISABLE
|
||||
dma_instance = dma_config(openocd)
|
||||
|
||||
if use_chip_erase:
|
||||
generic_flash.erase(openocd, generic_flash.EraseType.CHIP_ERASE)
|
||||
@ -440,99 +408,115 @@ def write_pages_by_sectors(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc,
|
||||
|
||||
openocd.halt()
|
||||
init(openocd)
|
||||
# openocd.run("rwp")
|
||||
|
||||
JEDEC_ID = send_command(
|
||||
openocd, 0x9F, Frameform.OPCODE_NOADDR, Fieldform.ALL_SERIAL, 3)
|
||||
print(f"JEDEC_ID {JEDEC_ID[0]:02x} {JEDEC_ID[1]:02x} {JEDEC_ID[2]:02x}")
|
||||
|
||||
dma_instance = dma_config(openocd)
|
||||
|
||||
sectors_list = get_segments_list(list(pages), 4*1024)
|
||||
|
||||
openocd.halt()
|
||||
pathname = os.path.dirname(sys.argv[0])
|
||||
|
||||
# openocd.run("load_image {%s}" % pathlib.Path(os.path.join(pathname, "firmware.hex")))
|
||||
openocd.run("rbp all")
|
||||
openocd.run("load_image {%s}" % pathlib.Path(
|
||||
"C:\\Users\\user\\Documents\\PlatformIO\\Projects\\SPIFI_JTAG_driver\\.pio\\build\\mik32v2\\firmware.hex"))
|
||||
openocd.run("bp 0x02002010 1 hw")
|
||||
openocd.resume(0x02000000)
|
||||
if wait_halted(openocd) != 0:
|
||||
return 1
|
||||
"C:\\Users\\user\\.platformio\\packages\\tool-mik32-uploader\\upload_drivers\\jtag_spifi\\.pio\\build\\mik32v2\\firmware.hex"
|
||||
))
|
||||
|
||||
openocd.run("wp 0x2003000 4 w")
|
||||
openocd.resume(0x2000000)
|
||||
wait_halted(openocd)
|
||||
openocd.halt()
|
||||
|
||||
# spifi erase
|
||||
for sector in sectors_list:
|
||||
print(f"Erase sector {sector}", flush=True)
|
||||
openocd.write_word(0x02002000, 0b0010 | (sector << 8))
|
||||
openocd.resume()
|
||||
if wait_halted(openocd) != 0:
|
||||
return 1
|
||||
print(
|
||||
f"Erase sector {sector} result {openocd.read_word(0x02002008)}", flush=True)
|
||||
|
||||
return 1
|
||||
#
|
||||
# for sector in sectors_list:
|
||||
# print(f"Erase sector {sector}", flush=True)
|
||||
# openocd.write_word(0x02002000, 0b0010 | (sector << 8))
|
||||
# openocd.resume()
|
||||
# if wait_halted(openocd) != 0:
|
||||
# return 1
|
||||
# print(
|
||||
# f"Erase sector {sector} result {openocd.read_word(0x02002008)}", flush=True)
|
||||
|
||||
# spifi erase check
|
||||
for sector in sectors_list:
|
||||
# print(f"Erase sector {sector}", flush=True)
|
||||
# openocd.write_word(0x02002000, 0b0010 | sector)
|
||||
# openocd.resume()
|
||||
# if wait_halted(openocd) != 0:
|
||||
# return 1
|
||||
# print(f"Erase sector {sector} result {openocd.read_word(0x02002008)}", flush=True)
|
||||
#
|
||||
# for sector in sectors_list:
|
||||
# # print(f"Erase sector {sector}", flush=True)
|
||||
# # openocd.write_word(0x02002000, 0b0010 | sector)
|
||||
# # openocd.resume()
|
||||
# # if wait_halted(openocd) != 0:
|
||||
# # return 1
|
||||
# # print(f"Erase sector {sector} result {openocd.read_word(0x02002008)}", flush=True)
|
||||
|
||||
page_bytes = [0xff] * 256
|
||||
# page_bytes = [0xff] * 256
|
||||
|
||||
result = spifi_read_data(openocd, sector, 256, page_bytes)
|
||||
# result = spifi_read_data(openocd, sector, 256, page_bytes)
|
||||
|
||||
if result == 1:
|
||||
print("Data error")
|
||||
return result
|
||||
# if result == 1:
|
||||
# print("Data error")
|
||||
# return result
|
||||
|
||||
for sector in sectors_list:
|
||||
print(f"Program sector {sector}", flush=True)
|
||||
bytes_list: List[int] = []
|
||||
for page in range(16):
|
||||
page = pages.get(page * 256 + sector * 4096)
|
||||
page = pages.get(page * 256 + sector)
|
||||
if page is not None:
|
||||
bytes_list.extend(page)
|
||||
else:
|
||||
bytes_list.extend([0]*256)
|
||||
|
||||
extend_value = 1 + sector
|
||||
bytes_list.extend([(extend_value >> 0) & 0xFF, (extend_value >> 8)
|
||||
& 0xFF, (extend_value >> 16) & 0xFF, (extend_value >> 24) & 0xFF])
|
||||
# extend_value = 1 + sector
|
||||
# bytes_list.extend([(extend_value >> 0) & 0xFF, (extend_value >> 8)
|
||||
# & 0xFF, (extend_value >> 16) & 0xFF, (extend_value >> 24) & 0xFF])
|
||||
# print(bytes_list)
|
||||
|
||||
while (openocd.read_word(0x0200200c) != 1):
|
||||
openocd.resume()
|
||||
openocd.halt()
|
||||
openocd.write_memory(0x02002000, 8, bytes_list)
|
||||
openocd.run(f"set_reg {{t6 {sector}}}")
|
||||
|
||||
openocd.resume()
|
||||
wait_halted(openocd)
|
||||
# openocd.halt()
|
||||
print(f"Check page result {openocd.read_memory(0x2003000, 32, 1)}")
|
||||
|
||||
print(f"{datetime.datetime.now().time()} Program sector {sector} complete", flush=True)
|
||||
|
||||
|
||||
|
||||
# result = generic_flash.read_data(openocd, sector, 4096, bytes_list)
|
||||
|
||||
# for page in range(16):
|
||||
# page_bytes = pages.get(page * 256 + sector)
|
||||
# if page_bytes is not None:
|
||||
# result = generic_flash.read_data(
|
||||
# openocd, page * 256 + sector, 256, page_bytes, dma=dma_instance)
|
||||
|
||||
# if result == 1:
|
||||
# print("Data error")
|
||||
# return result
|
||||
|
||||
openocd.write_memory(0x02001000, 8, bytes_list)
|
||||
while (openocd.read_word(0x0200200c) != 1):
|
||||
openocd.resume()
|
||||
openocd.halt()
|
||||
time.sleep(0.5)
|
||||
openocd.halt()
|
||||
print(
|
||||
f"Program sector {sector} result {openocd.read_word(0x02002008)}", flush=True)
|
||||
|
||||
init_memory(openocd)
|
||||
|
||||
# check write
|
||||
pages_offsets = list(pages)
|
||||
for index, page_offset in enumerate(pages_offsets):
|
||||
page_bytes = pages[page_offset]
|
||||
#
|
||||
# pages_offsets = list(pages)
|
||||
# for index, page_offset in enumerate(pages_offsets):
|
||||
# page_bytes = pages[page_offset]
|
||||
|
||||
memory_bytes = openocd.read_memory(page_offset + 0x80000000, 8, 256)
|
||||
print(page_offset, memory_bytes)
|
||||
# memory_bytes = openocd.read_memory(page_offset + 0x80000000, 8, 256)
|
||||
# print(page_offset, memory_bytes)
|
||||
|
||||
for i, byte in enumerate(memory_bytes):
|
||||
if byte != page_bytes[i]:
|
||||
print("Data error!")
|
||||
openocd.run("rbp 0x02002010")
|
||||
return result
|
||||
# for i, byte in enumerate(memory_bytes):
|
||||
# if byte != page_bytes[i]:
|
||||
# print("Data error!")
|
||||
# openocd.run("rbp 0x02002010")
|
||||
# return result
|
||||
|
||||
openocd.run("rbp 0x02002010")
|
||||
if result == 0:
|
||||
# Прошивка страниц флеш памяти по SPIFI была завершена
|
||||
print("Flashing of flash memory pages via SPIFI has been completed", flush=True)
|
||||
|
||||
@ -263,7 +263,7 @@ def upload_file(
|
||||
gpio_init(openocd, mik_version)
|
||||
start_time = time.perf_counter()
|
||||
|
||||
result |= spifi.write_pages(
|
||||
result |= spifi.write_pages_by_sectors(
|
||||
pages.pages_spifi, openocd, use_quad_spi=use_quad_spi)
|
||||
|
||||
write_time = time.perf_counter() - start_time
|
||||
|
||||
1
upload_drivers/jtag_spifi/.gitignore
vendored
Normal file
1
upload_drivers/jtag_spifi/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
.vscode
|
||||
238
upload_drivers/jtag_spifi/.pio/build/mik32v2/firmware.hex
Normal file
238
upload_drivers/jtag_spifi/.pio/build/mik32v2/firmware.hex
Normal file
@ -0,0 +1,238 @@
|
||||
:020000040200F8
|
||||
:10000000FD62938202400100FD12E39E02FE374131
|
||||
:10001000000213010100B7110002938101EBB71533
|
||||
:100020000002938505EB37160002130606EBB716A0
|
||||
:100030000002938606EB39A083A2050023A0560098
|
||||
:1000400091059106E3EAC5FEB7150002938505EB1D
|
||||
:1000500037160002130606EBB7160002938606EB6E
|
||||
:1000600039A083A2050023A0560091059106E3EA7A
|
||||
:10007000C5FEB7150002938505EB3716000213067F
|
||||
:1000800006EB21A023A005009105E3EDC5FEB70016
|
||||
:100090000002E780C00AB7000002E780C00AB7008C
|
||||
:1000A0000002E780002373005010F5BF828000003B
|
||||
:1000B0000000000000000000000000000000000040
|
||||
:1000C0006F004000197106C20AC40EC612C816CAD3
|
||||
:1000D0001ACC1ECE22D026D22AD42ED632D836DA48
|
||||
:1000E0003ADC3EDEC2C0C6C2CAC4CEC6D2C8D6CA78
|
||||
:1000F000DACCDECEE2D0E6D2EAD4EED6F2D8F6DA28
|
||||
:10010000FADCFEDE970000009380E00482909240CB
|
||||
:100110002241B2414242D2426243F24302549254DB
|
||||
:100120002255B2554256D2566257F2570648964863
|
||||
:100130002649B649464AD64A664BF64B065C965C5B
|
||||
:10014000265DB65D465ED65E665FF65F096173004A
|
||||
:10015000203001A03D432A876373C3029377F700E1
|
||||
:10016000BDEFADE5937606FF3D8ABA960CC34CC34E
|
||||
:100170000CC74CC74107E36BD7FE11E28280B30680
|
||||
:10018000C3408A069702000096966780A600230760
|
||||
:10019000B700A306B7002306B700A305B7002305E1
|
||||
:1001A000B700A304B7002304B700A303B7002303D9
|
||||
:1001B000B700A302B7002302B700A301B7002301D1
|
||||
:1001C000B700A300B7002300B700828093F5F50FB6
|
||||
:1001D00093968500D58D93960501D58D61B793963D
|
||||
:1001E00027009702000096968682E78086FA96801E
|
||||
:1001F000C1171D8F3E96E374C3F8A5B75D71130652
|
||||
:1002000080028145280886C6B137BD47230CF1001E
|
||||
:100210008947230EF1003ED2E177938707082C0827
|
||||
:100220000A85231AF102EF000079B64061618280ED
|
||||
:10023000757106C74AC1CEDED2DCD6DADAD8DED690
|
||||
:1002400022C526C3653F85653715080001478146ED
|
||||
:100250002146938555D013050540A122371500028C
|
||||
:10026000130585E5AD291306400281456818DD3583
|
||||
:10027000B707070028183EDCEF0090003715000292
|
||||
:10028000130585E6A9292818EF00F012371500029A
|
||||
:100290001305C5E7A921B729000237150002938588
|
||||
:1002A0000900130545E92529B737000223A00700F7
|
||||
:1002B00013890700056AB71A0002370B0080916B9B
|
||||
:1002C0002818EF00500FE256E1679387176AFD1771
|
||||
:1002D00081C7D84E418B65FFFE852818EF00B01707
|
||||
:1002E000814413840900B3069400B3859F0013066C
|
||||
:1002F0000010281893840410EF003011E39344FF9A
|
||||
:10030000514693854AE44800EF003019E2575146C0
|
||||
:100310004C0048103ECC02CE02D0EF001018280846
|
||||
:10032000EF00407AB307FB01944333077401814720
|
||||
:1003300010406303D6008D474104E31BE4FE2320F5
|
||||
:10034000F900BDBF0111B717080006CE02C402C6EE
|
||||
:10035000938707406312F502B70705000947D8CF16
|
||||
:10036000930700063EC085473EC28A853745080090
|
||||
:100370007126F24005618280B727080093870780C5
|
||||
:10038000E319F5FEB70705001147D8CF93070030F2
|
||||
:100390003EC03745080085473EC28A8513050540A3
|
||||
:1003A000C1BF011122CC26CA4AC84EC652C42A84F3
|
||||
:1003B00006CE2E89B284368ABA896937BD4701458F
|
||||
:1003C00063FE27032320040023262401FD575CCC71
|
||||
:1003D0002322440193E714002324340113F744003B
|
||||
:1003E0001CC0A1885C4C054501C713D56701058970
|
||||
:1003F00091CC6DD99396A700E3D606FEF2406244F5
|
||||
:10040000D2444249B249224A0561828061DDFDB78A
|
||||
:10041000484D198105898280411122C406C62A846B
|
||||
:100420002285FD3775DDB240224441018280931759
|
||||
:10043000050137150800C183130505401CD5E9BF28
|
||||
:10044000411122C406C62A840305040009E5B2400E
|
||||
:100450002244410182800504D93FFDB75971D6CAB3
|
||||
:10046000DAC8DEC6E2C4E6C2EAC086D6A2D4A6D204
|
||||
:10047000CAD0CECED2CC6EDEAA872E8D930A0003D0
|
||||
:10048000130BA002930BC004130C0002A94C0385AC
|
||||
:100490000700630705221307500213891700631131
|
||||
:1004A000E5080385170063105509038527001389A4
|
||||
:1004B000370085446316650B03240D0093074D0038
|
||||
:1004C00063550400330480408944030509003E8DD0
|
||||
:1004D00005099377F5FD639777010305090093E418
|
||||
:1004E00044000509630E051C13070006AA8763561E
|
||||
:1004F000A700930705FEE207E1871307F00463886E
|
||||
:10050000E70C6342F70613073004638CE70A13070E
|
||||
:1005100040046381E70E130720048946638AE70AD3
|
||||
:100520003937EA8951A01307D0026306E500138921
|
||||
:100530002700814441B70385270013893700894488
|
||||
:1005400095BF3304940305092A940305F9FF1304A6
|
||||
:1005500004FD930705FD93F7F70FE374F7FE95BFCE
|
||||
:1005600001442547FDB7130750056385E7081307C6
|
||||
:1005700080056383E70813073005E393E7FA832DCB
|
||||
:100580000D0093094D0013FA24006E85EF0050050D
|
||||
:100590002A8D93041D0063150A00636A8D00268D61
|
||||
:1005A0006E85793D636A8D004E8DCA87CDB5130582
|
||||
:1005B0000002B53D268DF1BF130500028D3D050DEE
|
||||
:1005C000D5B703050D0093094D009535F1BFA14640
|
||||
:1005D00013F7440093094D0015C313064004032785
|
||||
:1005E0000D006396C702635407023307E04093E4AB
|
||||
:1005F000040131A8A946E9BFC146D9BF1307400489
|
||||
:100600006395E70003270D00F9BF03270D001305CD
|
||||
:1006100085F89D4719E193077002100893F5F70FCD
|
||||
:10062000328D8147A5483378D7023A833385050157
|
||||
:100630003357D70263E50801131588016185130557
|
||||
:1006400005032300A600938D17006366D3000506FB
|
||||
:10065000639F8D05FD4713F7040101CF13870D023A
|
||||
:100660001408B30DD7001307D0022380EDFE938D3D
|
||||
:10067000270093F714001305000299C31305000324
|
||||
:100680006E8A898813071A0081E463648A023A8AB1
|
||||
:10069000FD1D3307BD0103050700513BE39A0DFE25
|
||||
:1006A000E3748AF0130500025933050AD5BFEE87BB
|
||||
:1006B0009DBF3AC62AC4A53B324722453A8AD9B7DC
|
||||
:1006C000B650265496540659F649664AD64A464BC1
|
||||
:1006D000B64B264C964C064DF25D656182803971B1
|
||||
:1006E0002ED24C1006CE32D436D63AD83EDA42DC80
|
||||
:1006F00046DE2EC6A533F24021618280B74708004E
|
||||
:10070000938707402A886303F508B7570800938743
|
||||
:1007100007806303F50A37470800630CE50A0545BF
|
||||
:100720008280331E1F013376DE0139C2C041884307
|
||||
:1007300013931800339662001346F6FF9374340047
|
||||
:10074000718DB3946400458D88C3630B740205CC2E
|
||||
:10075000084303AEC500718D331E6E003365C501BD
|
||||
:1007600008C38842698E884533156500498E90C25A
|
||||
:10077000850833D51E0155F53244A24441018280DB
|
||||
:100780002326C801F1B72324C801D9B7B71605003D
|
||||
:1007900037170500B7170500938646C1130707C131
|
||||
:1007A0009387C7C083AE05008148054F8D429143B2
|
||||
:1007B00033D51E0105ED8280B716050037170500F9
|
||||
:1007C000B7170500938606C21307C7C1938787C171
|
||||
:1007D000D1BFB716050037170500B7170500938678
|
||||
:1007E00086C0130747C0938707C06DBF331E1F0124
|
||||
:1007F0003376DE0119E2850865BF411122C626C4A1
|
||||
:1008000035B70547AA876305E50209476300E50692
|
||||
:10081000054591EBB7060600DC4A7D771307F73FE5
|
||||
:10082000F98FDCCA014582807D1719EB0D45828066
|
||||
:100830009306004037A7070013070712B705050006
|
||||
:10084000905D7D8E75D2370606005C4A7D77130772
|
||||
:10085000F73FF98FD58F41115CCA02C613073006E6
|
||||
:10086000B2476359F700014541018280856693864E
|
||||
:100870000680C9B7B24785073EC6DDB79147630713
|
||||
:10088000F50263EAA7008547630AF504894763090F
|
||||
:10089000F50405458280A147E31DF5FE094709459A
|
||||
:1008A00001A8FD1781EFC8D20D45828005470D458F
|
||||
:1008B000B7A7070093870712B7060500905E798EE9
|
||||
:1008C0006DD28A05C98D4111CCD202C613073006FC
|
||||
:1008D000B247635AF7000145410182801147C9BF01
|
||||
:1008E00021470145F1B7B24785073EC6D5B7054751
|
||||
:1008F000AA876305E50209476302E506054591EB12
|
||||
:10090000B70606009C4A7D771307F73FF98F9CCA0C
|
||||
:10091000014582807D1719EB0D45828093060040CA
|
||||
:1009200037A7070013070712B7050500905D7D8EF6
|
||||
:1009300075D2370706001C4B7D761306F63FF18F04
|
||||
:10094000D58F1CCB85471CCF411102C6130730063B
|
||||
:10095000B2476359F700014541018280856693865D
|
||||
:1009600006807DBFB24785073EC6DDB711C9854702
|
||||
:10097000630DF50205458280FD1791EB0D458280E0
|
||||
:100980000946B7A7070093870712B7060500985EC8
|
||||
:10099000718F7DD34111C8D602C613073006B24706
|
||||
:1009A0006357F7000145410182800546D9BFB24730
|
||||
:1009B00085073EC6EDB7011126CAB7040600DC481C
|
||||
:1009C00006CE22CC4AC84EC652C456C2F19BDCC8E1
|
||||
:1009D0009C482A89C845F19B9CC883C7C5012E84C1
|
||||
:1009E0008A07DCC883C7D5018A079CC8193D0C4417
|
||||
:1009F000AA8A0345440059351848B70705002A8AD2
|
||||
:100A000098C358480850D8C3184C98C7CD35AA8900
|
||||
:100A10004850A93F834704002A8793F6170089E6C8
|
||||
:100A2000D44893E62600D4C893F6270099E6370603
|
||||
:100A30000600544A93E6160054CA93F6470099E616
|
||||
:100A400037060600144A93E6260014CAA18B99E7DC
|
||||
:100A5000B70606009C4A93E717009CCAF24062441E
|
||||
:100A60002320590123224901232439012326E900A7
|
||||
:100A7000D244B249224A924A4A854249056182805B
|
||||
:100A8000011106CE22CC02C402C62147B7070500D9
|
||||
:100A900037550800D8C705448D478A85130505805A
|
||||
:100AA0003EC022C2A139375508009307C0038A858A
|
||||
:100AB0001305058022C222C43EC08931F24062443F
|
||||
:100AC00005618280411122C406C62A84553F184020
|
||||
:100AD0005C4F93E707015CCF1C441CCB5C4085CB8B
|
||||
:100AE0001C43B7061000D58F1CC3144C5C48B240A1
|
||||
:100AF000D606CE07D58F83460401C206D58F83461E
|
||||
:100B0000C4012244E206D58F1CCF410182801C43E0
|
||||
:100B1000B706F0FFFD16F58FC1BF032305002A8E2F
|
||||
:100B20000325C30113650502232EA3002324C3005C
|
||||
:100B30001396260149824D8E232603012322C300EA
|
||||
:100B4000139605016354060299C20545B1CB0147CE
|
||||
:100B50006346D700639C08020D4582803386E70018
|
||||
:100B6000034606000507230AC300DDB799C2054501
|
||||
:100B700005CB8147E3D0D7FE03260E00034546018F
|
||||
:100B80003306F70085072300A600EDB783270E0084
|
||||
:100B9000FD18DC4F93F70702D5DF11656D8D11E16C
|
||||
:100BA0008280B707070083C7470113F585001D8DB5
|
||||
:100BB0003335A00082801C414147D8CF8280E16854
|
||||
:100BC0009388086A01488147014781460146B70575
|
||||
:100BD0002006A1B7011106CEA30701008947639340
|
||||
:100BE000F502B7052035E1681307F1009388086A1C
|
||||
:100BF00001488147854601460D37F2400345F10023
|
||||
:100C000005618280B7052005F9BF011106CE22CC0F
|
||||
:100C100026CA2E844AC8AA84328936C64D37B247BE
|
||||
:100C2000E16822869388086A01480147CA86B78529
|
||||
:100C3000800226856164D5351304146A7D1411C4BD
|
||||
:100C400085452685413F058975F9F2406244D244C5
|
||||
:100C5000424905618280011106CE22CC26CA2EC6E9
|
||||
:100C6000AA84B13F3246E1689388086A0148814707
|
||||
:100C700001478146B705802026856164793D1304CC
|
||||
:100C8000146A7D1411C485452685A937058975F92F
|
||||
:100C9000F2406244D24405618280B3C7A5008D8BC7
|
||||
:100CA000B308C500B1E78D4763F4C70493773500F7
|
||||
:100CB0002A87B9EB13F6C8FFB306E6409307000294
|
||||
:100CC00063C8D706AE86BA876371C70203A8060059
|
||||
:100CD0009107910623AE07FFE3EAC7FE9307F6FFED
|
||||
:100CE000998FF19B91073E97BE95636617018280AD
|
||||
:100CF0002A87637E150383C7050005078505A30FB3
|
||||
:100D0000F7FEE39AE8FE828083C605000507937725
|
||||
:100D10003700A30FD7FE8505D1DF83C60500050781
|
||||
:100D200093773700A30FD7FE8505F9FF61B782805F
|
||||
:100D3000411122C61304000283A3050083A24500CB
|
||||
:100D400083AF850003AFC50083AE050103AE450147
|
||||
:100D500003A3850103A8C501945113074702B307F4
|
||||
:100D6000E640232E77FC232057FE2322F7FF23247F
|
||||
:100D7000E7FF2326D7FF2328C7FF232A67FE232C5C
|
||||
:100D800007FF232ED7FE93854502E347F4FAAE868C
|
||||
:100D9000BA876371C70203A806009107910623AEC4
|
||||
:100DA00007FFE3EAC7FE9307F6FF998FF19B9107D0
|
||||
:100DB0003E97BE956365170132444101828083C727
|
||||
:100DC000050005078505A30FF7FEE387E8FE83C747
|
||||
:100DD000050005078505A30FF7FEE392E8FEE9BFCE
|
||||
:100DE000937735002A879DEFB7867F7F9386F6F746
|
||||
:100DF000FD5510431107B377D600B697D18FD58F25
|
||||
:100E0000E389B7FE8346C7FFB307A7408DCA834671
|
||||
:100E1000D7FF9DC20345E7FF3335A0003E95791506
|
||||
:100E20008280F9D283470700050793763700F5FBE8
|
||||
:100E3000098F1305F7FF82801385D7FF8280138502
|
||||
:100E4000C7FF8280000000000000000000000000DA
|
||||
:100E50000400000003000000535441525420445247
|
||||
:100E6000495645520A0000006D737020696E69741E
|
||||
:100E700020636F6D706C6574650A0000737069663D
|
||||
:100E80006920726573657420636F6D706C6574653D
|
||||
:100E90000A000000425546464552344B203D203062
|
||||
:100EA00078253038780A00000000000000000000BB
|
||||
:0400000502000000F5
|
||||
:00000001FF
|
||||
39
upload_drivers/jtag_spifi/include/README
Normal file
39
upload_drivers/jtag_spifi/include/README
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||
46
upload_drivers/jtag_spifi/lib/README
Normal file
46
upload_drivers/jtag_spifi/lib/README
Normal file
@ -0,0 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||
16
upload_drivers/jtag_spifi/platformio.ini
Normal file
16
upload_drivers/jtag_spifi/platformio.ini
Normal file
@ -0,0 +1,16 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:mik32v2]
|
||||
platform = MIK32
|
||||
board = mik32v2
|
||||
framework = framework-mik32v2-sdk
|
||||
board_debug.ldscript = ram
|
||||
build_flags = -ffixed-x31 -D MIK32V2
|
||||
19
upload_drivers/jtag_spifi/ram.ld
Normal file
19
upload_drivers/jtag_spifi/ram.ld
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv")
|
||||
OUTPUT_ARCH(riscv)
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
|
||||
MEMORY {
|
||||
ram (RWX): ORIGIN = 0x02000000, LENGTH = 16K
|
||||
}
|
||||
|
||||
STACK_SIZE = 1024;
|
||||
|
||||
CL_SIZE = 16;
|
||||
|
||||
REGION_ALIAS("REGION_TEXT", ram);
|
||||
REGION_ALIAS("REGION_RAM", ram);
|
||||
|
||||
INCLUDE sections.lds
|
||||
105
upload_drivers/jtag_spifi/sections.lds
Normal file
105
upload_drivers/jtag_spifi/sections.lds
Normal file
@ -0,0 +1,105 @@
|
||||
|
||||
SECTIONS {
|
||||
.text ORIGIN(REGION_TEXT) : {
|
||||
PROVIDE(__TEXT_START__ = .);
|
||||
*crt0.o(.text .text.*)
|
||||
*(.text.smallsysteminit)
|
||||
*(.text.SmallSystemInit)
|
||||
. = ORIGIN(REGION_TEXT) + 0xC0;
|
||||
KEEP(*crt0.o(.trap_text))
|
||||
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
. = ALIGN(CL_SIZE);
|
||||
PROVIDE(__TEXT_END__ = .);
|
||||
} >REGION_TEXT
|
||||
|
||||
.data :
|
||||
AT( __TEXT_END__ ) {
|
||||
PROVIDE(__DATA_START__ = .);
|
||||
_gp = .;
|
||||
*(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata*)
|
||||
*(.sdata .sdata.* .gnu.linkonce.s.*)
|
||||
*(.data .data.*)
|
||||
. = ALIGN(CL_SIZE);
|
||||
PROVIDE(__DATA_END__ = .);
|
||||
} >REGION_RAM
|
||||
|
||||
__DATA_IMAGE_START__ = LOADADDR(.data);
|
||||
__DATA_IMAGE_END__ = LOADADDR(.data) + SIZEOF(.data);
|
||||
|
||||
/* thread-local data segment */
|
||||
.tdata : {
|
||||
PROVIDE(_tls_data = .);
|
||||
PROVIDE(_tdata_begin = .);
|
||||
*(.tdata .tdata.*)
|
||||
PROVIDE(_tdata_end = .);
|
||||
. = ALIGN(CL_SIZE);
|
||||
} >REGION_RAM
|
||||
|
||||
.tbss : {
|
||||
PROVIDE(__BSS_START__ = .);
|
||||
*(.tbss .tbss.*)
|
||||
. = ALIGN(CL_SIZE);
|
||||
PROVIDE(_tbss_end = .);
|
||||
} >REGION_RAM
|
||||
|
||||
/* bss segment */
|
||||
.sbss : {
|
||||
*(.sbss .sbss.* .gnu.linkonce.sb.*)
|
||||
*(.scommon)
|
||||
} >REGION_RAM
|
||||
|
||||
.bss : {
|
||||
*(.bss .bss.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(CL_SIZE);
|
||||
PROVIDE(__BSS_END__ = .);
|
||||
} >REGION_RAM
|
||||
|
||||
/* Code intended to be copied to REGION_RAM before execution */
|
||||
.ram_text :
|
||||
AT( ALIGN(__DATA_IMAGE_END__, CL_SIZE) ) {
|
||||
PROVIDE(__RAM_TEXT_START__ = .);
|
||||
*(.ram_text)
|
||||
. = ALIGN(CL_SIZE);
|
||||
PROVIDE(__RAM_TEXT_END__ = .);
|
||||
} > REGION_RAM
|
||||
|
||||
__RAM_TEXT_IMAGE_START__ = LOADADDR(.ram_text);
|
||||
__RAM_TEXT_IMAGE_END__ = LOADADDR(.ram_text) + SIZEOF(.ram_text);
|
||||
ASSERT(__RAM_TEXT_IMAGE_END__ < ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT), "REGION_TEXT segment overflows")
|
||||
|
||||
ASSERT(__RAM_TEXT_END__ < ORIGIN(REGION_RAM) + LENGTH(REGION_RAM) - STACK_SIZE, "REGION_RAM section overflows")
|
||||
|
||||
_end = .;
|
||||
PROVIDE(__end = .);
|
||||
|
||||
BUFFER4K_SIZE = 4K;
|
||||
|
||||
.buffer4k ORIGIN(REGION_RAM) + 8K : {
|
||||
FILL(0);
|
||||
PROVIDE(__BUFFER4K__END__ = .);
|
||||
PROVIDE(BUFFER4K = .);
|
||||
. += BUFFER4K_SIZE;
|
||||
PROVIDE(BUFFER_STATUS = .);
|
||||
. += 4;
|
||||
PROVIDE(__BUFFER4K__END__ = .);
|
||||
} >REGION_RAM
|
||||
|
||||
/* End of uninitalized data segement */
|
||||
|
||||
.stack ORIGIN(REGION_RAM) + LENGTH(REGION_RAM) - STACK_SIZE : {
|
||||
FILL(0);
|
||||
PROVIDE(__STACK_START__ = .);
|
||||
. += STACK_SIZE;
|
||||
PROVIDE(__C_STACK_TOP__ = .);
|
||||
PROVIDE(__STACK_END__ = .);
|
||||
} >REGION_RAM
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame .eh_frame.*)
|
||||
}
|
||||
}
|
||||
112
upload_drivers/jtag_spifi/src/main.c
Normal file
112
upload_drivers/jtag_spifi/src/main.c
Normal file
@ -0,0 +1,112 @@
|
||||
#include "mik32_hal_pcc.h"
|
||||
#include "mik32_hal_spifi.h"
|
||||
#include "mik32_hal_spifi_w25.h"
|
||||
|
||||
#include "uart_lib.h"
|
||||
#include "xprintf.h"
|
||||
|
||||
/**
|
||||
* @file main.c
|
||||
*
|
||||
* @brief Пример демонстрирует чтение и запись значений во внешнюю флеш память Winbond W25 по Standard (Single) SPI
|
||||
*/
|
||||
|
||||
// extern char __HEAP_START[];
|
||||
const int BUFFER4K_SIZE = 4 * 1024;
|
||||
extern uint8_t *BUFFER4K[];
|
||||
extern uint32_t *BUFFER_STATUS[];
|
||||
|
||||
register uint32_t address asm ("x31");
|
||||
|
||||
void SystemClock_Config(void);
|
||||
|
||||
void read_flash(SPIFI_HandleTypeDef *spifi, uint32_t address, uint8_t dataLength, uint8_t *dataBytes);
|
||||
|
||||
int main()
|
||||
{
|
||||
// *BUFFER_STATUS = 1;
|
||||
SystemClock_Config();
|
||||
|
||||
UART_Init(UART_0, 3333, UART_CONTROL1_TE_M | UART_CONTROL1_M_8BIT_M, 0, 0);
|
||||
xprintf("START DRIVER\n");
|
||||
|
||||
SPIFI_HandleTypeDef spifi = {
|
||||
.Instance = SPIFI_CONFIG,
|
||||
};
|
||||
|
||||
HAL_SPIFI_MspInit(&spifi);
|
||||
xprintf("msp init complete\n");
|
||||
|
||||
HAL_SPIFI_Reset(&spifi);
|
||||
xprintf("spifi reset complete\n");
|
||||
|
||||
xprintf("BUFFER4K = 0x%08x\n", BUFFER4K);
|
||||
|
||||
*BUFFER_STATUS = 0;
|
||||
|
||||
while (1) {
|
||||
// asm ("wfi");
|
||||
|
||||
// *BUFFER_STATUS = 1;
|
||||
|
||||
HAL_SPIFI_Reset(&spifi);
|
||||
HAL_SPIFI_WaitResetClear(&spifi, HAL_SPIFI_TIMEOUT);
|
||||
|
||||
// xprintf("ERASE SECTOR 0x%08x\n", address);
|
||||
HAL_SPIFI_W25_SectorErase4K(&spifi, address);
|
||||
|
||||
for (uint32_t ad = 0; ad < BUFFER4K_SIZE; ad += 256)
|
||||
{
|
||||
// xprintf("Write Page 0x%08x from 0x%08x\n", ad + address, (uint8_t *)((uint32_t)BUFFER4K + ad));
|
||||
HAL_SPIFI_W25_PageProgram(&spifi, ad + address, 256, (uint8_t *)((uint32_t)BUFFER4K + ad));
|
||||
}
|
||||
|
||||
SPIFI_MemoryCommandTypeDef cmd_mem = {
|
||||
.OpCode = 0x03,
|
||||
.FieldForm = SPIFI_CONFIG_CMD_FIELDFORM_ALL_SERIAL,
|
||||
.FrameForm = SPIFI_CONFIG_CMD_FRAMEFORM_OPCODE_3ADDR,
|
||||
.InterimData = 0,
|
||||
.InterimLength = 0,
|
||||
};
|
||||
|
||||
SPIFI_MemoryModeConfig_HandleTypeDef spifi_mem = {
|
||||
.Instance = spifi.Instance,
|
||||
.Command = cmd_mem,
|
||||
};
|
||||
|
||||
HAL_SPIFI_MemoryMode_Init(&spifi_mem);
|
||||
|
||||
int result = 0;
|
||||
for (uint32_t ad = 0; ad < BUFFER4K_SIZE; ad += 4)
|
||||
{
|
||||
if (*(uint32_t*)(BUFFER4K + ad) != *(uint32_t*)(0x80000000 + address))
|
||||
{
|
||||
result = 3;
|
||||
}
|
||||
}
|
||||
|
||||
*BUFFER_STATUS = result;
|
||||
// asm ("wfi");
|
||||
}
|
||||
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
void SystemClock_Config(void)
|
||||
{
|
||||
PCC_InitTypeDef PCC_OscInit = {0};
|
||||
|
||||
PCC_OscInit.OscillatorEnable = PCC_OSCILLATORTYPE_ALL;
|
||||
PCC_OscInit.FreqMon.OscillatorSystem = PCC_OSCILLATORTYPE_OSC32M;
|
||||
PCC_OscInit.FreqMon.ForceOscSys = PCC_FORCE_OSC_SYS_UNFIXED;
|
||||
PCC_OscInit.FreqMon.Force32KClk = PCC_FREQ_MONITOR_SOURCE_OSC32K;
|
||||
PCC_OscInit.AHBDivider = 0;
|
||||
PCC_OscInit.APBMDivider = 0;
|
||||
PCC_OscInit.APBPDivider = 0;
|
||||
PCC_OscInit.HSI32MCalibrationValue = 128;
|
||||
PCC_OscInit.LSI32KCalibrationValue = 128;
|
||||
PCC_OscInit.RTCClockSelection = PCC_RTC_CLOCK_SOURCE_AUTO;
|
||||
PCC_OscInit.RTCClockCPUSelection = PCC_CPU_RTC_CLOCK_SOURCE_OSC32K;
|
||||
HAL_PCC_Config(&PCC_OscInit);
|
||||
}
|
||||
11
upload_drivers/jtag_spifi/test/README
Normal file
11
upload_drivers/jtag_spifi/test/README
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
This directory is intended for PlatformIO Test Runner and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
||||
Loading…
Reference in New Issue
Block a user