hold_was_on = ishold??

本文介绍了MATLAB中两种绘图模式:增加模式和替换模式。详细讲解了如何使用hold on/off命令来控制绘图行为,并提供了实用代码示例,确保绘图过程中hold状态的一致性。
在matlab里面画图的时候,有两种模式:
(1)增加模式:保持现有的图,继续画;可以使用hold on命令,进入这种模式;
(2)替换模式:清空现有的图,重新画;可以使用hold off命令,进入这种模式。
如果是hold on状态,你先画一条横线,再画一条竖线,那么最终的结果是一横一竖两条线(横线之后增加了竖线);如果是hold off状态,你先画一条横线,再画一条竖线,那么最终的结果是一条竖线(竖线替换了横线)。
line(corners(1,:), corners(2,:), varargin{:}); %line([X1 X2 X3...],[Y1 Y2 Y3...],S); %点A(X1,Y1)和点B(X2 Y2)之间,(X2,Y2)和(X3 Y3)之间画一条直线...S为其它属性 
% patch(corners(1,:), corners(2,:), 'y', ...
%       'FaceAlpha',0, 'LineWidth',1.5, varargin{:});

center = mean(corners(:,1:4),2); %取四个顶点x坐标和y坐标各自的平均值作为center的坐标
hold_was_on = ishold; <pre id="best-content-1465705295" class="best-text mb-10" style="min-height: 55px;"><span style="font-size:18px;"></span><pre name="code" class="plain">%在画图之前,检测并记住hold状态,保存在变量hold_was_on之中。其中ishold是一个内置函数,可以返回当前的hold状态。
hold on; plot(center(1),center(2),varargin{:}); %画出中心点if (~hold_was_on) hold off; end %在画图之后,根据之前记录的结果,恢复之前的hold状态。
 

在新的plot之前,使用hold on;命令,意思是在原有的图上继续画。但是这样做,太 简单粗暴了,改变了画图的方式。如果有一天,你的同事或者同学拿到了你的代码,并且要进行修改。在没有细看的情况下,他把你这段代码插入到一段需要保持hold off状态的代码之中,就难免会发生错误。因此,最好能够在画图时,保持hold状态。因此,在画图之前,检测并记住hold状态,保存在变量hold_was_on之中。hold_was_on = ishold;其中ishold是一个内置函数,可以返回当前的hold状态。在画图之后,根据之前记录的结果,恢复之前的hold状态。if (~hold_was_on) hold off; end

                
这是我的button.h和button.c文件 /** * @File: flexible_button.h * @Author: MurphyZhao * @Date: 2018-09-29 * * Copyright (c) 2018-2019 MurphyZhao <d2014zjt@163.com> * https://github.com/murphyzhao * All rights reserved. * License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Change logs: * Date Author Notes * 2018-09-29 MurphyZhao First add * 2019-08-02 MurphyZhao Migrate code to github.com/murphyzhao account * 2019-12-26 MurphyZhao Refactor code and implement multiple clicks * */ #ifndef __BUTTON_H__ #define __BUTTON_H__ #include "stdint.h" #include "key_app.h" #include "KEY.h" #define FLEX_BTN_SCAN_FREQ_HZ 50 // How often flex_button_scan () is called #define FLEX_MS_TO_SCAN_CNT(ms) (ms / (1000 / FLEX_BTN_SCAN_FREQ_HZ)) /* Multiple clicks interval, default 300ms */ #define MAX_MULTIPLE_CLICKS_INTERVAL (FLEX_MS_TO_SCAN_CNT(300)) /** * @brief 按钮事件枚举类型 * * 定义了各种按钮触发事件类型,包括: * - 按下(FLEX_BTN_PRESS_DOWN) * - 单击(FLEX_BTN_PRESS_CLICK) * - 双击(FLEX_BTN_PRESS_DOUBLE_CLICK) * - 重复点击(FLEX_BTN_PRESS_REPEAT_CLICK) * - 短按开始(FLEX_BTN_PRESS_SHORT_START) * - 短按抬起(FLEX_BTN_PRESS_SHORT_UP) * - 长按开始(FLEX_BTN_PRESS_LONG_START) * - 长按抬起(FLEX_BTN_PRESS_LONG_UP) * - 长按保持(FLEX_BTN_PRESS_LONG_HOLD) * - 长按保持后抬起(FLEX_BTN_PRESS_LONG_HOLD_UP) * - 最大值(FLEX_BTN_PRESS_MAX) * - 无事件(FLEX_BTN_PRESS_NONE) */ typedef enum { FLEX_BTN_PRESS_DOWN = 0, FLEX_BTN_PRESS_CLICK, FLEX_BTN_PRESS_DOUBLE_CLICK, FLEX_BTN_PRESS_REPEAT_CLICK, FLEX_BTN_PRESS_SHORT_START, FLEX_BTN_PRESS_SHORT_UP, FLEX_BTN_PRESS_LONG_START, FLEX_BTN_PRESS_LONG_UP, FLEX_BTN_PRESS_LONG_HOLD, FLEX_BTN_PRESS_LONG_HOLD_UP, FLEX_BTN_PRESS_MAX, FLEX_BTN_PRESS_NONE, } flex_button_event_t; /** * flex_button_t * * @brief Button data structure * Below are members that need to user init before scan. * * @member next * Internal use. * One-way linked list, pointing to the next button. * * @member usr_button_read * User function is used to read button vaule. * * @member cb * Button event callback function. * * @member scan_cnt * Internal use, user read-only. * Number of scans, counted when the button is pressed, plus one per scan cycle. * * @member click_cnt * Internal use, user read-only. * Number of button clicks * * @member max_multiple_clicks_interval * Multiple click interval. Default 'MAX_MULTIPLE_CLICKS_INTERVAL'. * Need to use FLEX_MS_TO_SCAN_CNT to convert milliseconds into scan cnts. * * @member debounce_tick * Debounce. Not used yet. * Need to use FLEX_MS_TO_SCAN_CNT to convert milliseconds into scan cnts. * * @member short_press_start_tick * Short press start time. Requires user configuration. * Need to use FLEX_MS_TO_SCAN_CNT to convert milliseconds into scan cnts. * * @member long_press_start_tick * Long press start time. Requires user configuration. * Need to use FLEX_MS_TO_SCAN_CNT to convert milliseconds into scan cnts. * * @member long_hold_start_tick * Long hold press start time. Requires user configuration. * * @member id * Button id. Requires user configuration. * When multiple buttons use the same button callback function, * they are used to distinguish the buttons. * Each button id must be unique. * * @member pressed_logic_level * Requires user configuration. * The logic level of the button pressed, each bit represents a button. * * @member event * Internal use, users can call 'flex_button_event_read' to get current button event. * Used to record the current button event. * * @member status * Internal use, user unavailable. * Used to record the current state of buttons. * */ typedef struct flex_button { struct flex_button* next; uint8_t (*usr_button_read)(void *); flex_button_response_callback cb; uint16_t scan_cnt; uint16_t click_cnt; uint16_t max_multiple_clicks_interval; uint16_t debounce_tick; uint16_t short_press_start_tick; uint16_t long_press_start_tick; uint16_t long_hold_start_tick; uint8_t id; uint8_t pressed_logic_level : 1; uint8_t event : 4; uint8_t status : 3; } flex_button_t; #ifdef __cplusplus extern "C" { #endif int32_t flex_button_register(flex_button_t *button); flex_button_event_t flex_button_event_read(flex_button_t* button); uint8_t flex_button_scan(void); void user_button_init(void); #ifdef __cplusplus } #endif #endif /* __FLEXIBLE_BUTTON_H__ */ /** * @File: flexible_button.c * @Author: MurphyZhao * @Date: 2018-09-29 * * Copyright (c) 2018-2019 MurphyZhao <d2014zjt@163.com> * https://github.com/murphyzhao * All rights reserved. * License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Change logs: * Date Author Notes * 2018-09-29 MurphyZhao First add * 2019-08-02 MurphyZhao Migrate code to github.com/murphyzhao account * 2019-12-26 MurphyZhao Refactor code and implement multiple clicks * */ #include "button.h" #include "KEY.h" #include "string.h" #include "key_app.h" typedef enum { USER_BUTTON_UP = 0, // 对应 IoT Board 开发板的 PIN_KEY0 USER_BUTTON_LEFT, // 对应 IoT Board 开发板的 PIN_KEY1 USER_BUTTON_RIGHT, // 对应 IoT Board 开发板的 PIN_KEY2 USER_BUTTON_DOWN, USER_BUTTON_MID, // 对应 IoT Board 开发板的 PIN_WK_UP USER_BUTTON_MAX } user_button_t; static flex_button_t user_button[USER_BUTTON_MAX]; static uint8_t common_btn_read(void *arg) { uint8_t value = 0; flex_button_t *btn = (flex_button_t *)arg; switch (btn->id) { case USER_BUTTON_UP: value = key_scan().up; break; case USER_BUTTON_LEFT: value = key_scan().left; break; case USER_BUTTON_RIGHT: value =key_scan().right; break; case USER_BUTTON_DOWN: value = key_scan().down; break; case USER_BUTTON_MID: value = key_scan().mid; break; } return value; } // 配置项 说明 // id 按键编号 // usr_button_read 设置按键读值回调函数 // cb 设置按键事件回调函数 // pressed_logic_level 设置按键按下时的逻辑电平 // short_press_start_tick 短按起始 tick,使用 FLEX_MS_TO_SCAN_CNT 宏转化为扫描次数 // long_press_start_tick 长按起始 tick,使用 FLEX_MS_TO_SCAN_CNT 宏转化为扫描次数 // long_hold_start_tick 超长按起始 tick,使用 FLEX_MS_TO_SCAN_CNT 宏转化为扫描次数 // 注意,short_press_start_tick、long_press_start_tick 和 long_hold_start_tick 必须使用 FLEX_MS_TO_SCAN_CNT 将毫秒时间转化为扫描次数。 // user_button[i].short_press_start_tick = FLEX_MS_TO_SCAN_CNT(1500); 表示按键按下开始计时,1500 ms 后按键依旧是按下状态的话,就断定为短按开始。 //--------------------------------------------------改到这里了----------------------------- void user_button_init(void) { int i; memset(&user_button[0], 0x0, sizeof(user_button)); user_button[USER_BUTTON_UP].cb = up_btn_evt_cb; user_button[USER_BUTTON_LEFT].cb = left_btn_evt_cb; user_button[USER_BUTTON_RIGHT].cb = right_btn_evt_cb; user_button[USER_BUTTON_DOWN].cb = down_btn_evt_cb; user_button[USER_BUTTON_MID].cb = mid_btn_evt_cb; for (i = 0; i < USER_BUTTON_MAX; i ++) { user_button[i].id = i; user_button[i].usr_button_read = common_btn_read; user_button[i].pressed_logic_level = 0; user_button[i].short_press_start_tick = FLEX_MS_TO_SCAN_CNT(1500); user_button[i].long_press_start_tick = FLEX_MS_TO_SCAN_CNT(3000); user_button[i].long_hold_start_tick = FLEX_MS_TO_SCAN_CNT(4500); flex_button_register(&user_button[i]); } } #ifndef NULL #define NULL 0 #endif #define EVENT_SET_AND_EXEC_CB(btn, evt) \ do \ { \ btn->event = evt; \ if(btn->cb) \ btn->cb((flex_button_t*)btn); \ } while(0) /** * BTN_IS_PRESSED * * 1: is pressed * 0: is not pressed */ #define BTN_IS_PRESSED(i) (g_btn_status_reg & (1 << i)) enum FLEX_BTN_STAGE { FLEX_BTN_STAGE_DEFAULT = 0, FLEX_BTN_STAGE_DOWN = 1, FLEX_BTN_STAGE_MULTIPLE_CLICK = 2 }; typedef uint32_t btn_type_t; static flex_button_t *btn_head = NULL; /** * g_logic_level * * The logic level of the button pressed, * Each bit represents a button. * * First registered button, the logic level of the button pressed is * at the low bit of g_logic_level. */ btn_type_t g_logic_level = (btn_type_t)0; /** * g_btn_status_reg * * The status register of all button, each bit records the pressing state of a button. * * First registered button, the pressing state of the button is * at the low bit of g_btn_status_reg. */ btn_type_t g_btn_status_reg = (btn_type_t)0; static uint8_t button_cnt = 0; /** * @brief Register a user button * * @param button: button structure instance * @return Number of keys that have been registered, or -1 when error */ int32_t flex_button_register(flex_button_t *button) { flex_button_t *curr = btn_head; if (!button || (button_cnt > sizeof(btn_type_t) * 8)) { return -1; } while (curr) { if(curr == button) { return -1; /* already exist. */ } curr = curr->next; } /** * First registered button is at the end of the 'linked list'. * btn_head points to the head of the 'linked list'. */ button->next = btn_head; button->status = FLEX_BTN_STAGE_DEFAULT; button->event = FLEX_BTN_PRESS_NONE; button->scan_cnt = 0; button->click_cnt = 0; button->max_multiple_clicks_interval = MAX_MULTIPLE_CLICKS_INTERVAL; btn_head = button; /** * First registered button, the logic level of the button pressed is * at the low bit of g_logic_level. */ g_logic_level |= (button->pressed_logic_level << button_cnt); button_cnt ++; return button_cnt; } /** * @brief Read all key values in one scan cycle * * @param void * @return none */ static void flex_button_read(void) { uint8_t i; flex_button_t* target; /* The button that was registered first, the button value is in the low position of raw_data */ btn_type_t raw_data = 0; for(target = btn_head, i = button_cnt - 1; (target != NULL) && (target->usr_button_read != NULL); target = target->next, i--) { raw_data = raw_data | ((target->usr_button_read)(target) << i); } g_btn_status_reg = (~raw_data) ^ g_logic_level; } /** * @brief Handle all key events in one scan cycle. * Must be used after 'flex_button_read' API * * @param void * @return Activated button count */ static uint8_t flex_button_process(void) { uint8_t i; uint8_t active_btn_cnt = 0; flex_button_t* target; for (target = btn_head, i = button_cnt - 1; target != NULL; target = target->next, i--) { if (target->status > FLEX_BTN_STAGE_DEFAULT) { target->scan_cnt ++; if (target->scan_cnt >= ((1 << (sizeof(target->scan_cnt) * 8)) - 1)) { target->scan_cnt = target->long_hold_start_tick; } } switch (target->status) { case FLEX_BTN_STAGE_DEFAULT: /* stage: default(button up) */ if (BTN_IS_PRESSED(i)) /* is pressed */ { target->scan_cnt = 0; target->click_cnt = 0; EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_DOWN); /* swtich to button down stage */ target->status = FLEX_BTN_STAGE_DOWN; } else { target->event = FLEX_BTN_PRESS_NONE; } break; case FLEX_BTN_STAGE_DOWN: /* stage: button down */ if (BTN_IS_PRESSED(i)) /* is pressed */ { if (target->click_cnt > 0) /* multiple click */ { if (target->scan_cnt > target->max_multiple_clicks_interval) { EVENT_SET_AND_EXEC_CB(target, target->click_cnt < FLEX_BTN_PRESS_REPEAT_CLICK ? target->click_cnt : FLEX_BTN_PRESS_REPEAT_CLICK); /* swtich to button down stage */ target->status = FLEX_BTN_STAGE_DOWN; target->scan_cnt = 0; target->click_cnt = 0; } } else if (target->scan_cnt >= target->long_hold_start_tick) { if (target->event != FLEX_BTN_PRESS_LONG_HOLD) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_LONG_HOLD); } } else if (target->scan_cnt >= target->long_press_start_tick) { if (target->event != FLEX_BTN_PRESS_LONG_START) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_LONG_START); } } else if (target->scan_cnt >= target->short_press_start_tick) { if (target->event != FLEX_BTN_PRESS_SHORT_START) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_SHORT_START); } } } else /* button up */ { if (target->scan_cnt >= target->long_hold_start_tick) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_LONG_HOLD_UP); target->status = FLEX_BTN_STAGE_DEFAULT; } else if (target->scan_cnt >= target->long_press_start_tick) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_LONG_UP); target->status = FLEX_BTN_STAGE_DEFAULT; } else if (target->scan_cnt >= target->short_press_start_tick) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_SHORT_UP); target->status = FLEX_BTN_STAGE_DEFAULT; } else { /* swtich to multiple click stage */ target->status = FLEX_BTN_STAGE_MULTIPLE_CLICK; target->click_cnt ++; } } break; case FLEX_BTN_STAGE_MULTIPLE_CLICK: /* stage: multiple click */ if (BTN_IS_PRESSED(i)) /* is pressed */ { /* swtich to button down stage */ target->status = FLEX_BTN_STAGE_DOWN; target->scan_cnt = 0; } else { if (target->scan_cnt > target->max_multiple_clicks_interval) { EVENT_SET_AND_EXEC_CB(target, target->click_cnt < FLEX_BTN_PRESS_REPEAT_CLICK ? target->click_cnt : FLEX_BTN_PRESS_REPEAT_CLICK); /* swtich to default stage */ target->status = FLEX_BTN_STAGE_DEFAULT; } } break; } if (target->status > FLEX_BTN_STAGE_DEFAULT) { active_btn_cnt ++; } } return active_btn_cnt; } /** * flex_button_event_read * * @brief Get the button event of the specified button. * * @param button: button structure instance * @return button event */ flex_button_event_t flex_button_event_read(flex_button_t* button) { return (flex_button_event_t)(button->event); } /** * flex_button_scan * * @brief Start key scan. * Need to be called cyclically within the specified period. * Sample cycle: 5 - 20ms * * @param void * @return Activated button count */ uint8_t flex_button_scan(void) { flex_button_read(); return flex_button_process(); }
07-13
“”"Computation graph function and utilities By linking nodes together, one creates a computation graph representing a function, and one can use backpropagation to easily compute the gradient of the graph output with respect all input values. However, when doing machine learning, different nodes of the computation graph maybe treated differently and have special meaning. For example, if we represent a linear function in a computation graph, we will want the gradient w.r.t. the node representing the parameter vector, we’ll frequently want to access the node that is the linear function, since that is our predictions, but we’ll also need access to the graph output node, since that contains the objective function value. In the class ComputationGraphFunction below, we create a wrapper around a computation graph to handle many of the standard things we need to do in ML. Once graph is constructed, in the sense of constructing the nodes and linking them together, we can construct a ComputationGraphFunction below by passing the nodes in different lists, specifying whether a node is an input, outcome (i.e. label or response), parameter, prediction, or objective node. [Note that not all nodes of the graph will be one of these types. The nodes that are not explicitly passed in one of these lists are still accessible, since they are linked to other nodes.] This computation graph framework was designed and implemented by Philipp Meerkamp, Pierre Garapon, and David Rosenberg. License: Creative Commons Attribution 4.0 International License “”" import numpy as np class ComputationGraphFunction: def init(self, inputs, outcomes, parameters, prediction, objective): “”" Parameters: inputs: list of ValueNode objects containing inputs (in the ML sense) outcomes: list of ValueNode objects containing outcomes (in the ML sense) parameters: list of ValueNode objects containing values we will optimize over prediction: node whose ‘out’ variable contains our prediction objective: node containing the objective for which we compute the gradient “”" self.inputs = inputs self.outcomes = outcomes self.parameters = parameters self.prediction = prediction self.objective = objective # Create name to node lookup, so users can just supply node_name to set parameters self.name_to_node = {} self.name_to_node[self.prediction.node_name] = self.prediction self.name_to_node[self.objective.node_name] = self.objective for node in self.inputs + self.outcomes + self.parameters: self.name_to_node[node.node_name] = node # Precompute the topological and reverse topological sort of the nodes self.objective_node_list_forward = sort_topological(self.objective) self.objective_node_list_backward = sort_topological(self.objective) self.objective_node_list_backward.reverse() self.prediction_node_list_forward = sort_topological(self.prediction) def __set_values__(self, node_values): for node_name in node_values: node = self.name_to_node[node_name] node.out = node_values[node_name] def set_parameters(self, parameter_values): self.__set_values__(parameter_values) def increment_parameters(self, parameter_steps): for node_name in parameter_steps: node = self.name_to_node[node_name] node.out += parameter_steps[node_name] def get_objective(self, input_values, outcome_values): self.__set_values__(input_values) self.__set_values__(outcome_values) obj = forward_graph(self.objective, node_list=self.objective_node_list_forward) return obj def get_gradients(self, input_values, outcome_values): obj = self.get_objective(input_values, outcome_values) #need forward pass anyway #print("backward node list: ",self.objective_node_list_backward) backward_graph(self.objective, node_list=self.objective_node_list_backward) parameter_gradients = {} for node in self.parameters: parameter_gradients[node.node_name] = node.d_out return obj, parameter_gradients def get_prediction(self, input_values): self.__set_values__(input_values) pred = forward_graph(self.prediction, node_list=self.prediction_node_list_forward) return pred Computation graph utilities def sort_topological(sink): “”“Returns a list of the sink node and all its ancestors in topologically sorted order. Subgraph of these nodes must form a DAG.”“” L = [] # Empty list that will contain the sorted nodes T = set() # Set of temporarily marked nodes P = set() # Set of permanently marked nodes def visit(node): if node in P: return if node in T: raise 'Your graph is not a DAG!' T.add(node) # mark node temporarily for predecessor in node.get_predecessors(): visit(predecessor) P.add(node) # mark node permanently L.append(node) visit(sink) return L def forward_graph(graph_output_node, node_list=None): # If node_list is not None, it should be sort_topological(graph_output_node) if node_list is None: node_list = sort_topological(graph_output_node) for node in node_list: out = node.forward() return out def backward_graph(graph_output_node, node_list=None): “”" If node_list is not None, it should be the reverse of sort_topological(graph_output_node). Assumes that forward_graph has already been called on graph_output_node. Sets d_out of each node to the appropriate derivative. “”" if node_list is None: node_list = sort_topological(graph_output_node) node_list.reverse() graph_output_node.d_out = np.array(1) # Derivative of graph output w.r.t. itself is 1 for node in node_list: node.backward() “”" 计算图节点类型 节点必须实现以下方法: init:初始化节点 forward:反向传播的第1步,从前置节点获取输出,更新自身输出,并将梯度设为零 backward:反向传播的第2步,假设已进行前向传播并调用了后续节点的backward方法,计算图输出关于节点输入的导数,将这些导数加到输入节点的d_out数组中 get_predecessors:返回节点的父节点列表 节点必须具有以下属性: node_name:节点名称(字符串) out:节点输出 d_out:图输出关于节点输出的导数 “”" import numpy as np class ValueNode(object): “”“计算图中没有输入的节点,仅持有一个值”“” def init(self, node_name): self.node_name = node_name self.out = None self.d_out = None def forward(self): self.d_out = np.zeros(self.out.shape) return self.out def backward(self): pass def get_predecessors(self): return [] class VectorScalarAffineNode(object): “”“计算一个将向量映射到标量的仿射函数的节点”“” def init(self, x, w, b, node_name): “”" 参数: x: 节点,其 x.out 是一个一维的 numpy 数组 w: 节点,其 w.out 是一个与 x.out 相同大小的一维 numpy 数组 b: 节点,其 b.out 是一个 numpy 标量(即 0 维数组) node_name: 节点的名称(字符串) “”" self.node_name = node_name self.out = None self.d_out = None self.x = x self.w = w self.b = b def forward(self): self.out = np.dot(self.x.out, self.w.out) + self.b.out self.d_out = np.zeros(self.out.shape) return self.out def backward(self): d_x = self.d_out * self.w.out d_w = self.d_out * self.x.out d_b = self.d_out self.x.d_out += d_x self.w.d_out += d_w self.b.d_out += d_b def get_predecessors(self): return [self.x, self.w, self.b] class SquaredL2DistanceNode(object): “”" 计算两个数组之间的 L2 距离(平方差之和)的节点"“” def init(self, a, b, node_name): “”" 参数: a: 节点,其 a.out 是一个 numpy 数组 b: 节点,其 b.out 是一个与 a.out 形状相同的 numpy 数组 node_name: 节点的名称(字符串) “”" self.node_name = node_name self.out = None self.d_out = None self.a = a self.b = b self.a_minus_b = None def forward(self): self.a_minus_b = self.a.out - self.b.out self.out = np.sum(self.a_minus_b ** 2) self.d_out = np.zeros(self.out.shape) #此处为初始化,下同 return self.out def backward(self): d_a = self.d_out * 2 * self.a_minus_b d_b = -self.d_out * 2 * self.a_minus_b self.a.d_out += d_a self.b.d_out += d_b return self.d_out def get_predecessors(self): return [self.a, self.b] class L2NormPenaltyNode(object): “”" 计算 l2_reg * ||w||^2 节点,其中 l2_reg 为标量, w为向量"“” def init(self, l2_reg, w, node_name): “”" 参数: l2_reg: 一个大于等于0的标量值(不是节点) w: 节点,其 w.out 是一个 numpy 向量 node_name: 节点的名称(字符串) “”" self.node_name = node_name self.out = None self.d_out = None self.l2_reg = np.array(l2_reg) self.w = w def forward(self): self.out = self.l2_reg * np.sum(self.w.out ** 2) self.d_out = np.zeros(self.out.shape) return self.out def backward(self): d_w = self.d_out * 2 * self.l2_reg * self.w.out self.w.d_out += d_w return self.d_out def get_predecessors(self): return [self.w] ## TODO ## Hint:实现对应的forward,backword,get_predecessors接口即可 class SumNode(object): “”" 计算 a + b 的节点,其中 a 和 b 是 numpy 数组。“”" def init(self, a, b, node_name): “”" 参数: a: 节点,其 a.out 是一个 numpy 数组 b: 节点,其 b.out 是一个与 a 的形状相同的 numpy 数组 node_name: 节点的名称(一个字符串) “”" self.node_name = node_name self.out = None self.d_out = None self.a = a self.b = b def forward(self): self.out = self.a.out + self.b.out self.d_out = np.zeros(self.out.shape) return self.out def backward(self): d_a = self.d_out * np.ones_like(self.a.out) d_b = self.d_out * np.ones_like(self.b.out) self.a.d_out += d_a self.b.d_out += d_b return self.d_out def get_predecessors(self): return [self.a, self.b] ## TODO ## Hint:实现对应的forward,backword,get_predecessors接口即可 class AffineNode(object): “”“实现仿射变换 (W,x,b)–>Wx+b 的节点,其中 W 是一个矩阵,x 和 b 是向量 参数: W: 节点,其 W.out 是形状为 (m,d) 的 numpy 数组 x: 节点,其 x.out 是形状为 (d) 的 numpy 数组 b: 节点,其 b.out 是形状为 (m) 的 numpy 数组(即长度为 m 的向量) “”” def init(self, W, x, b, node_name): self.node_name = node_name self.out = None self.d_out = None self.W = W self.x = x self.b = b def forward(self): self.out = np.dot(self.W.out, self.x.out) + self.b.out self.d_out = np.zeros(self.out.shape) return self.out def backward(self): d_W = np.outer(self.d_out, self.x.out) d_x = np.dot(self.W.out.T, self.d_out) d_b = self.d_out.copy() self.W.d_out += d_W self.x.d_out += d_x self.b.d_out += d_b return self.d_out def get_predecessors(self): return [self.W, self.x, self.b] Hint:实现对应的forward,backword,get_predecessors接口即可 class TanhNode(object): “”“节点 tanh(a),其中 tanh 是对数组 a 逐元素应用的 参数: a: 节点,其 a.out 是一个 numpy 数组 “”” def init(self, a, node_name): self.node_name = node_name self.out = None self.d_out = None self.a = a def forward(self): self.out = np.tanh(self.a.out) self.d_out = np.zeros(self.out.shape) return self.out def backward(self): d_a = self.d_out * (1 - self.out ** 2) self.a.d_out += d_a return self.d_out def get_predecessors(self): return [self.a] TODO Hint:实现对应的forward,backword,get_predecessors接口即可 tanh函数直接调np.tanh即可 import matplotlib.pyplot as plt import setup_problem from sklearn.base import BaseEstimator, RegressorMixin import numpy as np import nodes import graph import plot_utils #import pdb #pdb.set_trace() #useful for debugging! class MLPRegression(BaseEstimator, RegressorMixin): “”" 基于计算图的MLP实现 “”" def init(self, num_hidden_units=10, step_size=.005, init_param_scale=0.01, max_num_epochs = 5000): self.num_hidden_units = num_hidden_units self.init_param_scale = 0.01 self.max_num_epochs = max_num_epochs self.step_size = step_size # 开始构建计算图 self.x = nodes.ValueNode(node_name="x") # to hold a vector input self.y = nodes.ValueNode(node_name="y") # to hold a scalar response ## TODO ## Hint: 根据PPT中给定的图,来构建MLP def fit(self, X, y): num_instances, num_ftrs = X.shape y = y.reshape(-1) ## TODO: 初始化参数(小的随机数——不是全部为0,以打破对称性) s = self.init_param_scale init_values = None ## TODO,在这里进行初始化,hint:调用np.random.standard_normal方法 self.graph.set_parameters(init_values) for epoch in range(self.max_num_epochs): shuffle = np.random.permutation(num_instances) epoch_obj_tot = 0.0 for j in shuffle: obj, grads = self.graph.get_gradients(input_values = {"x": X[j]}, outcome_values = {"y": y[j]}) #print(obj) epoch_obj_tot += obj # Take step in negative gradient direction steps = {} for param_name in grads: steps[param_name] = -self.step_size * grads[param_name] self.graph.increment_parameters(steps) if epoch % 50 == 0: train_loss = sum((y - self.predict(X,y)) **2)/num_instances print("Epoch ",epoch,": Ave objective=",epoch_obj_tot/num_instances," Ave training loss: ",train_loss) def predict(self, X, y=None): try: getattr(self, “graph”) except AttributeError: raise RuntimeError(“You must train classifer before predicting data!”) num_instances = X.shape[0] preds = np.zeros(num_instances) for j in range(num_instances): preds[j] = self.graph.get_prediction(input_values={"x":X[j]}) return preds def main(): #lasso_data_fname = “lasso_data.pickle” lasso_data_fname = r"C:\Users\XM_Ta\OneDrive\Desktop\1120223544-汤阳光-实验四\Question\lasso_data.pickle" x_train, y_train, x_val, y_val, target_fn, coefs_true, featurize = setup_problem.load_problem(lasso_data_fname) Generate features X_train = featurize(x_train) X_val = featurize(x_val) Let’s plot prediction functions and compare coefficients for several fits and the target function. pred_fns = [] x = np.sort(np.concatenate([np.arange(0,1,.001), x_train])) pred_fns.append({“name”: “Target Parameter Values (i.e. Bayes Optimal)”, “coefs”: coefs_true, “preds”: target_fn(x)}) estimator = MLPRegression(num_hidden_units=10, step_size=0.001, init_param_scale=.0005, max_num_epochs=5000) x_train_as_column_vector = x_train.reshape(x_train.shape[0],1) # fit expects a 2-dim array x_as_column_vector = x.reshape(x.shape[0],1) # fit expects a 2-dim array estimator.fit(x_train_as_column_vector, y_train) name = “MLP regression - no features” pred_fns.append({“name”:name, “preds”: estimator.predict(x_as_column_vector) }) X = featurize(x) estimator = MLPRegression(num_hidden_units=10, step_size=0.0005, init_param_scale=.01, max_num_epochs=500) estimator.fit(X_train, y_train) name = “MLP regression - with features” pred_fns.append({“name”:name, “preds”: estimator.predict(X) }) plot_utils.plot_prediction_functions(x, pred_fns, x_train, y_train, legend_loc=“best”) if name == ‘main’: main() 请帮我补充完整以上代码
05-29
以下是我修改后的代码,依然无法完成向S25FL256SAGNFI000写入数据,帮我检查bug #include "xparameters.h" /* SDK generated parameters */ #include "xqspips.h" /* QSPI device driver */ #include "xil_printf.h" #include "QSPI_flash.h" #include "FIFO.h" #include "G_variable.h" #include "PL_uart.h" #include "UDP_base.h" #include "config_PL.h" #include "sleep.h" /************************** Constant Definitions *****************************/ #define cfg_pkg_len 2000 /* * The following constants map to the XPAR parameters created in the * xparameters.h file. They are defined here such that a user can easily * change all the needed parameters in one place. */ #define QSPI_DEVICE_ID XPAR_XQSPIPS_0_DEVICE_ID /* * The following constants define the commands which may be sent to the FLASH * device. */ #define WRITE_STATUS_CMD 0x01 //#define WRITE_CMD 0x02 #define READ_CMD 0x03 #define WRITE_DISABLE_CMD 0x04 #define READ_STATUS_CMD 0x05 #define WRITE_ENABLE_CMD 0x06 #define FAST_READ_CMD 0x0B #define DUAL_READ_CMD 0x3B #define QUAD_READ_CMD 0x6B #define BULK_ERASE_CMD 0xC7 #define SEC_ERASE_CMD 0xD8 #define READ_ID 0x9F #define WRITE_4B_CMD 0x12 // 新增 4 字节页编程命令 #define SEC_ERASE_4B_CMD 0xDC // 4 字节扇区擦除命令 #define PAGE_SIZE 256 #define DATA_OFFSET 5 /* Start of Data for Read/Write */ #define WRITE_CMD 0x02 #define FLASH_BOOT_BIN_ADDRESS 0x0 /* * The following constants define the offsets within a FlashBuffer data * type for each kind of data. Note that the read data offset is not the * same as the write data because the QSPI driver is designed to allow full * duplex transfers such that the number of bytes received is the number * sent and received. */ #define COMMAND_OFFSET 0 /* FLASH instruction */ #define ADDRESS_1_OFFSET 1 /* MSB byte of address to read or write */ #define ADDRESS_2_OFFSET 2 /* Middle byte of address to read or write */ #define ADDRESS_3_OFFSET 3 /* LSB byte of address to read or write */ #define ADDRESS_4_OFFSET 4 /* LSB byte of address to read or write */ //#define DATA_OFFSET 5 /* Start of Data for Read/Write */ #define DUMMY_OFFSET 5 /* Dummy byte offset for fast, dual and quad * reads */ #define DUMMY_SIZE 1 /* Number of dummy bytes for fast, dual and * quad reads */ #define RD_ID_SIZE 4 /* Read ID command + 3 bytes ID response */ #define BULK_ERASE_SIZE 1 /* Bulk Erase command size */ #define SEC_ERASE_SIZE 5 /* Sector Erase command + Sector address */ /* 添加4字节读命令 */ #define QUAD_READ_4B_CMD 0x6C #define FAST_READ_4B_CMD 0x0C /* * The following constants specify the extra bytes which are sent to the * FLASH on the QSPI interface, that are not data, but control information * which includes the command and address */ #define OVERHEAD_SIZE 5 /* * The following constants specify the page size, sector size, and number of * pages and sectors for the FLASH. The page size specifies a max number of * bytes that can be written to the FLASH with a single transfer. */ #define SECTOR_SIZE 0x10000 #define NUM_SECTORS 0x200 //256Mb #define NUM_PAGES 0x20000 //256Mb /* Number of flash pages to be written.*/ #define PAGE_COUNT 16 /* Flash address to which data is to be written.*/ #define TEST_ADDRESS (250000000/8)//0x00055000 //4字节BOOT.bin长度,长度不包括头,但包括CRC #define BIN_HEAD_LEN 12 #define BIN_CRC_LEN 4 #define BOOT_BIN_SIZE (1024*1024*15) //8M #define UNIQUE_VALUE 0x05 /* * The following constants specify the max amount of data and the size of the * the buffer required to hold the data and overhead to transfer the data to * and from the FLASH. */ #define MAX_DATA (PAGE_COUNT * PAGE_SIZE) /**************************** Type Definitions *******************************/ /***************** Macros (Inline Functions) Definitions *********************/ /************************** Function Prototypes ******************************/ void FlashErase(XQspiPs *QspiPtr, u32 Address, u32 ByteCount); void FlashWrite(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command); void FlashRead(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command); int FlashReadID(void); void FlashQuadEnable(XQspiPs *QspiPtr); int QspiFlashPolledExample(XQspiPs *QspiInstancePtr, u16 QspiDeviceId,u8 write_en,u8 read_en); /************************** Variable Definitions *****************************/ /* * The instances to support the device drivers are global such that they * are initialized to zero each time the program runs. They could be local * but should at least be static so they are zeroed. */ XQspiPs my_QspiInstance; /* * The following variable allows a test value to be added to the values that * are written to the FLASH such that unique values can be generated to * guarantee the writes to the FLASH were successful */ int Test = 5; /* * The following variables are used to read and write to the flash and they * are global to avoid having large buffers on the stack */ u8 ReadBuffer[MAX_DATA + DATA_OFFSET + DUMMY_SIZE]; u8 flash_WriteBuffer[PAGE_SIZE + OVERHEAD_SIZE]; u8 user_WriteBuffer[(cfg_pkg_len/PAGE_SIZE + 1) * PAGE_SIZE]; u8 *BufferPtr; int8_t DEV_UID[8]; /*****************************************************************************/ /** * * Main function to call the QSPI Flash example. * * * @return XST_SUCCESS if successful, otherwise XST_FAILURE. * * @note None * ******************************************************************************/ // int main(void) // { // int Status; // xil_printf("QSPI FLASH Polled Example Test \r\n"); // /* Run the Qspi Interrupt example.*/ // Status = QspiFlashPolledExample(&my_QspiInstance, QSPI_DEVICE_ID); // if (Status != XST_SUCCESS) { // xil_printf("QSPI FLASH Polled Example Test Failed\r\n"); // return XST_FAILURE; // } // xil_printf("Successfully ran QSPI FLASH Polled Example Test\r\n"); // return XST_SUCCESS; // } // 新增函数:启用 4 字节地址模式 void FlashEnter4ByteMode(XQspiPs *QspiPtr) { u8 Enter4ByteModeCmd = 0xB7; // 进入 4 字节地址模式命令 XQspiPs_PolledTransfer(QspiPtr, &Enter4ByteModeCmd, NULL, 1); } void QSPI_flash_write(unsigned char *p,unsigned int len) { int Status; int i; for(i = 0;i < len;i ++) { user_WriteBuffer[i] = p[i]; } Status = QspiFlashPolledExample(&my_QspiInstance, QSPI_DEVICE_ID,1,0); if (Status != XST_SUCCESS) { //xil_printf("QSPI flash write Failed\r\n"); } } void QSPI_flash_read(unsigned char *p,unsigned int len) { int Status; int i; Status = QspiFlashPolledExample(&my_QspiInstance, QSPI_DEVICE_ID,0,1); if (Status != XST_SUCCESS) { //xil_printf("QSPI flash read Failed\r\n"); } else { for(i = 0;i < len;i ++) { p[i] = BufferPtr[i]; } //xil_printf("QSPI flash read successfull\r\n"); } } /*****************************************************************************/ /** * * The purpose of this function is to illustrate how to use the XQspiPs * device driver in polled mode. This function writes and reads data * from a serial FLASH. * * @param QspiInstancePtr is a pointer to the QSPIPS driver to use. * @param QspiDeviceId is the XPAR_<QSPIPS_instance>_DEVICE_ID value * from xparameters.h. * * @return XST_SUCCESS if successful, else XST_FAILURE. * * @note None. * *****************************************************************************/ int QspiFlashPolledExample(XQspiPs *QspiInstancePtr, u16 QspiDeviceId,u8 write_en,u8 read_en) { int Status; u8 UniqueValue; int Count; int Page; XQspiPs_Config *QspiConfig; int i; /* Initialize the QSPI driver so that it's ready to use*/ QspiConfig = XQspiPs_LookupConfig(QspiDeviceId); if (QspiConfig == NULL) { return XST_FAILURE; } Status = XQspiPs_CfgInitialize(QspiInstancePtr, QspiConfig, QspiConfig->BaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* Perform a self-test to check hardware build*/ Status = XQspiPs_SelfTest(QspiInstancePtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Initialize the write buffer for a pattern to write to the FLASH * and the read buffer to zero so it can be verified after the read, * the test value that is added to the unique value allows the value * to be changed in a debug environment to guarantee */ // for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < PAGE_SIZE; // Count++, UniqueValue++) { // flash_WriteBuffer[DATA_OFFSET + Count] = (u8)(UniqueValue + Test); // } memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); /* * Set Manual Start and Manual Chip select options and drive HOLD_B * pin high. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_MANUAL_START_OPTION | XQSPIPS_FORCE_SSELECT_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); /* Set the prescaler for QSPI clock*/ XQspiPs_SetClkPrescaler(QspiInstancePtr, XQSPIPS_CLK_PRESCALE_8); /* Assert the FLASH chip select.*/ XQspiPs_SetSlaveSelect(QspiInstancePtr); FlashReadID(); FlashEnter4ByteMode(QspiInstancePtr); // 新增:启用 4 字节地址模式 FlashQuadEnable(QspiInstancePtr); if(write_en) { /* Erase the flash.*/ FlashErase(QspiInstancePtr, TEST_ADDRESS, MAX_DATA); for (Page = 0; Page < (cfg_pkg_len + PAGE_SIZE - 1)/PAGE_SIZE; Page++) //PAGE_COUNT { for (Count = 0; Count < PAGE_SIZE; Count++) { if ((DATA_OFFSET + Count) < sizeof(flash_WriteBuffer)) { flash_WriteBuffer[DATA_OFFSET + Count] = user_WriteBuffer[Count + Page*PAGE_SIZE]; } } FlashWrite(QspiInstancePtr, (Page * PAGE_SIZE) + TEST_ADDRESS,PAGE_SIZE, WRITE_CMD); //cfg_pkg_len PAGE_SIZE } } /* * Read the contents of the FLASH from TEST_ADDRESS, using Normal Read * command. Change the prescaler as the READ command operates at a * lower frequency. */ // FlashRead(QspiInstancePtr, TEST_ADDRESS, MAX_DATA, READ_CMD); // // /* // * Setup a pointer to the start of the data that was read into the read // * buffer and verify the data read is the data that was written // */ // BufferPtr = &ReadBuffer[DATA_OFFSET]; // // for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; // Count++, UniqueValue++) { // if (BufferPtr[Count] != (u8)(UniqueValue + Test)) { // return XST_FAILURE; // } // } /* * Read the contents of the FLASH from TEST_ADDRESS, using Fast Read * command */ if(read_en) { memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); FlashRead(QspiInstancePtr, TEST_ADDRESS, MAX_DATA, FAST_READ_CMD); /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ BufferPtr = &ReadBuffer[DATA_OFFSET + DUMMY_SIZE]; } if(write_en && read_en) { for (i = 0; i < cfg_pkg_len; i ++) { if (BufferPtr[i] != user_WriteBuffer[i]) { return XST_FAILURE; } } } // /* // * Read the contents of the FLASH from TEST_ADDRESS, using Dual Read // * command // */ // memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); // FlashRead(QspiInstancePtr, TEST_ADDRESS, MAX_DATA, DUAL_READ_CMD); // // /* // * Setup a pointer to the start of the data that was read into the read // * buffer and verify the data read is the data that was written // */ // BufferPtr = &ReadBuffer[DATA_OFFSET + DUMMY_SIZE]; // // for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; // Count++, UniqueValue++) { // if (BufferPtr[Count] != (u8)(UniqueValue + Test)) { // return XST_FAILURE; // } // } // // /* // * Read the contents of the FLASH from TEST_ADDRESS, using Quad Read // * command // */ // memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); // FlashRead(QspiInstancePtr, TEST_ADDRESS, MAX_DATA, QUAD_READ_CMD); // // /* // * Setup a pointer to the start of the data that was read into the read // * buffer and verify the data read is the data that was written // */ // BufferPtr = &ReadBuffer[DATA_OFFSET + DUMMY_SIZE]; // // for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; // Count++, UniqueValue++) { // if (BufferPtr[Count] != (u8)(UniqueValue + Test)) { // return XST_FAILURE; // } // } // // /* // * Initialize the write buffer for a pattern to write to the FLASH // * and the read buffer to zero so it can be verified after the read, // * the test value that is added to the unique value allows the value // * to be changed in a debug environment to guarantee // */ // for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < PAGE_SIZE; // Count++, UniqueValue++) { // flash_WriteBuffer[DATA_OFFSET + Count] = (u8)(UniqueValue + Test); // } // memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); // // /* // * Set Auto Start and Manual Chip select options and drive HOLD_B // * pin high. // */ // XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_FORCE_SSELECT_OPTION | // XQSPIPS_HOLD_B_DRIVE_OPTION); // // /* Erase the flash.*/ // FlashErase(QspiInstancePtr, TEST_ADDRESS, MAX_DATA); // // /* // * Write the data in the write buffer to the serial FLASH a page at a // * time, starting from TEST_ADDRESS // */ // for (Page = 0; Page < PAGE_COUNT; Page++) { // FlashWrite(QspiInstancePtr, (Page * PAGE_SIZE) + TEST_ADDRESS, // PAGE_SIZE, WRITE_CMD); // } // // /* // * Read the contents of the FLASH from TEST_ADDRESS, using Normal Read // * command. Change the prescaler as the READ command operates at a // * lower frequency. // */ // FlashRead(QspiInstancePtr, TEST_ADDRESS, MAX_DATA, READ_CMD); // // /* // * Setup a pointer to the start of the data that was read into the read // * buffer and verify the data read is the data that was written // */ // BufferPtr = &ReadBuffer[DATA_OFFSET]; // // // for (i = 0; i < cfg_pkg_len; i ++) // { // if (BufferPtr[i] != user_WriteBuffer[i]) // { // return XST_FAILURE; // } // } // /* // * Read the contents of the FLASH from TEST_ADDRESS, using Fast Read // * command // */ // memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); // FlashRead(QspiInstancePtr, TEST_ADDRESS, MAX_DATA, FAST_READ_CMD); // /* // * Setup a pointer to the start of the data that was read into the read // * buffer and verify the data read is the data that was written // */ // BufferPtr = &ReadBuffer[DATA_OFFSET + DUMMY_SIZE]; // for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; // Count++, UniqueValue++) { // if (BufferPtr[Count] != (u8)(UniqueValue + Test)) { // return XST_FAILURE; // } // } // /* // * Read the contents of the FLASH from TEST_ADDRESS, using Dual Read // * command // */ // memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); // FlashRead(QspiInstancePtr, TEST_ADDRESS, MAX_DATA, DUAL_READ_CMD); // /* // * Setup a pointer to the start of the data that was read into the read // * buffer and verify the data read is the data that was written // */ // BufferPtr = &ReadBuffer[DATA_OFFSET + DUMMY_SIZE]; // for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; // Count++, UniqueValue++) { // if (BufferPtr[Count] != (u8)(UniqueValue + Test)) { // return XST_FAILURE; // } // } // /* // * Read the contents of the FLASH from TEST_ADDRESS, using Quad Read // * command // */ // memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); // FlashRead(QspiInstancePtr, TEST_ADDRESS, MAX_DATA, QUAD_READ_CMD); // /* // * Setup a pointer to the start of the data that was read into the read // * buffer and verify the data read is the data that was written // */ // BufferPtr = &ReadBuffer[DATA_OFFSET + DUMMY_SIZE]; // for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; // Count++, UniqueValue++) { // if (BufferPtr[Count] != (u8)(UniqueValue + Test)) { // return XST_FAILURE; // } // } return XST_SUCCESS; } /*****************************************************************************/ /** * * This function writes to the serial FLASH connected to the QSPI interface. * All the data put into the buffer must be in the same page of the device with * page boundaries being on 256 byte boundaries. * * @param QspiPtr is a pointer to the QSPI driver component to use. * @param Address contains the address to write data to in the FLASH. * @param ByteCount contains the number of bytes to write. * @param Command is the command used to write data to the flash. QSPI * device supports only Page Program command to write data to the * flash. * * @return None. * * @note None. * ******************************************************************************/ void FlashWrite(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command) { u8 WriteEnableCmd = WRITE_ENABLE_CMD; u8 ReadStatusCmd[] = { READ_STATUS_CMD, 0 }; u8 FlashStatus[2]; // 发送写使能 XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL, sizeof(WriteEnableCmd)); // 选择正确的写命令 (4字节/3字节) u8 actualCommand = (Address > 0xFFFFFF) ? WRITE_4B_CMD : Command; // 填充命令和地址 flash_WriteBuffer[COMMAND_OFFSET] = actualCommand; flash_WriteBuffer[ADDRESS_1_OFFSET] = (u8)((Address >> 24) & 0xFF); flash_WriteBuffer[ADDRESS_2_OFFSET] = (u8)((Address >> 16) & 0xFF); flash_WriteBuffer[ADDRESS_3_OFFSET] = (u8)((Address >> 8) & 0xFF); flash_WriteBuffer[ADDRESS_4_OFFSET] = (u8)(Address & 0xFF); // 计算实际传输长度 u32 headerSize = (actualCommand == WRITE_4B_CMD) ? 5 : 4; u32 TransferLength = headerSize + ByteCount; // 确保不超出缓冲区大小 if (TransferLength > sizeof(flash_WriteBuffer)) { TransferLength = sizeof(flash_WriteBuffer); } // 执行传输 XQspiPs_PolledTransfer(QspiPtr, flash_WriteBuffer, NULL, TransferLength); // 等待写入完成 do { XQspiPs_PolledTransfer(QspiPtr, ReadStatusCmd, FlashStatus, sizeof(ReadStatusCmd)); } while (FlashStatus[1] & 0x01); // 检查 BUSY 位 } /*****************************************************************************/ /** * * This function reads from the serial FLASH connected to the * QSPI interface. * * @param QspiPtr is a pointer to the QSPI driver component to use. * @param Address contains the address to read data from in the FLASH. * @param ByteCount contains the number of bytes to read. * @param Command is the command used to read data from the flash. QSPI * device supports one of the Read, Fast Read, Dual Read and Fast * Read commands to read data from the flash. * * @return None. * * @note None. * ******************************************************************************/ void FlashRead(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command) { // 添加命令转换逻辑 u8 actualCommand = Command; // 添加对所有读命令的转换 switch(Command) { case FAST_READ_CMD: actualCommand = FAST_READ_4B_CMD; break; case QUAD_READ_CMD: actualCommand = QUAD_READ_4B_CMD; break; case DUAL_READ_CMD: actualCommand = DUAL_READ_CMD; break; // 没有4B版本 case READ_CMD: actualCommand = READ_CMD; break; // 没有4B版本 default: actualCommand = Command; break; } /* * Setup the write command with the specified address and data for the * FLASH */ flash_WriteBuffer[COMMAND_OFFSET] = actualCommand; /* flash_WriteBuffer[ADDRESS_1_OFFSET] = (u8)((Address & 0xFF0000) >> 16); flash_WriteBuffer[ADDRESS_2_OFFSET] = (u8)((Address & 0xFF00) >> 8); flash_WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF); */ flash_WriteBuffer[ADDRESS_1_OFFSET] = (u8)((Address & 0xFF000000) >> 24); // 新增 flash_WriteBuffer[ADDRESS_2_OFFSET] = (u8)((Address & 0xFF0000) >> 16); flash_WriteBuffer[ADDRESS_3_OFFSET] = (u8)((Address & 0xFF00) >> 8); flash_WriteBuffer[ADDRESS_4_OFFSET] = (u8)(Address & 0xFF); // 修改 // 设置虚拟字节大小 u32 DummyBytes = 0; if (actualCommand == FAST_READ_4B_CMD || actualCommand == QUAD_READ_4B_CMD) { DummyBytes = DUMMY_SIZE; flash_WriteBuffer[DUMMY_OFFSET] = 0x00; // 必须设置虚拟字节值 } // 计算总传输长度 u32 TransferLength = OVERHEAD_SIZE + ByteCount + DummyBytes; // 确保不超出缓冲区大小 if (TransferLength > sizeof(ReadBuffer)) { TransferLength = sizeof(ReadBuffer); } /* * Send the read command to the FLASH to read the specified number * of bytes from the FLASH, send the read command and address and * receive the specified number of bytes of data in the data buffer */ XQspiPs_PolledTransfer(QspiPtr, flash_WriteBuffer, ReadBuffer,TransferLength); } /*****************************************************************************/ /** * * This function erases the sectors in the serial FLASH connected to the * QSPI interface. * * @param QspiPtr is a pointer to the QSPI driver component to use. * @param Address contains the address of the first sector which needs to * be erased. * @param ByteCount contains the total size to be erased. * * @return None. * * @note None. * ******************************************************************************/ void FlashErase(XQspiPs *QspiPtr, u32 Address, u32 ByteCount) { u8 WriteEnableCmd = { WRITE_ENABLE_CMD }; u8 ReadStatusCmd[] = { READ_STATUS_CMD, 0 }; /* must send 2 bytes */ u8 FlashStatus[2]; int Sector; /* * If erase size is same as the total size of the flash, use bulk erase * command */ if (ByteCount == (NUM_SECTORS * SECTOR_SIZE)) { /* * Send the write enable command to the FLASH so that it can be * written to, this needs to be sent as a separate transfer * before the erase */ XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL, sizeof(WriteEnableCmd)); /* Setup the bulk erase command*/ flash_WriteBuffer[COMMAND_OFFSET] = BULK_ERASE_CMD; /* * Send the bulk erase command; no receive buffer is specified * since there is nothing to receive */ XQspiPs_PolledTransfer(QspiPtr, flash_WriteBuffer, NULL, BULK_ERASE_SIZE); /* Wait for the erase command to the FLASH to be completed*/ while (1) { /* * Poll the status register of the device to determine * when it completes, by sending a read status command * and receiving the status byte */ XQspiPs_PolledTransfer(QspiPtr, ReadStatusCmd, FlashStatus, sizeof(ReadStatusCmd)); /* * If the status indicates the write is done, then stop * waiting; if a value of 0xFF in the status byte is * read from the device and this loop never exits, the * device slave select is possibly incorrect such that * the device status is not being read */ //FlashStatus[1] |= FlashStatus[0]; if ((FlashStatus[1] & 0x01) == 0) { break; } } return; } /* * If the erase size is less than the total size of the flash, use * sector erase command */ for (Sector = 0; Sector < ((ByteCount / SECTOR_SIZE) + 1); Sector++) { /* * Send the write enable command to the SEEPOM so that it can be * written to, this needs to be sent as a separate transfer * before the write */ XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL, sizeof(WriteEnableCmd)); /* * Setup the write command with the specified address and data * for the FLASH */ // 根据地址选择命令 u8 eraseCmd = (Address > 0xFFFFFF) ? SEC_ERASE_4B_CMD : SEC_ERASE_CMD; flash_WriteBuffer[COMMAND_OFFSET] = eraseCmd; //flash_WriteBuffer[COMMAND_OFFSET] = SEC_ERASE_CMD; /* flash_WriteBuffer[ADDRESS_1_OFFSET] = (u8)(Address >> 16); flash_WriteBuffer[ADDRESS_2_OFFSET] = (u8)(Address >> 8); flash_WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF); */ flash_WriteBuffer[ADDRESS_1_OFFSET] = (u8)((Address & 0xFF000000) >> 24); flash_WriteBuffer[ADDRESS_2_OFFSET] = (u8)((Address & 0xFF0000) >> 16); flash_WriteBuffer[ADDRESS_3_OFFSET] = (u8)((Address & 0xFF00) >> 8); flash_WriteBuffer[ADDRESS_4_OFFSET] = (u8)(Address & 0xFF); /* * Send the sector erase command and address; no receive buffer * is specified since there is nothing to receive */ XQspiPs_PolledTransfer(QspiPtr, flash_WriteBuffer, NULL, SEC_ERASE_SIZE); /* * Wait for the sector erse command to the * FLASH to be completed */ while (1) { /* * Poll the status register of the device to determine * when it completes, by sending a read status command * and receiving the status byte */ XQspiPs_PolledTransfer(QspiPtr, ReadStatusCmd, FlashStatus, sizeof(ReadStatusCmd)); /* * If the status indicates the write is done, then stop * waiting, if a value of 0xFF in the status byte is * read from the device and this loop never exits, the * device slave select is possibly incorrect such that * the device status is not being read */ //FlashStatus[1] |= FlashStatus[0]; if ((FlashStatus[0] & 0x01) == 0) { break; } } Address += SECTOR_SIZE; } } /*****************************************************************************/ /** * * This function reads serial FLASH ID connected to the SPI interface. * * * @return XST_SUCCESS if read id, otherwise XST_FAILURE. * * @note None. * ******************************************************************************/ int FlashReadID(void) { int Status; // 正确的退出 4 字节模式命令 u8 Exit4ByteModeCmd = 0xE9; // 根据 S25FL256S 数据手册 XQspiPs_PolledTransfer(&my_QspiInstance, &Exit4ByteModeCmd, NULL, 1); /* Read ID in Auto mode.*/ flash_WriteBuffer[COMMAND_OFFSET] = READ_ID; flash_WriteBuffer[ADDRESS_1_OFFSET] = 0x23; /* 3 dummy bytes */ flash_WriteBuffer[ADDRESS_2_OFFSET] = 0x08; flash_WriteBuffer[ADDRESS_3_OFFSET] = 0x09; Status = XQspiPs_PolledTransfer(&my_QspiInstance, flash_WriteBuffer, ReadBuffer, RD_ID_SIZE); if (Status != XST_SUCCESS) { return XST_FAILURE; } //xil_printf("FlashID=0x%x 0x%x 0x%x\n\r", ReadBuffer[1], ReadBuffer[2], // ReadBuffer[3]); // 重新进入4字节模式 FlashEnter4ByteMode(&my_QspiInstance); return XST_SUCCESS; } /* int FlashReadUID(void) { int Status; flash_WriteBuffer[COMMAND_OFFSET] = 0x4B; flash_WriteBuffer[ADDRESS_1_OFFSET] = 0x23; flash_WriteBuffer[ADDRESS_2_OFFSET] = 0x08; flash_WriteBuffer[ADDRESS_3_OFFSET] = 0x09; Status = XQspiPs_PolledTransfer(&my_QspiInstance,flash_WriteBuffer, ReadBuffer, 16); if (Status != XST_SUCCESS) { return XST_FAILURE; } DEV_UID[0] = ReadBuffer[5]; DEV_UID[1] = ReadBuffer[6]; DEV_UID[2] = ReadBuffer[7]; DEV_UID[3] = ReadBuffer[8]; DEV_UID[4] = ReadBuffer[9]; DEV_UID[5] = ReadBuffer[10]; DEV_UID[6] = ReadBuffer[11]; DEV_UID[7] = ReadBuffer[12]; //xil_printf("Flash Unique ID=0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n\r",ReadBuffer[5], ReadBuffer[6], ReadBuffer[7], ReadBuffer[8], ReadBuffer[9], ReadBuffer[10], ReadBuffer[11], ReadBuffer[12]); return XST_SUCCESS; } */ int FlashReadUID(void) { int Status; u8 cmdBuffer[5] = {0x4B, 0x00, 0x00, 0x00, 0x00}; // 命令 + 4字节地址 u8 response[13]; // 接收缓冲区 // 保存当前地址模式 u8 Exit4ByteModeCmd = 0xE9; XQspiPs_PolledTransfer(&my_QspiInstance, &Exit4ByteModeCmd, NULL, 1); // 发送读取UID命令 Status = XQspiPs_PolledTransfer(&my_QspiInstance, cmdBuffer, response, sizeof(cmdBuffer)); // 恢复4字节模式 u8 Enter4ByteModeCmd = 0xB7; XQspiPs_PolledTransfer(&my_QspiInstance, &Enter4ByteModeCmd, NULL, 1); if (Status != XST_SUCCESS) { //xil_printf("FlashReadUID: Transfer failed with status %d\r\n", Status); return XST_FAILURE; } // 验证响应(可选) if(response[0] != 0x4B) { //xil_printf("FlashReadUID: Invalid response header\r\n"); return XST_FAILURE; } // 提取唯一ID(字节5-12) for(int i=0; i<8; i++) { DEV_UID[i] = response[i+5]; } return XST_SUCCESS; } /*****************************************************************************/ /** * * This function enables quad mode in the serial flash connected to the * SPI interface. * * @param QspiPtr is a pointer to the QSPI driver component to use. * * @return None. * * @note None. * ******************************************************************************/ void FlashQuadEnable(XQspiPs *QspiPtr) { u8 WriteEnableCmd = WRITE_ENABLE_CMD; u8 ReadStatusCmd1[] = {0x05, 0}; // 读状态寄存器1 u8 ReadStatusCmd2[] = {0x35, 0}; // 读状态寄存器2 u8 WriteStatusCmd[] = {0x01, 0x00, 0x02}; // 写状态寄存器 (直接设置 QE 位) u8 FlashStatus[2]; // 读取状态寄存器2 XQspiPs_PolledTransfer(QspiPtr, ReadStatusCmd2, FlashStatus, sizeof(ReadStatusCmd2)); // 检查QE位(bit1)是否已设置 if ((FlashStatus[1] & 0x02) == 0) { // 修正索引为 [1] // 发送写使能 XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL, sizeof(WriteEnableCmd)); // 直接设置 QE 位 (bit1) WriteStatusCmd[2] = 0x02; // 状态寄存器2的QE位 // 写入状态寄存器 XQspiPs_PolledTransfer(QspiPtr, WriteStatusCmd, NULL, sizeof(WriteStatusCmd)); // 增加延迟确保写入完成 usleep(50000); // 50ms 延迟 // 等待写入完成 do { XQspiPs_PolledTransfer(QspiPtr, ReadStatusCmd1, FlashStatus, sizeof(ReadStatusCmd1)); } while (FlashStatus[1] & 0x01); // 检查 BUSY 位 } }
07-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值