0
0
Fork 0

feat: Enhance SPI and GPIO compatibility.

This commit is contained in:
windowsair 2021-02-15 20:46:19 +08:00
parent 3f0d196bce
commit b4691546d1
9 changed files with 1553 additions and 1212 deletions

110
README.md
View File

@ -1,10 +1,12 @@
<p align="center"><img src="https://user-images.githubusercontent.com/17078589/73821108-300bda00-482e-11ea-89f6-011a50037a12.png"/></p> <p align="center"><img src="https://user-images.githubusercontent.com/17078589/107881245-7d7d5580-6f1e-11eb-9f66-6ac589e5f95c.png"/></p>
<h1 align="center">Wireless ESP8266 DAP</h1>
[![Build Status](https://github.com/windowsair/wireless-esp8266-dap/workflows/build/badge.svg?branch=master)](https://github.com/windowsair/wireless-esp8266-dap/actions?query=branch%3Amaster) master ![image](https://user-images.githubusercontent.com/17078589/107857220-05ecef00-6e68-11eb-9fa0-506b32052dba.png)
[![Build Status](https://github.com/windowsair/wireless-esp8266-dap/workflows/build/badge.svg?branch=master)](https://github.com/windowsair/wireless-esp8266-dap/actions?query=branch%3Amaster) master 
[![Build Status](https://github.com/windowsair/wireless-esp8266-dap/workflows/build/badge.svg?branch=develop)](https://github.com/windowsair/wireless-esp8266-dap/actions?query=branch%3Adevelop) develop [![Build Status](https://github.com/windowsair/wireless-esp8266-dap/workflows/build/badge.svg?branch=develop)](https://github.com/windowsair/wireless-esp8266-dap/actions?query=branch%3Adevelop) develop
[![](https://img.shields.io/badge/license-MIT-green.svg?style=flat-square)](https://github.com/windowsair/wireless-esp8266-dap/LICENSE) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-blue.svg?style=flat-square)](https://github.com/windowsair/wireless-esp8266-dap/pulls) [![%e2%9d%a4](https://img.shields.io/badge/made%20with-%e2%9d%a4-ff69b4.svg?style=flat-square)](https://github.com/windowsair/wireless-esp8266-dap) [![](https://img.shields.io/badge/license-MIT-green.svg?style=flat-square)](https://github.com/windowsair/wireless-esp8266-dap/LICENSE) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-blue.svg?style=flat-square)](https://github.com/windowsair/wireless-esp8266-dap/pulls) [![%e2%9d%a4](https://img.shields.io/badge/made%20with-%e2%9d%a4-ff69b4.svg?style=flat-square)](https://github.com/windowsair/wireless-esp8266-dap)
## Introduce ## Introduce
@ -13,19 +15,20 @@ Wireless debugging with ***only one ESP8266*** !
Realized by USBIP and CMSIS-DAP protocol stack. Realized by USBIP and CMSIS-DAP protocol stack.
> 👉 5m distance, 100kb size firmware flash test: > 👉 5m distance, 100kb size firmware(Hex) flash test:
<p align="center"><img src="https://user-images.githubusercontent.com/17078589/73829782-808b3380-483e-11ea-8389-1570bc4200af.gif"/></p> <p align="center"><img src="https://user-images.githubusercontent.com/17078589/107896674-e5a95700-6f71-11eb-90f7-bf7362045537.gif"/></p>
## Feature ## Feature
1. Debug Communication Mode 1. Debug Communication Mode & Debug Port
- [x] SWD - [x] SWD(SW-DP)
- [x] JTAG - [x] JTAG(JTAG-DP)
- [x] SWJ-DP
2. USB Communication Mode 2. USB Communication Mode
- [x] USB-HID (Default) - [x] USB-HID
- [x] WCID & WinUSB (Experimental) - [x] WCID & WinUSB (Default)
3. Debug Trace 3. Debug Trace
- [ ] UART Serial Wire Output(SWO) - [ ] UART Serial Wire Output(SWO)
@ -53,8 +56,9 @@ You can change `WIFI_SSID` and ` WIFI_PASS` in [wifi_configuration.h](main/wifi_
| SWD | | | SWD | |
|----------------|--------| |----------------|--------|
| SWCLK | GPIO5 | | SWCLK | GPIO14 |
| SWDIO | GPIO4 | | SWDIO | GPIO12 |
| SWDIO_MOSI | GPIO13 |
| LED\_CONNECTED | GPIO2 | | LED\_CONNECTED | GPIO2 |
| LED\_RUNNING | GPIO15 | | LED\_RUNNING | GPIO15 |
| TVCC | 3V3 | | TVCC | 3V3 |
@ -66,30 +70,43 @@ You can change `WIFI_SSID` and ` WIFI_PASS` in [wifi_configuration.h](main/wifi_
| JTAG | | | JTAG | |
|--------------------|---------| |--------------------|---------|
| TCK | GPIO5 | | TCK | GPIO14 |
| TMS | GPIO4 | | TMS | GPIO13 |
| TDI | GPIO13 | | TDI | GPIO4 |
| TDO | GPIO12 | | TDO | GPIO16 |
| nTRST \(optional\) | GPIO0\* | | nTRST \(optional\) | GPIO0\* |
| nRESET | GPIO14 | | nRESET | GPIO5 |
| LED\_CONNECTED | GPIO2 | | LED\_CONNECTED | GPIO2 |
| LED\_RUNNING | GPIO15 | | LED\_RUNNING | GPIO15 |
| TVCC | 3V3 | | TVCC | 3V3 |
| GND | GND | | GND | GND |
You can modify these pin definitions in [DAP_config.h](components/DAP/config/DAP_config.h)
> Tips: Try to avoid using `GPIO0`(working mode switch) and `GPIO16`(RTC) In order to use SPI acceleration, you need to physically connect `SWDIO(GPIO12)` to `SWDIO_MOSI(GPIO13)`.
## Build Here, we give a simple example for reference:
You can build locally or use Github Action to build online ![sch](https://user-images.githubusercontent.com/17078589/107851862-f9589e80-6e47-11eb-9eca-e80760822a6a.png)
Alternatively, you can connect directly with wires as we gave at the beginning, without additional circuits.
> If you need to modify the LED or JTAG pins, please refer to the instructions in [DAP_config.h](components/DAP/config/DAP_config.h) to modify them carefully.
------
## Build And Flash
You can build locally or use Github Action to build online and then download firmware to flash.
### Build with Github Action Online ### Build with Github Action Online
See: [Build with Github Action](https://github.com/windowsair/wireless-esp8266-dap/wiki/Build-with-Github-Action) See: [Build with Github Action](https://github.com/windowsair/wireless-esp8266-dap/wiki/Build-with-Github-Action)
### General build
### General build and Flash
1. Get ESP8266 RTOS Software Development Kit 1. Get ESP8266 RTOS Software Development Kit
@ -117,9 +134,8 @@ python ./idf.py -p /dev/ttyS5 flash
1. Get USBIP project 1. Get USBIP project
- Windows: [usbip-win](https://github.com/cezanne/usbip-win) . - Windows: [usbip-win](https://github.com/cezanne/usbip-win) .
> The pre-compiled version on SourceForge is also available, for HID mode only, but it may be faster. - Linux: Distributed as part of the Linux kernel, but we have not yet tested on Linux platform, and the following instructions are all under Windows platform.
- Linux: Distributed as part of the kernel
2. Start esp8266 and connect it to the device to be debugged 2. Start esp8266 and connect it to the device to be debugged
@ -131,6 +147,7 @@ python ./idf.py -p /dev/ttyS5 flash
# or usbip old version # or usbip old version
.\usbip.exe -D -a <your-esp8266-ip-address> 1-1 .\usbip.exe -D -a <your-esp8266-ip-address> 1-1
# 👉 Recommend
# HID Mode Or WinUSB Mode # HID Mode Or WinUSB Mode
# for usbip-win 0.3.0 kmdf ude # for usbip-win 0.3.0 kmdf ude
.\usbip.exe attach_ude -r <your-esp8266-ip-address> -b 1-1 .\usbip.exe attach_ude -r <your-esp8266-ip-address> -b 1-1
@ -139,31 +156,38 @@ python ./idf.py -p /dev/ttyS5 flash
If all goes well, you should see your device connected. If all goes well, you should see your device connected.
![image](https://user-images.githubusercontent.com/17078589/73833411-eb3f6d80-4844-11ea-8501-02a008f6119d.png) ![image](https://user-images.githubusercontent.com/17078589/107849548-f903d780-6e36-11eb-846f-3eaf0c0dc089.png)
Then test it under MDK: Here, we use MDK for testing:
![target](https://user-images.githubusercontent.com/17078589/73830040-eb3c6f00-483e-11ea-85ee-c40b68a836b2.png) ![target](https://user-images.githubusercontent.com/17078589/73830040-eb3c6f00-483e-11ea-85ee-c40b68a836b2.png)
------
## Speed Strategy
The maximum rate of esp8266 pure IO is about 2MHz.
When you select max clock, we will take the following actions:
- `clock < 2Mhz` : Similar to the clock speed you choose.
- `2MHz <= clock < 10MHz` : Use the fastest pure IO speed.
- `clock >= 10MHz` : SPI acceleration using 40MHz clock.
> Note that the most significant speed constraint of this project is still the TCP connection speed.
## Develop ## Develop
0. Check other branches to know the latest development progress. 0. Check other branches to know the latest development progress.
1. Use WinUSB Mode: 1. Use WinUSB Mode(enabled by default):
change `USE_WINUSB` macor in [USBd_config.h](components/USBIP/USBd_config.h) change `USE_WINUSB` macor in [USBd_config.h](components/USBIP/USBd_config.h)
> Credits to:
> - https://github.com/thevoidnn/esp8266-wifi-cmsis-dap for adapter firmware based on CMSIS-DAP v1.0
> - https://github.com/ARM-software/CMSIS_5 for CMSIS
> - https://github.com/cezanne/usbip-win for usbip windows
In this repo you can find the complete implementation of the USB protocol stack including USB-HID, WCID, WinUSB. ~~Although WinUSB-based mode currently does not work on USBIP~~ :disappointed_relieved: . They are very easy and can help you quickly build your own DAP on other hardware platforms. In this repo you can find the complete implementation of the USB protocol stack including USB-HID, WCID, WinUSB. ~~Although WinUSB-based mode currently does not work on USBIP~~ :disappointed_relieved: . They are very easy and can help you quickly build your own DAP on other hardware platforms.
@ -198,6 +222,22 @@ Due to the completeness of the USBIP protocol document, we have not yet understo
We will continue to try to make it work on USB HID. Once the USBIP problem is solved, we will immediately transfer it to work on WinUSB We will continue to try to make it work on USB HID. Once the USBIP problem is solved, we will immediately transfer it to work on WinUSB
------
# Credit
Credits to the following project, people and organizations:
> - https://github.com/thevoidnn/esp8266-wifi-cmsis-dap for adapter firmware based on CMSIS-DAP v1.0
> - https://github.com/ARM-software/CMSIS_5 for CMSIS
> - https://github.com/cezanne/usbip-win for usbip windows
- @HeavenSpree
- @Zy19930907
- @caiguang1997
## License ## License
[MIT LICENSE](LICENSE) [MIT LICENSE](LICENSE)

File diff suppressed because it is too large Load Diff

View File

@ -233,6 +233,14 @@ extern DAP_Data_t DAP_Data; // DAP Data
extern volatile uint8_t DAP_TransferAbort; // Transfer Abort Flag extern volatile uint8_t DAP_TransferAbort; // Transfer Abort Flag
enum transfer_type {
kTransfer_GPIO_normal,
kTransfer_GPIO_fast,
kTransfer_SPI
};
extern uint8_t SWD_TransferSpeed;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
{ {

View File

@ -0,0 +1,46 @@
#ifndef __GPIO_OP_H__
#define __GPIO_OP_H__
#include "cmsis_compiler.h"
#include "gpio.h"
#include "gpio_struct.h"
#include "timer_struct.h"
#include "esp8266/pin_mux_register.h"
__STATIC_INLINE void GPIO_FUNCTION_SET(int io_num)
{
gpio_pin_reg_t pin_reg;
pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(io_num));
// It should be noted that GPIO0, 2, 4, and 5 need to set the func register to 0,
// and the other GPIO needs to be set to 3 so that IO can be GPIO function.
if ((0x1 << io_num) & (GPIO_Pin_0 | GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_5)) {
pin_reg.rtc_pin.func_low_bit = 0;
pin_reg.rtc_pin.func_high_bit = 0;
} else {
pin_reg.func_low_bit = 3;
pin_reg.func_high_bit = 0;
}
WRITE_PERI_REG(GPIO_PIN_REG(io_num), pin_reg.val);
}
static void GPIO_SET_DIRECTION_NORMAL_OUT(int io_num)
{
GPIO.enable_w1ts |= (0x1 << io_num);
// PP out
GPIO.pin[io_num].driver = 0;
}
// static void GPIO_SET_DIRECTION_NORMAL_IN(int io_num)
// {
// GPIO.enable_w1tc |= (0x1 << io_num);
// }
#endif

View File

@ -5,6 +5,7 @@
void DAP_SPI_WriteBits(const uint8_t count, const uint8_t *buf); void DAP_SPI_WriteBits(const uint8_t count, const uint8_t *buf);
void DAP_SPI_ReadBits(const uint8_t count, uint8_t *buf);
void DAP_SPI_Send_Header(const uint8_t packetHeaderData, uint8_t *ack, uint8_t TrnAfterACK); void DAP_SPI_Send_Header(const uint8_t packetHeaderData, uint8_t *ack, uint8_t TrnAfterACK);
void DAP_SPI_Read_Data(uint32_t* resData, uint8_t* resParity); void DAP_SPI_Read_Data(uint32_t* resData, uint8_t* resParity);

View File

@ -29,6 +29,8 @@
#include "DAP_config.h" #include "DAP_config.h"
#include "DAP.h" #include "DAP.h"
#include "spi_switch.h"
#if (DAP_PACKET_SIZE < 64U) #if (DAP_PACKET_SIZE < 64U)
#error "Minimum Packet Size is 64!" #error "Minimum Packet Size is 64!"
@ -109,7 +111,7 @@ static uint8_t DAP_Info(uint8_t id, uint8_t *info) {
length = 1U; length = 1U;
break; break;
case DAP_ID_TIMESTAMP_CLOCK: case DAP_ID_TIMESTAMP_CLOCK:
#if (TIMESTAMP_CLOCK != 0U) #if (TIMESTAMP_CLOCK != 0U)
info[0] = (uint8_t)(TIMESTAMP_CLOCK >> 0); info[0] = (uint8_t)(TIMESTAMP_CLOCK >> 0);
info[1] = (uint8_t)(TIMESTAMP_CLOCK >> 8); info[1] = (uint8_t)(TIMESTAMP_CLOCK >> 8);
info[2] = (uint8_t)(TIMESTAMP_CLOCK >> 16); info[2] = (uint8_t)(TIMESTAMP_CLOCK >> 16);
@ -207,7 +209,7 @@ static uint32_t DAP_Connect(const uint8_t *request, uint8_t *response) {
} else { } else {
port = *request; port = *request;
} }
switch (port) { switch (port) {
#if (DAP_SWD != 0) #if (DAP_SWD != 0)
case DAP_PORT_SWD: case DAP_PORT_SWD:
@ -266,9 +268,9 @@ static uint32_t DAP_SWJ_Pins(const uint8_t *request, uint8_t *response) {
uint32_t select; uint32_t select;
uint32_t wait; uint32_t wait;
uint32_t timestamp; uint32_t timestamp;
value = (uint32_t) *(request+0); value = (uint32_t) *(request+0);
select = (uint32_t) *(request+1); select = (uint32_t) *(request+1);
wait = (uint32_t)(*(request+2) << 0) | wait = (uint32_t)(*(request+2) << 0) |
(uint32_t)(*(request+3) << 8) | (uint32_t)(*(request+3) << 8) |
(uint32_t)(*(request+4) << 16) | (uint32_t)(*(request+4) << 16) |
@ -300,7 +302,7 @@ static uint32_t DAP_SWJ_Pins(const uint8_t *request, uint8_t *response) {
if (wait != 0U) { if (wait != 0U) {
#if (TIMESTAMP_CLOCK != 0U) #if (TIMESTAMP_CLOCK != 0U)
if (wait > 3000000U) { if (wait > 3000000U) {
wait = 3000000U; wait = 3000000U;
} }
#if (TIMESTAMP_CLOCK >= 1000000U) #if (TIMESTAMP_CLOCK >= 1000000U)
@ -357,6 +359,7 @@ static uint32_t DAP_SWJ_Pins(const uint8_t *request, uint8_t *response) {
return ((6U << 16) | 1U); return ((6U << 16) | 1U);
} }
extern uint8_t SWD_TransferSpeed;
// Process SWJ Clock command and prepare response // Process SWJ Clock command and prepare response
// request: pointer to request data // request: pointer to request data
@ -377,18 +380,30 @@ static uint32_t DAP_SWJ_Clock(const uint8_t *request, uint8_t *response) {
*response = DAP_ERROR; *response = DAP_ERROR;
return ((4U << 16) | 1U); return ((4U << 16) | 1U);
} }
if(clock == 10000000){
clock = MAX_USER_CLOCK;
}
if (clock >= MAX_SWJ_CLOCK(DELAY_FAST_CYCLES)) { // Note that the maximum IO frequency of esp8266 is less than 2MHz
// clock >= 10MHz -> use 40MHz SPI
if (clock >= 10000000) {
DAP_SPI_Init();
DAP_Data.fast_clock = 1U; DAP_Data.fast_clock = 1U;
DAP_Data.clock_delay = 1U; DAP_Data.clock_delay = 1U;
SWD_TransferSpeed = kTransfer_SPI;
} else if (clock >= 2000000) {
// clock >= 2MHz -> Use GPIO with no program delay
DAP_SPI_Deinit();
DAP_Data.fast_clock = 1U;
DAP_Data.clock_delay = 1U;
SWD_TransferSpeed = kTransfer_GPIO_fast;
} else { } else {
// clock < 2MHz -> Use GPIO with delay
DAP_SPI_Deinit();
DAP_Data.fast_clock = 0U; DAP_Data.fast_clock = 0U;
SWD_TransferSpeed = kTransfer_GPIO_normal;
delay = ((CPU_CLOCK/2U) + (clock - 1U)) / clock; #define CPU_CLOCK_FIXED 80000000
delay = ((CPU_CLOCK_FIXED/2U) + (clock - 1U)) / clock;
if (delay > IO_PORT_WRITE_CYCLES) { if (delay > IO_PORT_WRITE_CYCLES) {
delay -= IO_PORT_WRITE_CYCLES; delay -= IO_PORT_WRITE_CYCLES;
delay = (delay + (DELAY_SLOW_CYCLES - 1U)) / DELAY_SLOW_CYCLES; delay = (delay + (DELAY_SLOW_CYCLES - 1U)) / DELAY_SLOW_CYCLES;
@ -417,7 +432,7 @@ static uint32_t DAP_SWJ_Sequence(const uint8_t *request, uint8_t *response) {
uint32_t count; uint32_t count;
count = *request++; count = *request++;
if (count == 0U) { if (count == 0U) {
count = 256U; count = 256U;
} }
@ -446,7 +461,7 @@ static uint32_t DAP_SWD_Configure(const uint8_t *request, uint8_t *response) {
value = *request; value = *request;
DAP_Data.swd_conf.turnaround = (value & 0x03U) + 1U; DAP_Data.swd_conf.turnaround = (value & 0x03U) + 1U;
DAP_Data.swd_conf.data_phase = (value & 0x04U) ? 1U : 0U; DAP_Data.swd_conf.data_phase = (value & 0x04U) ? 1U : 0U;
*response = DAP_OK; *response = DAP_OK;
#else #else
*response = DAP_ERROR; *response = DAP_ERROR;
@ -480,7 +495,7 @@ static uint32_t DAP_SWD_Sequence(const uint8_t *request, uint8_t *response) {
while (sequence_count--) { while (sequence_count--) {
sequence_info = *request++; sequence_info = *request++;
count = sequence_info & SWD_SEQUENCE_CLK; count = sequence_info & SWD_SEQUENCE_CLK;
if (count == 0U) { if (count == 0U) {
count = 64U; count = 64U;
} }
count = (count + 7U) / 8U; count = (count + 7U) / 8U;
@ -630,7 +645,7 @@ static uint32_t DAP_JTAG_IDCode(const uint8_t *request, uint8_t *response) {
id_error: id_error:
#endif #endif
*response = DAP_ERROR; *response = DAP_ERROR;
return ((1U << 16) | 1U); return ((1U << 16) | 1U);
} }
@ -644,11 +659,11 @@ static uint32_t DAP_TransferConfigure(const uint8_t *request, uint8_t *response)
DAP_Data.transfer.idle_cycles = *(request+0); DAP_Data.transfer.idle_cycles = *(request+0);
DAP_Data.transfer.retry_count = (uint16_t) *(request+1) | DAP_Data.transfer.retry_count = (uint16_t) *(request+1) |
(uint16_t)(*(request+2) << 8); (uint16_t)(*(request+2) << 8);
DAP_Data.transfer.match_retry = (uint16_t) *(request+3) | DAP_Data.transfer.match_retry = (uint16_t) *(request+3) |
(uint16_t)(*(request+4) << 8); (uint16_t)(*(request+4) << 8);
*response = DAP_OK; *response = DAP_OK;
return ((5U << 16) | 1U); return ((5U << 16) | 1U);
} }
@ -711,7 +726,7 @@ static uint32_t DAP_SWD_Transfer(const uint8_t *request, uint8_t *response) {
} while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort);
post_read = 0U; post_read = 0U;
} }
if (response_value != DAP_TRANSFER_OK) { if (response_value != DAP_TRANSFER_OK) {
break; break;
} }
// Store previous AP data // Store previous AP data
@ -1386,14 +1401,14 @@ static uint32_t DAP_JTAG_TransferBlock(const uint8_t *request, uint8_t *response
// Device index (JTAP TAP) // Device index (JTAP TAP)
DAP_Data.jtag_dev.index = *request++; DAP_Data.jtag_dev.index = *request++;
if (DAP_Data.jtag_dev.index >= DAP_Data.jtag_dev.count) { if (DAP_Data.jtag_dev.index >= DAP_Data.jtag_dev.count) {
goto end; goto end;
} }
request_count = (uint32_t)(*(request+0) << 0) | request_count = (uint32_t)(*(request+0) << 0) |
(uint32_t)(*(request+1) << 8); (uint32_t)(*(request+1) << 8);
request += 2; request += 2;
if (request_count == 0U) { if (request_count == 0U) {
goto end; goto end;
} }
@ -1549,7 +1564,7 @@ static uint32_t DAP_JTAG_WriteAbort(const uint8_t *request, uint8_t *response) {
DAP_Data.jtag_dev.index = *request; DAP_Data.jtag_dev.index = *request;
if (DAP_Data.jtag_dev.index >= DAP_Data.jtag_dev.count) { if (DAP_Data.jtag_dev.index >= DAP_Data.jtag_dev.count) {
*response = DAP_ERROR; *response = DAP_ERROR;
return (1U); return (1U);
} }
// Select JTAG chain // Select JTAG chain
@ -1565,7 +1580,7 @@ static uint32_t DAP_JTAG_WriteAbort(const uint8_t *request, uint8_t *response) {
JTAG_WriteAbort(data); JTAG_WriteAbort(data);
*response = DAP_OK; *response = DAP_OK;
return (1U); return (1U);
} }
#endif #endif
@ -1741,7 +1756,7 @@ uint32_t DAP_ExecuteCommand(const uint8_t *request, uint8_t *response) {
n = DAP_ProcessCommand(request, response); n = DAP_ProcessCommand(request, response);
num += n; num += n;
request += (uint16_t)(n >> 16); request += (uint16_t)(n >> 16);
response += (uint16_t) n; response += (uint16_t) n;
} }
return (num); return (num);
} }

View File

@ -1,326 +1,528 @@
/* /*
* Copyright (c) 2013-2017 ARM Limited. All rights reserved. * Copyright (c) 2013-2017 ARM Limited. All rights reserved.
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
* Licensed under the Apache License, Version 2.0 (the License); you may * Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License. * not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* www.apache.org/licenses/LICENSE-2.0 * www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT * distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
* *
* ---------------------------------------------------------------------- * ----------------------------------------------------------------------
* *
* $Date: 1. December 2017 * $Date: 1. December 2017
* $Revision: V2.0.0 * $Revision: V2.0.0
* *
* Project: CMSIS-DAP Source * Project: CMSIS-DAP Source
* Title: SW_DP.c CMSIS-DAP SW DP I/O * Title: SW_DP.c CMSIS-DAP SW DP I/O
* *
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
#include "DAP_config.h" /**
#include "DAP.h" * @file SW_DP.c
* @author windowsair
#include "spi_op.h" * @brief Adaptation of GPIO and SPI
#include "spi_switch.h" * @change:
#include "dap_utility.h" * 2021-2-10 Support GPIO and SPI for SWD sequence / SWJ sequence / SWD transfer
* Note: SWD sequence not yet tested
// Debug * @version 0.1
#define PRINT_SWD_PROTOCOL 0 * @date 2021-2-10
*
// SW Macros * @copyright Copyright (c) 2021
*
#define PIN_SWCLK_SET PIN_SWCLK_TCK_SET */
#define PIN_SWCLK_CLR PIN_SWCLK_TCK_CLR
#define SW_CLOCK_CYCLE() \ #include "DAP_config.h"
PIN_SWCLK_CLR(); \ #include "DAP.h"
PIN_DELAY(); \
PIN_SWCLK_SET(); \ #include "spi_op.h"
PIN_DELAY() #include "spi_switch.h"
#include "dap_utility.h"
#define SW_WRITE_BIT(bit) \
PIN_SWDIO_OUT(bit); \ // Debug
PIN_SWCLK_CLR(); \ #define PRINT_SWD_PROTOCOL 0
PIN_DELAY(); \
PIN_SWCLK_SET(); \ // SW Macros
PIN_DELAY()
#define PIN_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay)
#define SW_READ_BIT(bit) \
PIN_SWCLK_CLR(); \ #define PIN_SWCLK_SET PIN_SWCLK_TCK_SET
PIN_DELAY(); \ #define PIN_SWCLK_CLR PIN_SWCLK_TCK_CLR
bit = PIN_SWDIO_IN(); \
PIN_SWCLK_SET(); \ // Space for time in the original version,
PIN_DELAY() // and time for space in our implementation
//#define PIN_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay) #define SW_CLOCK_CYCLE() \
#define PIN_DELAY() PIN_DELAY_FAST() PIN_SWCLK_CLR(); \
if (need_delay) { PIN_DELAY(); } \
PIN_SWCLK_SET(); \
// Generate SWJ Sequence if (need_delay) { PIN_DELAY(); }
// count: sequence bit count
// data: pointer to sequence bit data #define SW_WRITE_BIT(bit) \
// return: none PIN_SWDIO_OUT(bit); \
#if ((DAP_SWD != 0) || (DAP_JTAG != 0)) PIN_SWCLK_CLR(); \
void SWJ_Sequence (uint32_t count, const uint8_t *data) { if (need_delay) { PIN_DELAY(); } \
if (count != 8 && count != 16 && count!= 51) PIN_SWCLK_SET(); \
{ if (need_delay) { PIN_DELAY(); }
printf("[ERROR] wrong SWJ Swquence length:%d\r\n", (int)count);
return; #define SW_READ_BIT(bit) \
} PIN_SWCLK_CLR(); \
DAP_SPI_Enable(); if (need_delay) { PIN_DELAY(); } \
DAP_SPI_WriteBits(count, data); bit = PIN_SWDIO_IN(); \
} PIN_SWCLK_SET(); \
#endif if (need_delay) { PIN_DELAY(); }
// Generate SWD Sequence
// info: sequence information uint8_t SWD_TransferSpeed = kTransfer_GPIO_normal;
// swdo: pointer to SWDIO generated data
// swdi: pointer to SWDIO captured data
// return: none void SWJ_Sequence_GPIO (uint32_t count, const uint8_t *data, uint8_t need_delay);
#if (DAP_SWD != 0) void SWJ_Sequence_SPI (uint32_t count, const uint8_t *data);
void SWD_Sequence (uint32_t info, const uint8_t *swdo, uint8_t *swdi) {
uint32_t val; void SWD_Sequence_GPIO (uint32_t info, const uint8_t *swdo, uint8_t *swdi);
uint32_t bit; void SWD_Sequence_SPI (uint32_t info, const uint8_t *swdo, uint8_t *swdi);
uint32_t n, k;
n = info & SWD_SEQUENCE_CLK; // Generate SWJ Sequence
if (n == 0U) { // count: sequence bit count
n = 64U; // data: pointer to sequence bit data
} // return: none
#if ((DAP_SWD != 0) || (DAP_JTAG != 0))
if (info & SWD_SEQUENCE_DIN) { void SWJ_Sequence (uint32_t count, const uint8_t *data) {
while (n) { // if (count != 8 && count != 16 && count!= 51)
val = 0U; // {
for (k = 8U; k && n; k--, n--) { // printf("[ERROR] wrong SWJ Swquence length:%d\r\n", (int)count);
SW_READ_BIT(bit); // return;
val >>= 1; // }
val |= bit << 7;
} if(SWD_TransferSpeed == kTransfer_SPI) {
val >>= k; SWJ_Sequence_SPI(count, data);
*swdi++ = (uint8_t)val; } else {
} SWJ_Sequence_GPIO(count, data, 1);
} else { }
while (n) {
val = *swdo++; }
for (k = 8U; k && n; k--, n--) {
SW_WRITE_BIT(val);
val >>= 1; void SWJ_Sequence_GPIO (uint32_t count, const uint8_t *data, uint8_t need_delay) {
} uint32_t val;
} uint32_t n;
}
} val = 0U;
#endif n = 0U;
while (count--) {
if (n == 0U) {
#if (DAP_SWD != 0) val = *data++;
n = 8U;
}
// SWD Transfer I/O if (val & 1U) {
// request: A[3:2] RnW APnDP PIN_SWDIO_TMS_SET();
// data: DATA[31:0] } else {
// return: ACK[2:0] PIN_SWDIO_TMS_CLR();
}
//// TODO: low speed SW_CLOCK_CYCLE();
#define SWD_TransferFunction(speed) /* Speed may be useless, because all use this function */ \ val >>= 1;
static uint8_t SWD_Transfer##speed (uint32_t request, uint32_t *data) { \ n--;
SWD_Transfer_Common(request,data); \ }
return 1; \ }
}
void SWJ_Sequence_SPI (uint32_t count, const uint8_t *data) {
static uint8_t SWD_Transfer_Common (uint32_t request, uint32_t *data) { DAP_SPI_Enable();
uint8_t ack; DAP_SPI_WriteBits(count, data);
// uint32_t bit; }
uint32_t val; #endif
uint8_t parity;
uint8_t computedParity;
// Generate SWD Sequence
uint32_t n; // info: sequence information
// swdo: pointer to SWDIO generated data
int retryCount = 0; // swdi: pointer to SWDIO captured data
const uint8_t constantBits = 0b10000001U; /* Start Bit & Stop Bit & Park Bit is fixed. */ // return: none
uint8_t requestByte; /* LSB */ #if (DAP_SWD != 0)
void SWD_Sequence (uint32_t info, const uint8_t *swdo, uint8_t *swdi) {
if (SWD_TransferSpeed == kTransfer_SPI) {
DAP_SPI_Enable(); SWD_Sequence_SPI(info, swdo, swdi);
do { } else {
requestByte = constantBits | (((uint8_t)(request & 0xFU)) << 1U) | (ParityEvenUint8(request & 0xFU) << 5U); SWD_Sequence_GPIO(info, swdo, swdi);
/* For 4bit, Parity can be equivalent to 8bit with all 0 high bits */ }
}
#if (PRINT_SWD_PROTOCOL == 1)
switch (requestByte) void SWD_Sequence_GPIO (uint32_t info, const uint8_t *swdo, uint8_t *swdi) {
{ const uint8_t need_delay = 1;
case 0xA5U:
printf("IDCODE\r\n"); uint32_t val;
break; uint32_t bit;
case 0xA9U: uint32_t n, k;
printf("W CTRL/STAT\r\n");
break; n = info & SWD_SEQUENCE_CLK;
case 0xBDU: if (n == 0U) {
printf("RDBUFF\r\n"); n = 64U;
break; }
case 0x8DU: // n = 1 ~ 64
printf("R CTRL/STAT\r\n");
break; // LSB
case 0x81U: if (info & SWD_SEQUENCE_DIN) {
printf("W ABORT\r\n"); while (n) {
break; val = 0U;
case 0xB1U: for (k = 8U; k && n; k--, n--) {
printf("W SELECT\r\n"); SW_READ_BIT(bit);
break; val >>= 1;
case 0xBBU: val |= bit << 7;
printf("W APc\r\n"); }
break; val >>= k;
case 0x9FU: *swdi++ = (uint8_t)val;
printf("R APc\r\n"); }
break; } else {
case 0x8BU: while (n) {
printf("W AP4\r\n"); val = *swdo++;
break; for (k = 8U; k && n; k--, n--) {
case 0xA3U: SW_WRITE_BIT(val);
printf("W AP0\r\n"); val >>= 1;
break; }
case 0X87U: }
printf("R AP0\r\n"); }
break; }
case 0xB7U:
printf("R AP8\r\n"); void SWD_Sequence_SPI (uint32_t info, const uint8_t *swdo, uint8_t *swdi) {
break; uint32_t n;
default: n = info & SWD_SEQUENCE_CLK;
//W AP8 if (n == 0U) {
printf("Unknown:%08x\r\n", requestByte); n = 64U;
break; }
} // n = 1 ~ 64
#endif
if (info & SWD_SEQUENCE_DIN) {
DAP_SPI_ReadBits(n, swdi);
} else {
if (request & DAP_TRANSFER_RnW) { DAP_SPI_WriteBits(n, swdo);
/* Read data */ }
}
DAP_SPI_Send_Header(requestByte, &ack, 0); // 0 Trn After ACK
if (ack == DAP_TRANSFER_OK) { #endif
DAP_SPI_Read_Data(&val, &parity);
computedParity = ParityEvenUint32(val);
#if (DAP_SWD != 0)
if ((computedParity ^ parity) & 1U) {
ack = DAP_TRANSFER_ERROR;
} // SWD Transfer I/O
if (data) { *data = val; } // request: A[3:2] RnW APnDP
// data: DATA[31:0]
/* Capture Timestamp */ // return: ACK[2:0]
if (request & DAP_TRANSFER_TIMESTAMP) { static uint8_t SWD_Transfer_SPI (uint32_t request, uint32_t *data) {
DAP_Data.timestamp = TIMESTAMP_GET(); // SPI transfer mode does not require operations such as PIN_DELAY
} uint8_t ack;
// uint32_t bit;
} uint32_t val;
else if ((ack == DAP_TRANSFER_WAIT) || (ack == DAP_TRANSFER_FAULT)) { uint8_t parity;
DAP_SPI_Generate_Cycle(1); uint8_t computedParity;
#if (PRINT_SWD_PROTOCOL == 1)
printf("WAIT\r\n"); uint32_t n;
#endif
const uint8_t constantBits = 0b10000001U; /* Start Bit & Stop Bit & Park Bit is fixed. */
continue; uint8_t requestByte; /* LSB */
// return DAP_TRANSFER_WAIT;
}
else { DAP_SPI_Enable();
/* Protocol error */
DAP_SPI_Disable(); requestByte = constantBits | (((uint8_t)(request & 0xFU)) << 1U) | (ParityEvenUint8(request & 0xFU) << 5U);
PIN_SWDIO_TMS_SET(); /* For 4bit, Parity can be equivalent to 8bit with all 0 high bits */
DAP_SPI_Enable(); #if (PRINT_SWD_PROTOCOL == 1)
DAP_SPI_Protocol_Error_Read(); switch (requestByte)
{
DAP_SPI_Disable(); case 0xA5U:
PIN_SWDIO_TMS_SET(); printf("IDCODE\r\n");
printf("Protocol Error: Read\r\n"); break;
} case 0xA9U:
printf("W CTRL/STAT\r\n");
return ((uint8_t)ack); break;
} case 0xBDU:
else { printf("RDBUFF\r\n");
/* Write data */ break;
parity = ParityEvenUint32(*data); case 0x8DU:
DAP_SPI_Send_Header(requestByte, &ack, 1); // 1 Trn After ACK printf("R CTRL/STAT\r\n");
if (ack == DAP_TRANSFER_OK) { break;
DAP_SPI_Write_Data(*data, parity); case 0x81U:
/* Capture Timestamp */ printf("W ABORT\r\n");
if (request & DAP_TRANSFER_TIMESTAMP) { break;
DAP_Data.timestamp = TIMESTAMP_GET(); case 0xB1U:
} printf("W SELECT\r\n");
/* Idle cycles */ break;
n = DAP_Data.transfer.idle_cycles; case 0xBBU:
if (n) { DAP_SPI_Generate_Cycle(n); } printf("W APc\r\n");
break;
DAP_SPI_Disable(); case 0x9FU:
PIN_SWDIO_TMS_SET(); printf("R APc\r\n");
break;
return ((uint8_t)ack); case 0x8BU:
} printf("W AP4\r\n");
else if ((ack == DAP_TRANSFER_WAIT) || (ack == DAP_TRANSFER_FAULT)) { break;
/* already turnaround. */ case 0xA3U:
printf("W AP0\r\n");
/* TODO: overrun transfer -> for read */ break;
#if (PRINT_SWD_PROTOCOL == 1) case 0X87U:
printf("WAIT\r\n"); printf("R AP0\r\n");
#endif break;
case 0xB7U:
continue; printf("R AP8\r\n");
break;
} default:
else { //W AP8
//// FIXME: bug printf("Unknown:%08x\r\n", requestByte);
/* Protocol error */ break;
DAP_SPI_Disable(); }
PIN_SWDIO_TMS_SET(); #endif
DAP_SPI_Enable(); if (request & DAP_TRANSFER_RnW) {
DAP_SPI_Protocol_Error_Write(); /* Read data */
DAP_SPI_Disable(); DAP_SPI_Send_Header(requestByte, &ack, 0); // 0 Trn After ACK
PIN_SWDIO_TMS_SET(); if (ack == DAP_TRANSFER_OK) {
printf("Protocol Error: Write\r\n"); DAP_SPI_Read_Data(&val, &parity);
} computedParity = ParityEvenUint32(val);
return ((uint8_t)ack); if ((computedParity ^ parity) & 1U) {
ack = DAP_TRANSFER_ERROR;
} }
} while (retryCount++ < 99); if (data) { *data = val; }
return DAP_TRANSFER_ERROR; /* Capture Timestamp */
if (request & DAP_TRANSFER_TIMESTAMP) {
DAP_Data.timestamp = TIMESTAMP_GET();
} }
}
#undef PIN_DELAY else if ((ack == DAP_TRANSFER_WAIT) || (ack == DAP_TRANSFER_FAULT)) {
#define PIN_DELAY() PIN_DELAY_FAST() DAP_SPI_Generate_Cycle(1);
SWD_TransferFunction(Fast) #if (PRINT_SWD_PROTOCOL == 1)
printf("WAIT\r\n");
#undef PIN_DELAY #endif
#define PIN_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay)
SWD_TransferFunction(Slow) // return DAP_TRANSFER_WAIT;
}
else {
// SWD Transfer I/O /* Protocol error */
// request: A[3:2] RnW APnDP DAP_SPI_Disable();
// data: DATA[31:0] PIN_SWDIO_TMS_SET();
// return: ACK[2:0]
uint8_t SWD_Transfer(uint32_t request, uint32_t *data) { DAP_SPI_Enable();
if (DAP_Data.fast_clock) { DAP_SPI_Protocol_Error_Read();
return SWD_TransferFast(request, data);
} else { DAP_SPI_Disable();
return SWD_TransferSlow(request, data); PIN_SWDIO_TMS_SET();
} #if (PRINT_SWD_PROTOCOL == 1)
} printf("Protocol Error: Read\r\n");
#endif
}
#endif /* (DAP_SWD != 0) */
return ((uint8_t)ack);
}
else {
/* Write data */
parity = ParityEvenUint32(*data);
DAP_SPI_Send_Header(requestByte, &ack, 1); // 1 Trn After ACK
if (ack == DAP_TRANSFER_OK) {
DAP_SPI_Write_Data(*data, parity);
/* Capture Timestamp */
if (request & DAP_TRANSFER_TIMESTAMP) {
DAP_Data.timestamp = TIMESTAMP_GET();
}
/* Idle cycles */
n = DAP_Data.transfer.idle_cycles;
if (n) { DAP_SPI_Generate_Cycle(n); }
DAP_SPI_Disable();
PIN_SWDIO_TMS_SET();
return ((uint8_t)ack);
}
else if ((ack == DAP_TRANSFER_WAIT) || (ack == DAP_TRANSFER_FAULT)) {
/* already turnaround. */
/* TODO: overrun transfer -> for read */
#if (PRINT_SWD_PROTOCOL == 1)
printf("WAIT\r\n");
#endif
}
else {
//// FIXME: bug
/* Protocol error */
DAP_SPI_Disable();
PIN_SWDIO_TMS_SET();
DAP_SPI_Enable();
DAP_SPI_Protocol_Error_Write();
DAP_SPI_Disable();
PIN_SWDIO_TMS_SET();
#if (PRINT_SWD_PROTOCOL == 1)
printf("Protocol Error: Write\r\n");
#endif
}
return ((uint8_t)ack);
}
return DAP_TRANSFER_ERROR;
}
static uint8_t SWD_Transfer_GPIO (uint32_t request, uint32_t *data, uint8_t need_delay) {
uint32_t ack;
uint32_t bit;
uint32_t val;
uint32_t parity;
uint32_t n;
/* Packet Request */
parity = 0U;
SW_WRITE_BIT(1U); /* Start Bit */
bit = request >> 0;
SW_WRITE_BIT(bit); /* APnDP Bit */
parity += bit;
bit = request >> 1;
SW_WRITE_BIT(bit); /* RnW Bit */
parity += bit;
bit = request >> 2;
SW_WRITE_BIT(bit); /* A2 Bit */
parity += bit;
bit = request >> 3;
SW_WRITE_BIT(bit); /* A3 Bit */
parity += bit;
SW_WRITE_BIT(parity); /* Parity Bit */
SW_WRITE_BIT(0U); /* Stop Bit */
SW_WRITE_BIT(1U); /* Park Bit */
/* Turnaround */
PIN_SWDIO_OUT_DISABLE();
for (n = DAP_Data.swd_conf.turnaround; n; n--) {
SW_CLOCK_CYCLE();
}
/* Acknowledge response */
SW_READ_BIT(bit);
ack = bit << 0;
SW_READ_BIT(bit);
ack |= bit << 1;
SW_READ_BIT(bit);
ack |= bit << 2;
if (ack == DAP_TRANSFER_OK) { /* OK response */
/* Data transfer */
if (request & DAP_TRANSFER_RnW) {
/* Read data */
val = 0U;
parity = 0U;
for (n = 32U; n; n--) {
SW_READ_BIT(bit); /* Read RDATA[0:31] */
parity += bit;
val >>= 1;
val |= bit << 31;
}
SW_READ_BIT(bit); /* Read Parity */
if ((parity ^ bit) & 1U) {
ack = DAP_TRANSFER_ERROR;
}
if (data) { *data = val; }
/* Turnaround */
for (n = DAP_Data.swd_conf.turnaround; n; n--) {
SW_CLOCK_CYCLE();
}
PIN_SWDIO_OUT_ENABLE();
} else {
/* Turnaround */
for (n = DAP_Data.swd_conf.turnaround; n; n--) {
SW_CLOCK_CYCLE();
}
PIN_SWDIO_OUT_ENABLE();
/* Write data */
val = *data;
parity = 0U;
for (n = 32U; n; n--) {
SW_WRITE_BIT(val); /* Write WDATA[0:31] */
parity += val;
val >>= 1;
}
SW_WRITE_BIT(parity); /* Write Parity Bit */
}
/* Capture Timestamp */
if (request & DAP_TRANSFER_TIMESTAMP) {
DAP_Data.timestamp = TIMESTAMP_GET();
}
/* Idle cycles */
n = DAP_Data.transfer.idle_cycles;
if (n) {
PIN_SWDIO_OUT(0U);
for (; n; n--) {
SW_CLOCK_CYCLE();
}
}
PIN_SWDIO_OUT(1U);
return ((uint8_t)ack);
}
if ((ack == DAP_TRANSFER_WAIT) || (ack == DAP_TRANSFER_FAULT)) {
/* WAIT or FAULT response */
if (DAP_Data.swd_conf.data_phase && ((request & DAP_TRANSFER_RnW) != 0U)) {
for (n = 32U+1U; n; n--) {
SW_CLOCK_CYCLE(); /* Dummy Read RDATA[0:31] + Parity */
}
}
/* Turnaround */
for (n = DAP_Data.swd_conf.turnaround; n; n--) {
SW_CLOCK_CYCLE();
}
PIN_SWDIO_OUT_ENABLE();
if (DAP_Data.swd_conf.data_phase && ((request & DAP_TRANSFER_RnW) == 0U)) {
PIN_SWDIO_OUT(0U);
for (n = 32U+1U; n; n--) {
SW_CLOCK_CYCLE(); /* Dummy Write WDATA[0:31] + Parity */
}
}
PIN_SWDIO_OUT(1U);
return ((uint8_t)ack);
}
/* Protocol error */
for (n = DAP_Data.swd_conf.turnaround + 32U + 1U; n; n--) {
SW_CLOCK_CYCLE(); /* Back off data phase */
}
PIN_SWDIO_OUT_ENABLE();
PIN_SWDIO_OUT(1U);
return ((uint8_t)ack);
}
// SWD Transfer I/O
// request: A[3:2] RnW APnDP
// data: DATA[31:0]
// return: ACK[2:0]
uint8_t SWD_Transfer(uint32_t request, uint32_t *data) {
switch (SWD_TransferSpeed) {
case kTransfer_SPI:
return SWD_Transfer_SPI(request, data);
case kTransfer_GPIO_fast:
return SWD_Transfer_GPIO(request, data, 0);
case kTransfer_GPIO_normal:
return SWD_Transfer_GPIO(request, data, 1);
default:
return SWD_Transfer_GPIO(request, data, 1);
}
}
#endif /* (DAP_SWD != 0) */

View File

@ -1,3 +1,15 @@
/**
* @file spi_op.c
* @author windowsair
* @brief Using SPI for common transfer operations
* @change: 2020-11-25 first version
* 2021-2-11 Support SWD sequence
* @version 0.2
* @date 2021-2-11
*
* @copyright Copyright (c) 2021
*
*/
#include <stdio.h> #include <stdio.h>
#include "esp8266/spi_struct.h" #include "esp8266/spi_struct.h"
@ -6,12 +18,23 @@
#define DAP_SPI SPI1 #define DAP_SPI SPI1
/**
* @brief Calculate integer division and round up
*
* @param A
* @param B
* @return result
*/
__STATIC_FORCEINLINE int div_round_up(int A, int B)
{
return (A + B - 1) / B;
}
/** /**
* @brief Write bits. LSB & little-endian * @brief Write bits. LSB & little-endian
* Note: No check. The pointer must be valid. * Note: No check. The pointer must be valid.
* @param count Number of bits to be written * @param count Number of bits to be written (<= 64 bits, no length check)
* @param buf Data Buf * @param buf Data Buf
*/ */
void DAP_SPI_WriteBits(const uint8_t count, const uint8_t *buf) void DAP_SPI_WriteBits(const uint8_t count, const uint8_t *buf)
@ -26,22 +49,35 @@ void DAP_SPI_WriteBits(const uint8_t count, const uint8_t *buf)
switch (count) switch (count)
{ {
case 8: case 8:
DAP_SPI.data_buf[0] = (buf[0] << 0) | (0U << 8) | (0U << 16) | (0U << 24); DAP_SPI.data_buf[0] = (buf[0] << 0) | (0U << 8) | (0U << 16) | (0U << 24);
break; break;
case 16: case 16:
DAP_SPI.data_buf[0] = (buf[0] << 0) | (buf[1] << 8) | (0x000U << 16) | (0x000U << 24); DAP_SPI.data_buf[0] = (buf[0] << 0) | (buf[1] << 8) | (0x000U << 16) | (0x000U << 24);
break; break;
case 33: // 32bits data & 1 bit parity case 33: // 32bits data & 1 bit parity
DAP_SPI.data_buf[0] = (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); DAP_SPI.data_buf[0] = (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
DAP_SPI.data_buf[1] = (buf[4] << 0) | (0x000U << 8) | (0x000U << 16) | (0x000U << 24); DAP_SPI.data_buf[1] = (buf[4] << 0) | (0x000U << 8) | (0x000U << 16) | (0x000U << 24);
break; break;
case 51: // for line reset case 51: // for line reset
DAP_SPI.data_buf[0] = (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); DAP_SPI.data_buf[0] = (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
DAP_SPI.data_buf[1] = (buf[4] << 0) | (buf[5] << 8) | (buf[2] << 16) | (0x000U << 24); DAP_SPI.data_buf[1] = (buf[4] << 0) | (buf[5] << 8) | (buf[2] << 16) | (0x000U << 24);
break; break;
default: default:
printf("[ERROR] Using unaligned data!\r\n"); {
break; uint32_t data_buf[2];
uint8_t *pData = (uint8_t *)data_buf;
int i;
for (i = 0; i < div_round_up(count, 8); i++)
{
pData[i] = buf[i];
}
// last byte use mask:
pData[i-1] = pData[i-1] & ((2U >> (count % 8)) - 1U);
DAP_SPI.data_buf[0] = data_buf[0];
DAP_SPI.data_buf[1] = data_buf[1];
}
} }
// Start transmission // Start transmission
@ -51,9 +87,44 @@ void DAP_SPI_WriteBits(const uint8_t count, const uint8_t *buf)
} }
/** /**
* @brief Step1: Packet Request * @brief Read bits. LSB & little-endian
* * Note: No check. The pointer must be valid.
* @param count Number of bits to be read (<= 64 bits, no length check)
* @param buf Data Buf
*/
void DAP_SPI_ReadBits(const uint8_t count, uint8_t *buf) {
int i;
uint32_t data_buf[2];
uint8_t * pData = (uint8_t *)data_buf;
DAP_SPI.user.usr_mosi = 0;
DAP_SPI.user.usr_miso = 1;
DAP_SPI.user1.usr_miso_bitlen = count - 1U;
// Start transmission
DAP_SPI.cmd.usr = 1;
// Wait for reading to complete
while (DAP_SPI.cmd.usr);
data_buf[0] = DAP_SPI.data_buf[0];
data_buf[1] = DAP_SPI.data_buf[1];
for (i = 0; i < div_round_up(count, 8); i++)
{
buf[i] = pData[i];
}
// last byte use mask:
buf[i-1] = buf[i-1] & ((2 >> (count % 8)) - 1);
}
/**
* @brief Step1: Packet Request
*
* @param packetHeaderData data from host * @param packetHeaderData data from host
* @param ack ack from target * @param ack ack from target
* @param TrnAfterACK num of trn after ack * @param TrnAfterACK num of trn after ack
@ -70,9 +141,9 @@ __FORCEINLINE void DAP_SPI_Send_Header(const uint8_t packetHeaderData, uint8_t *
// 1 bit Trn(Before ACK) + 3bits ACK + TrnAferACK - 1(prescribed) // 1 bit Trn(Before ACK) + 3bits ACK + TrnAferACK - 1(prescribed)
DAP_SPI.user1.usr_miso_bitlen = 1U + 3U + TrnAfterACK - 1U; DAP_SPI.user1.usr_miso_bitlen = 1U + 3U + TrnAfterACK - 1U;
// copy data to reg // copy data to reg
DAP_SPI.data_buf[0] = (packetHeaderData << 0) | (0U << 8) | (0U << 16) | (0U << 24); DAP_SPI.data_buf[0] = (packetHeaderData << 0) | (0U << 8) | (0U << 16) | (0U << 24);
// Start transmission // Start transmission
DAP_SPI.cmd.usr = 1; DAP_SPI.cmd.usr = 1;
@ -86,21 +157,20 @@ __FORCEINLINE void DAP_SPI_Send_Header(const uint8_t packetHeaderData, uint8_t *
/** /**
* @brief Step2: Read Data * @brief Step2: Read Data
* *
* @param resData data from target * @param resData data from target
* @param resParity parity from target * @param resParity parity from target
*/ */
__FORCEINLINE void DAP_SPI_Read_Data(uint32_t* resData, uint8_t* resParity) __FORCEINLINE void DAP_SPI_Read_Data(uint32_t *resData, uint8_t *resParity)
{ {
uint64_t dataBuf; uint64_t dataBuf;
uint32_t *pU32Data = (uint32_t *)&dataBuf; uint32_t *pU32Data = (uint32_t *)&dataBuf;
DAP_SPI.user.usr_mosi = 0; DAP_SPI.user.usr_mosi = 0;
DAP_SPI.user.usr_miso = 1; DAP_SPI.user.usr_miso = 1;
// 1 bit Trn(End) + 3bits ACK + 32bis data + 1bit parity - 1(prescribed) // 1 bit Trn(End) + 3bits ACK + 32bis data + 1bit parity - 1(prescribed)
DAP_SPI.user1.usr_miso_bitlen = 1U +32U + 1U - 1U; DAP_SPI.user1.usr_miso_bitlen = 1U + 32U + 1U - 1U;
// Start transmission // Start transmission
DAP_SPI.cmd.usr = 1; DAP_SPI.cmd.usr = 1;
@ -110,13 +180,13 @@ __FORCEINLINE void DAP_SPI_Read_Data(uint32_t* resData, uint8_t* resParity)
pU32Data[0] = DAP_SPI.data_buf[0]; pU32Data[0] = DAP_SPI.data_buf[0];
pU32Data[1] = DAP_SPI.data_buf[1]; pU32Data[1] = DAP_SPI.data_buf[1];
*resData = (dataBuf >> 0U) & 0xFFFFFFFFU ; // 32bits Response Data *resData = (dataBuf >> 0U) & 0xFFFFFFFFU; // 32bits Response Data
*resParity = (dataBuf >> (0U + 32U)) & 1U; // 3bits ACK + 32bis data *resParity = (dataBuf >> (0U + 32U)) & 1U; // 3bits ACK + 32bis data
} }
/** /**
* @brief Step2: Write Data * @brief Step2: Write Data
* *
* @param data data from host * @param data data from host
* @param parity parity from host * @param parity parity from host
*/ */
@ -126,7 +196,7 @@ __FORCEINLINE void DAP_SPI_Write_Data(uint32_t data, uint8_t parity)
DAP_SPI.user.usr_miso = 0; DAP_SPI.user.usr_miso = 0;
DAP_SPI.user1.usr_mosi_bitlen = 32U + 1U - 1U; // 32bis data + 1bit parity - 1(prescribed) DAP_SPI.user1.usr_mosi_bitlen = 32U + 1U - 1U; // 32bis data + 1bit parity - 1(prescribed)
// copy data to reg // copy data to reg
DAP_SPI.data_buf[0] = data; DAP_SPI.data_buf[0] = data;
DAP_SPI.data_buf[1] = parity; DAP_SPI.data_buf[1] = parity;
@ -139,11 +209,12 @@ __FORCEINLINE void DAP_SPI_Write_Data(uint32_t data, uint8_t parity)
/** /**
* @brief Generate Clock Cycle * @brief Generate Clock Cycle
* *
* @param num Cycle Num * @param num Cycle Num
*/ */
__FORCEINLINE void DAP_SPI_Generate_Cycle(uint8_t num) __FORCEINLINE void DAP_SPI_Generate_Cycle(uint8_t num)
{ {
//// TODO: It may take long time to generate just one clock
DAP_SPI.user.usr_mosi = 1; DAP_SPI.user.usr_mosi = 1;
DAP_SPI.user.usr_miso = 0; DAP_SPI.user.usr_miso = 0;
DAP_SPI.user1.usr_mosi_bitlen = num - 1U; DAP_SPI.user1.usr_mosi_bitlen = num - 1U;
@ -157,7 +228,7 @@ __FORCEINLINE void DAP_SPI_Generate_Cycle(uint8_t num)
/** /**
* @brief Generate Protocol Error Cycle * @brief Generate Protocol Error Cycle
* *
*/ */
__FORCEINLINE void DAP_SPI_Protocol_Error_Read() __FORCEINLINE void DAP_SPI_Protocol_Error_Read()
{ {
@ -167,7 +238,7 @@ __FORCEINLINE void DAP_SPI_Protocol_Error_Read()
DAP_SPI.data_buf[0] = 0xFFFFFFFFU; DAP_SPI.data_buf[0] = 0xFFFFFFFFU;
DAP_SPI.data_buf[1] = 0xFFFFFFFFU; DAP_SPI.data_buf[1] = 0xFFFFFFFFU;
DAP_SPI.cmd.usr = 1; DAP_SPI.cmd.usr = 1;
while (DAP_SPI.cmd.usr); while (DAP_SPI.cmd.usr);
} }
@ -175,7 +246,7 @@ __FORCEINLINE void DAP_SPI_Protocol_Error_Read()
/** /**
* @brief Generate Protocol Error Cycle * @brief Generate Protocol Error Cycle
* *
*/ */
__FORCEINLINE void DAP_SPI_Protocol_Error_Write() __FORCEINLINE void DAP_SPI_Protocol_Error_Write()
{ {
@ -185,7 +256,7 @@ __FORCEINLINE void DAP_SPI_Protocol_Error_Write()
DAP_SPI.data_buf[0] = 0xFFFFFFFFU; DAP_SPI.data_buf[0] = 0xFFFFFFFFU;
DAP_SPI.data_buf[1] = 0xFFFFFFFFU; DAP_SPI.data_buf[1] = 0xFFFFFFFFU;
DAP_SPI.cmd.usr = 1; DAP_SPI.cmd.usr = 1;
while (DAP_SPI.cmd.usr); while (DAP_SPI.cmd.usr);
} }

View File

@ -2,11 +2,13 @@
* @file spi_switch.c * @file spi_switch.c
* @author windowsair * @author windowsair
* @brief Switching between SPI mode and IO mode * @brief Switching between SPI mode and IO mode
* @version 0.1 * @change: 2020-11-25 first version
* @date 2020-11-25 * 2021-2-11 Transmission mode switching test passed
* * @version 0.2
* @copyright Copyright (c) 2020 * @date 2021-2-11
* *
* @copyright Copyright (c) 2021
*
*/ */
#include <stdbool.h> #include <stdbool.h>
@ -31,7 +33,7 @@ typedef enum {
/** /**
* @brief Initialize on first use * @brief Initialize on first use
* *
*/ */
void DAP_SPI_Init() void DAP_SPI_Init()
{ {
@ -59,7 +61,7 @@ void DAP_SPI_Init()
DAP_SPI.ctrl2.mosi_delay_num = 0; DAP_SPI.ctrl2.mosi_delay_num = 0;
DAP_SPI.ctrl2.miso_delay_num = 0; DAP_SPI.ctrl2.miso_delay_num = 0;
// DIO & QIO SPI disable // DIO & QIO SPI disable
DAP_SPI.user.fwrite_dual = false; DAP_SPI.user.fwrite_dual = false;
DAP_SPI.user.fwrite_quad = false; DAP_SPI.user.fwrite_quad = false;
DAP_SPI.user.fwrite_dio = false; DAP_SPI.user.fwrite_dio = false;
@ -69,14 +71,14 @@ void DAP_SPI_Init()
DAP_SPI.ctrl.fread_dio = false; DAP_SPI.ctrl.fread_dio = false;
DAP_SPI.ctrl.fread_qio = false; DAP_SPI.ctrl.fread_qio = false;
DAP_SPI.ctrl.fastrd_mode = true; DAP_SPI.ctrl.fastrd_mode = true;
// Enable soft reset // Enable soft reset
DAP_SPI.slave.sync_reset = true; DAP_SPI.slave.sync_reset = true;
// Set the clock polarity and phase CPOL = CPHA = 0 // Set the clock polarity and phase CPOL = CPHA = 0
DAP_SPI.pin.ck_idle_edge = 1; // HIGH while idle DAP_SPI.pin.ck_idle_edge = 1; // HIGH while idle
DAP_SPI.user.ck_out_edge = 0; DAP_SPI.user.ck_out_edge = 0;
// Set data bit order // Set data bit order
DAP_SPI.ctrl.wr_bit_order = 1; // SWD -> LSB DAP_SPI.ctrl.wr_bit_order = 1; // SWD -> LSB
@ -88,7 +90,7 @@ void DAP_SPI_Init()
// Set dummy // Set dummy
DAP_SPI.user.usr_dummy = 0; DAP_SPI.user.usr_dummy = 0;
// Initialize HSPI IO // Initialize HSPI IO
gpio_pin_reg_t pin_reg; gpio_pin_reg_t pin_reg;
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, FUNC_HSPI_CLK); // GPIO14 is SPI CLK pin (Clock) PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, FUNC_HSPI_CLK); // GPIO14 is SPI CLK pin (Clock)
@ -96,10 +98,10 @@ void DAP_SPI_Init()
pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(14)); pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(14));
pin_reg.pullup = 1; pin_reg.pullup = 1;
WRITE_PERI_REG(GPIO_PIN_REG(14), pin_reg.val); WRITE_PERI_REG(GPIO_PIN_REG(14), pin_reg.val);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_HSPID_MOSI); // GPIO13 is SPI MOSI pin (Master Data Out) PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_HSPID_MOSI); // GPIO13 is SPI MOSI pin (Master Data Out)
GPIO.enable_w1ts |= (0x1 << 13); GPIO.enable_w1ts |= (0x1 << 13);
GPIO.pin[13].driver = 0; // PP Output or OD output GPIO.pin[13].driver = 0; // PP Output or OD output
pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(13)); pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(13));
pin_reg.pullup = 0; pin_reg.pullup = 0;
WRITE_PERI_REG(GPIO_PIN_REG(13), pin_reg.val); WRITE_PERI_REG(GPIO_PIN_REG(13), pin_reg.val);
@ -110,6 +112,8 @@ void DAP_SPI_Init()
pin_reg.pullup = 0; pin_reg.pullup = 0;
WRITE_PERI_REG(GPIO_PIN_REG(12), pin_reg.val); WRITE_PERI_REG(GPIO_PIN_REG(12), pin_reg.val);
// Set spi clk div // Set spi clk div
CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_CONF_U, SPI1_CLK_EQU_SYS_CLK); CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_CONF_U, SPI1_CLK_EQU_SYS_CLK);
@ -124,35 +128,53 @@ void DAP_SPI_Init()
DAP_SPI.user.usr_addr = 0; DAP_SPI.user.usr_addr = 0;
} }
/**
* @brief Switch to GPIO
* Note: You may be able to pull the pin high in SPI mode, though you cannot set it to LOW
*/
__FORCEINLINE void DAP_SPI_Deinit()
{
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, FUNC_GPIO14);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13); // MOSI
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12); // MISO
// disable MISO output connect
GPIO.enable_w1tc |= (0x1 << 12);
gpio_pin_reg_t pin_reg;
GPIO.enable_w1ts |= (0x1 << 13);
GPIO.pin[13].driver = 1; // OD output
pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(13));
pin_reg.pullup = 0;
WRITE_PERI_REG(GPIO_PIN_REG(13), pin_reg.val);
}
/** /**
* @brief Use SPI acclerate * @brief Use SPI acclerate
* *
*/ */
void DAP_SPI_Enable() void DAP_SPI_Enable()
{ {
// may be unuse
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_HSPID_MOSI); // GPIO13 is SPI MOSI pin (Master Data Out) PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_HSPID_MOSI); // GPIO13 is SPI MOSI pin (Master Data Out)
} }
/** /**
* @brief Disable SPI * @brief Disable SPI
* * Drive capability not yet known
*/ */
__FORCEINLINE void DAP_SPI_Disable() __FORCEINLINE void DAP_SPI_Disable()
{ {
DAP_SPI_Deinit(); ;
//CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_MTCK_U, (PERIPHS_IO_MUX_FUNC << PERIPHS_IO_MUX_FUNC_S));
// may be unuse
// gpio_pin_reg_t pin_reg;
// GPIO.enable_w1ts |= (0x1 << 13);
// GPIO.pin[13].driver = 0; // OD Output
// pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(13));
// pin_reg.pullup = 1;
// WRITE_PERI_REG(GPIO_PIN_REG(13), pin_reg.val);
} }
__FORCEINLINE void DAP_SPI_Deinit()
{
CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_MTCK_U, (PERIPHS_IO_MUX_FUNC << PERIPHS_IO_MUX_FUNC_S));
// may be unuse
gpio_pin_reg_t pin_reg;
GPIO.enable_w1ts |= (0x1 << 13);
GPIO.pin[13].driver = 0; // OD Output
pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(13));
pin_reg.pullup = 1;
WRITE_PERI_REG(GPIO_PIN_REG(13), pin_reg.val);
}