Nguyên văn bởi nemesis21
Xem bài viết
Thông báo
Collapse
No announcement yet.
Project nhỏ: Bộ lọc số FIR thực hiện bằng FPGA
Collapse
This is a sticky topic.
X
X
-
Tôi nghĩ nếu bạn cá chép đang gặp vấn đề với mạch delay, những giai đoạn tất yếu trước đó đã được hoàn thành? Dù với project nhỏ, chúng ta vẫn nên làm theo trình tự để giảm thiểu vấn đề.
- Requirements / specs cho filter như thế nào? Có vài chỉ số được đưa ra, nhưng hình như thiếu sự liên kết giữa các chỉ số quan trọng. Dù với scalable design, chúng ta vẫn phải đặt ra performance bounds. Rất không nên nhảy vào coding trước khi establishing requirements / specs.
- Design cho filter như thế nào? Dựa vào requirements / specs, bạn đã chọn filter structure nào? Parallel, serial (single multiplier), hoặc semi-parallel? Nếu serial, mạch delay của bạn nên sử dụng RAM (hoặc registers và multiplexer để emulate RAM). Nếu parallel, mạch delay của bạn nên sử dụng registers. Bạn đã chọn structure / mạch delay nào? Bạn đã vẽ block diagram cho design của bạn? Generic design hay là target spefiic? Chẳng hạn như với DSP48 của Virtex-4, parallel design có thể hoàn toàn sử dụng intenal registers và routing của DSP48. Bạn đã diagram / model mạch delay của bạn?
- Giai đoạn viết VHDL nên là giai đoạn dễ dàng nhất.
Khuyến khích làm các project là một việc hay, nhưng tôi nghĩ rằng học về process và các trình tự tất yếu còn quan trọng hơn simulation output đối với những người mới.
Comment
-
Phần filter analysis / design không quá khó. Chỉ với vài dòng lệnh, bạn có thể generate filter coefficients và analyze frequency response như trong screen captures 01/02, so sánh 21/51/101 taps Hamming filters và 101 taps Boxcar filter.
Trong screen captures 03 / 04, zero-padded sine wave được filter qua 21-tap Hamming filter. Zero-padded data được dùng để chúng ta có thể dễ dàng thấy được effect của filter.
Phần FIR filter đơn giản chỉ có 3-4 dòng:
Code:for in range (len(x)) : delay_buf[1:len(filter_coeffs)] = delay_buf[0:len(filter_coeffs)-1] delay_buf[0] = x[i] y[i] = sum(delay_buf * filter_coeffs)
Code:delay_buf[1:len(filter_coeffs)] = delay_buf[0:len(filter_coeffs)-1] delay_buf[0] = x[i]
Code:for j in range(len(filter_coeffs)-1,0,-1) : delay_buf[j] = delay_buf[j-1] delay_buf[0] = x[i]
Code:DATA_SHIFT : for j in 20 downto 1 generate delay_buf(j) = delay_buf(j-1) when rising_edge(clk); end generate;
Tương tự như vậy, bạn cũng chuyển dần dòng lệnh dưới sang một dạng suitable cho HDL implementation hơn.
Code:y[i] = sum(delay_buf * filter_coeffs)
Ở đây tôi đã dùng floating-point, nhưng đại khái là, bạn nên tạo ra một functional model trước, và sau đó chuyển thể từ từ sang dạng HDL suitable hơn. Như đã từng đề cập, phần viết VHDL nên là phần dễ dàng nhất. Chúc bạn thành công.
Comment
-
Nguyên văn bởi tonyvandinh Xem bài viếtNemesis21 có thể giúp dùng Matlab để tạo ra bộ coefficient, số tap, input và output vectors được kô? Thx
Code:N = 20; cf = fir1(N, .2, hamming(N+1))
Code:freqz(cf, 1)
Code:input = sin((1:100)/10))
Comment
-
Sẵn rãnh một chút, tôi sẽ bàn tiếp về FIR filter implementation cho các bạn mới bắt đầu.
Về cấu trúc, khi nào áp dụng serial, parallel, hoặc semi-parallel?
Dựa vào các thông số number of taps N, processing clock rate C, và output sample rate S.
Serial, bạn sử dụng 1 multiplier (M = 1). Bạn cần N clock cycles để calculate 1 output. Nếu processing clock rate = 200 MHz, và number of taps = 20, bạn có thể dùng 1 multiplier để calculate 10 Msps (Megasample per second) trở xuống, N * S <= C * M
Nhưng nếu required output sample rate = 200 Msps, M = 1 không đủ. Trong trường hợp này, bạn cần fully parallel structure, M = N.
Nếu output sample rate = 50 Msps chẳng hạn, chúng ta vẫn có thể dùng M = N. Nhưng thông thường, design goal là phải sử dụng ít resources nhất, cho nên chúng ta sử dụng semi-parallel structure, với M = N / 4.
Nếu output sample rate > 200 Msps, chúng ta vẫn có thể xử lý, nhưng hơi advance cho mạch này.
=======
Sau khi chúng ta đã chọn filter structure hợp lý, cần phải model như thế nào?
Code:y[i] = sum(delay_buf * filter_coeffs)
Break down một chút:
Code:temp = 0; for k in range(len(filter_coeffs)) : temp = temp + delay_buf[k] * filter_coeffs[k]; y[i] = temp;
Code:prod = zeros(len(filter_coeffs)); for k in range(len(filter_coeffs)) : prod[k] = delay_buf[k] * filter_coeffs[k];
.......
Comment
-
......
Hãy chọn adder tree nhé? Tổng thể model như thế này:
Code:delay_buf = zeros(len(filter_coeffs)); y = zeros(len(x)); prod = zeros(len(filter_coeffs)) for i in range (len(x)) : delay_buf[1:len(filter_coeffs)] = delay_buf[0:len(filter_coeffs)-1];delay_buf[0] = x[i] for k in range (len(filter_coeffs)) : prod[k] = delay_buf[k] * filter_coeffs[k]; y[i] = adder_tree(prod)
Sau đây hãy bắt đầu so chiếu với VHDL code đơn giản dùng pre-loaded coefficients.
Code:library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.math_real.all; entity pfir is generic ( NUM_TAPS : positive range 5 to 200 := 21 ); port ( clk : in STD_LOGIC; data_in : in STD_LOGIC_VECTOR; data_out : out STD_LOGIC_VECTOR ); end pfir;
Code:type data_mem_type is array (natural range <>) of std_logic_vector(data_in'range); signal delay_buf : data_mem_type(NUM_TAPS-1 downto 0) := (others => (others => '0'));
Code:delay_buf <= delay_buf(NUM_TAPS-2 downto 0) & data_in when rising_edge(clk);
Code:constant filter_coeffs : data_mem_type(NUM_TAPS-1 downto 0) := ( std_logic_vector(to_signed(integer(-6.21115459e-19 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(-2.12227115e-03 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(-6.32535399e-03 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(-1.16118104e-02 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(-1.23546567e-02 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(4.19252935e-18 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(3.17744976e-02 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(8.14359076e-02 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(1.37493782e-01 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(1.82125490e-01 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(1.99168830e-01 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(1.82125490e-01 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(1.37493782e-01 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(8.14359076e-02 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(3.17744976e-02 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(4.19252935e-18 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(-1.23546567e-02 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(-1.16118104e-02 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(-6.32535399e-03 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(-2.12227115e-03 * 2.0**(data_in'length-1)-1.0),data_in'length)), std_logic_vector(to_signed(integer(-6.21115459e-19 * 2.0**(data_in'length-1)-1.0),data_in'length)) );
Phần multiplication cũng không quá khác so với model, cũng dùng for loop.
Code:type prod_mem_type is array (natural range <>) of signed(data_in'length*2-1 downto 0); signal prod : prod_mem_type(NUM_TAPS-1 downto 0) := (others => (others => '0'));
Code:MULT_GEN : for i in 0 to NUM_TAPS-1 generate prod(i) <= signed(delay_buf(i)) * signed(filter_coeffs(i)) when rising_edge(clk); end generate MULT_GEN;
Comment
-
.......
Adder tree rất cơ bản, chẳng hạn như chúng ta có 4 inputs a, b, c, d, nhưng adder chỉ có thể cộng lại tối đa mỗi lần 2 inputs, chúng ta trước tiên phải cộng (a+b) và (c+d), và sau đó cộng (a+b)+(c+d). Không khó để các bạn model adder tree, nhưng tôi đưa lên một version ở đây để tham khảo đối chiếu với VHDL implementation.
Code:def adder_tree (data_in) : num_inputs = len(data_in); num_levels = int(ceil(log2(num_inputs))); sum_out = zeros((num_levels, num_inputs)); for l in range(num_levels) : num_adders = int(ceil(num_inputs/(2.0**(l+1)))); num_adder_prev_stage=int(ceil(num_inputs/(2.0**(l)))); if (l == 0) : for m in range (num_adders) : if (m == (num_adders - 1)) and (num_adder_prev_stage % 2 == 1) : sum_out[l][m] = data_in[m*2]; else : sum_out[l][m] = data_in[m*2] + data_in[m*2+1]; else : for m in range (num_adders) : if (m == (num_adders - 1)) and (num_adder_prev_stage % 2 == 1) : sum_out[l][m] = sum_out[l-1][m*2]; else : sum_out[l][m] = sum_out[l-1][m*2] + sum_out[l-1][m*2+1]; return sum_out[num_levels-1][0]
So sánh với phần VHDL dưới đây:
Code:type sum_mem_type is array (natural range <>, natural range <>) of signed(data_in'length*2-1 downto 0); constant num_levels : natural := integer(ceil(log(real(NUM_TAPS)) / log(2.0))); signal sum : sum_mem_type(num_levels-1 downto 0, NUM_TAPS-1 downto 0) := (others => (others => (others => '0')));
Code:ADDER_LEVELS_GEN : for l in 0 to num_levels-1 generate constant num_adders : natural := integer(ceil(real(NUM_TAPS)/(2.0**(l+1)))); constant num_adder_prev_stage : natural := integer(ceil(real(NUM_TAPS)/(2.0**(l)))); begin LEVEL_0_GEN : if (l = 0) generate ADDERS_GEN : for m in 0 to num_adders-1 generate NO_ADDER_GEN : if ((m = (num_adders-1)) and ((num_adder_prev_stage mod 2) = 1)) generate sum(l,m) <= prod(m*2) when rising_edge(clk); end generate NO_ADDER_GEN; ADDER_GEN : if ((m < (num_adders-1)) or ((num_adder_prev_stage mod 2) = 0)) generate sum(l,m) <= prod(m*2) + prod(m*2+1) when rising_edge(clk); end generate ADDER_GEN; end generate ADDERS_GEN; end generate LEVEL_0_GEN; LEVEL_X_GEN : if (l > 0) generate ADDERS_GEN : for m in 0 to num_adders-1 generate NO_ADDER_GEN : if ((m = (num_adders-1)) and ((num_adder_prev_stage mod 2) = 1)) generate sum(l,m) <= sum(l-1,m*2) when rising_edge(clk); end generate NO_ADDER_GEN; ADDER_GEN : if ((m < (num_adders-1)) or ((num_adder_prev_stage mod 2) = 0)) generate sum(l,m) <= sum(l-1,m*2) + sum(l-1,m*2+1) when rising_edge(clk); end generate ADDER_GEN; end generate ADDERS_GEN; end generate LEVEL_X_GEN; end generate ADDER_LEVELS_GEN; data_out <= std_logic_vector(sum(num_levels-1,0)) when rising_edge(clk);
Comment
-
Sang phần simulation, bạn có thể tiếp tục dùng math_real library.
Code:signal data_in : std_logic_vector(15 downto 0) := (others => '0'); signal data_out : std_logic_vector(31 downto 0) := (others => '0'); signal counter : natural := 0;
Code:data_gen_proc : process(clk) begin if (rising_edge(clk)) then if (counter mod 4 = 0) then data_in <= std_logic_vector(to_signed(integer(sin(real(counter) / 10.0) * 32767.0), data_in'length)); else data_in <= (others => '0'); end if; counter <= counter + 1; end if; end process data_gen_proc;
=======
Adder tree còn rườm rà; systolic form gọn hơn nhiều:
Code:delay_buf = zeros(len(filter_coeffs)*2-1); y = zeros(len(x)); prod = zeros(len(filter_coeffs)); sum_out = zeros(len(filter_coeffs)); for i in range (len(x)) : delay_buf[1:len(delay_buf)] = delay_buf[0:len(delay_buf)-1];delay_buf[0] = x[i] for k in range (len(filter_coeffs)) : prod[k] = delay_buf[k*2] * filter_coeffs[k]; for k in range (len(filter_coeffs)-1,-1,-1) : if (k == 0) : sum_out[k] = prod[k]; else : sum_out[k] = prod[k] + sum_out[k-1]; y[i] = sum_out[len(sum_out)-1]
Last edited by nemesis21; 08-05-2010, 07:14.
Comment
-
Nguyên văn bởi nemesis21 Xem bài viết- Design cho filter như thế nào? Dựa vào requirements / specs, bạn đã chọn filter structure nào? Parallel, serial (single multiplier), hoặc semi-parallel? Nếu serial, mạch delay của bạn nên sử dụng RAM (hoặc registers và multiplexer để emulate RAM). Nếu parallel, mạch delay của bạn nên sử dụng registers. Bạn đã chọn structure / mạch delay nào? Bạn đã vẽ block diagram cho design của bạn? Generic design hay là target spefiic? Chẳng hạn như với DSP48 của Virtex-4, parallel design có thể hoàn toàn sử dụng intenal registers và routing của DSP48. Bạn đã diagram / model mạch delay của bạn?
http://en.wikipedia.org/wiki/High-level_synthesis
Comment
-
Nguyên văn bởi tonyvandinh Xem bài viếtĐây là những câu hỏi thường có trong đầu của người làm thiết kế. Khá phức tạp để chọn lựa cái architecture nào để làm. Khi chọn rồi, làm giữa chừng mà muốn đổi thì sao? Làm sao để trade-off giữa tốc độ và tốn kém? Vì vậy cần phải giữ thiết kế nguồn kô bị lệ thuộc vào thời gian and hardware architecture rồi dùng phương pháp tự động hóa để chuyển biến qua thiết kế hiện thực mà mình muốn. Link dưới đây sẽ cho các bạn có thêm khái niệm về phương pháp này (High Level Synthesis)
http://en.wikipedia.org/wiki/High-level_synthesis
Nếu chúng ta cần gấp một configurable FIR core, chúng ta có thể bỏ ra vài phút với Coregen. FIR filter là một beginner project vừa tầm để introduce basic techniques, nhưng là một unconvincing case cho high level synthesis tools.
Mentor có một demonstration video dùng Catapult C để implement FIR:
http://www.mentor.com/products/esl/m...1-b8518e15cbbe
Phần C code cũng tương tự như bạn đã đưa lên, nhưng phần implementation lại nhắm vào ASIC, nên không thể nói rằng những biến thể đó là parallel vs semi-parallel vs serial architecture trên FPGA.
Nếu có thể thì bạn làm một high level synthesis demonstration cho FPGA. Demo của Mentor không nhắm vào FPGA cho nên chưa được convincing lắm.
System C là một chuyện, more exposure về FPGA cho "software crowd" beginners. Có khá nhiều tool để chuyển từ System C sang HDL. Nhưng "algorithm synthesis tool" có lẽ thuộc vào một phạm trù khác. Về cost và availability, nó nằm ngoài tầm với, ngay cả cho nhiều companies. Tôi cảm thấy nó là một sự phụ thuộc vào tool từ một vài specific vendor hơn là một phương pháp đại trà.
Comment
-
Tiếp theo phần simple systolic FIR hôm trước, nếu bạn thử implement adder chain và synthesize FIR cho Virtex-5 speed grade -2 device, maximum frequency sẽ vào khoảng 250 MHz.
Code:ADDER_GEN : for i in 0 to NUM_TAPS-1 generate ADDER_0_GEN : if i = 0 generate sum(i) <= prod(i) when rising_edge(clk); end generate; ADDER_X_GEN : if i > 0 generate sum(i) <= prod(i) + sum(i-1) when rising_edge(clk); end generate; end generate ADDER_GEN;
Code:Timing Summary: --------------- Speed Grade: -2 Minimum period: 3.883ns (Maximum Frequency: 257.506MHz) Minimum input arrival time before clock: 0.980ns Maximum output required time after clock: 2.910ns Maximum combinational path delay: No path found
Chúng ta bắt đầu lại với phần hoán chuyển từ adder tree sang adder chain. Đó là một well-documented technique. Hình đính kèm từ Lyrtech illustrate technique đó khá rõ. Chúng ta có thể thấy các systolic "processing elements" illustrated trong phần 3. Simplified systolic (Python) model đã được đưa ra ở trên. Nhưng chúng ta model full systolic array như thế nào?
Đại khái là, processing element có thể được model bằng class:
Code:class PE () : def __init__(self) : self.leftCell = 0; self.a1 = 0; self.a2 = 0; self.b2 = 0; self.m = 0; self.p = 0; def simClkCycle (self, a1 = 0) : if (self.leftCell == 0) : self.p = self.m + 0; self.m = self.a2 * self.b2; self.a2 = self.a1; self.a1 = a1; else : self.p = self.m + self.leftCell.p; self.m = self.a2 * self.b2; self.a2 = self.a1; self.a1 = self.leftCell.a2;
Code:peList = list(); previousPE = 0; for j in range(len(filter_coeffs)) : pe = PE(); pe.b2 = filter_coeffs[j]; pe.leftCell = previousPE; peList.append(pe); previousPE = pe;
Code:for i in range (len(x)) : for k in range (len(filter_coeffs)-1,0,-1) : peList[k].simClkCycle(); peList[0].simClkCycle(x[i]); y[i] = peList[len(peList)-1].p;
Code:type breg_type is array(natural range <>) of std_logic_vector(data_in'range); signal breg : breg_type(NUM_TAPS-1 downto 0); type preg_type is array(natural range <>) of std_logic_vector(data_in'length*2-1 downto 0); signal preg : preg_type(NUM_TAPS-1 downto 0); constant zero : std_logic_vector(47 downto 0) := (others => '0');
Code:pe_inst : entity work.pe port map ( clk => clk, a => filter_coeffs(0), bcin => data_in, bcout => breg(0), pcin => zero(preg(0)'range), pcout => preg(0) ); PE_X: for i in 1 to NUM_TAPS-1 generate pe_inst : entity work.pe port map ( clk => clk, a => filter_coeffs(i), bcin => breg(i-1), bcout => breg(i), pcin => preg(i-1), pcout => preg(i) ); end generate; data_out <= preg(NUM_TAPS-1);
Code:Slice Logic Utilization: Slice Logic Distribution: Number of LUT Flip Flop pairs used: 0 Number with an unused Flip Flop: 0 out of 0 Number with an unused LUT: 0 out of 0 Number of fully used LUT-FF pairs: 0 out of 0 Number of unique control sets: 0 IO Utilization: Number of IOs: 49 Number of bonded IOBs: 49 out of 480 10% Specific Feature Utilization: Number of BUFG/BUFGCTRLs: 1 out of 32 3% Number of DSP48Es: 21 out of 288 7%
Code:Timing Summary: --------------- Speed Grade: -2 Minimum period: 1.692ns (Maximum Frequency: 591.017MHz) Minimum input arrival time before clock: 1.190ns Maximum output required time after clock: 2.910ns Maximum combinational path delay: No path found
Comment
-
Processing element model, nếu bạn nhìn kỹ, là một partial model của DSP48 slice (hình đính kèm). Chúng ta vòng vo một chút để illustrate modeling technique, nhưng DSP48 là primitive mà bạn có thể instantiate directly. Đơn giản là một phần của DSP48 được design especially cho filter implementations.
Code:class PE () : def __init__(self) : self.leftCell = 0; self.a1 = 0; self.a2 = 0; self.b2 = 0; self.m = 0; self.p = 0; def simClkCycle (self, a1 = 0) : if (self.leftCell == 0) : self.p = self.m + 0; self.m = self.a2 * self.b2; self.a2 = self.a1; self.a1 = a1; else : self.p = self.m + self.leftCell.p; self.m = self.a2 * self.b2; self.a2 = self.a1; self.a1 = self.leftCell.a2;
FIR filter có thể là quá đơn giản để model, nhưng các algorithm với multi-dimension systolic array có lẽ sẽ interesting hơn. FIR thì vẫn còn serial và semi-parallel implementation. Chúc thành công.
Comment
-
Em kiếm được cái master thesis của bọn này triển khai FIR filter trên FPGA, show các bác xem thế nào ^^
Link download : http://hungnm.edu.vn/cupid1102/FIR_Filter_FPGA/Cupid1102 = Cupid độc nhất vô nhị
Comment
Bài viết mới nhất
Collapse
-
Trả lời cho Hỗ trợ tìm linh kiện mạch hạ áp 220V - 110Vbởi dinhthuong80Mạch trên nếu dùng vào việc khác ( theo người thiết kế ra nó) thì cũng được: làm mạch tiền khuếch đại (pre-Amply) cho "con sò công suất" hay mạch công suất, để chạy cái loa cũng tạm ok.
Các chữ E,B,C trên mạch trên gắn...-
Channel: Hướng dẫn tìm thông tin linh kiện
hôm nay, 16:47 -
-
Trả lời cho Hỗ trợ tìm linh kiện mạch hạ áp 220V - 110Vbởi iTronvây là mình đã hiểu lí do vì sao ông ấy lại đưa mình nguyên hộp có hơn chục cái mạch này trong đó...
-
Channel: Hướng dẫn tìm thông tin linh kiện
hôm nay, 12:21 -
-
Trả lời cho Hỗ trợ tìm linh kiện mạch hạ áp 220V - 110Vbởi mèomướpDạ mạch này hông dùng được ạ. Chú sang chị hàng xóm mượn cái cuốc kiếm góc nào trong bản có nhìu người qua lại để trồng 1 cây cải ngồng, ngày ngày chú chịu khó qua đấy tưới chăm cho nó lớn ạ, vài tháng sau nó to chú mang ra chợ bán...
-
Channel: Hướng dẫn tìm thông tin linh kiện
hôm nay, 12:13 -
-
bởi iTronEm được ông anh cho mạch như hình, nhờ ace trong diễn đàn xem giúp mạch này dùng ổn ko và dùng linh kiện công suất nào thì phù hợp.
Xin cảm ơn...-
Channel: Hướng dẫn tìm thông tin linh kiện
hôm nay, 11:27 -
-
Trả lời cho Tiếng Anh cho người Việtbởi dinhthuong80Vì sản phẩm của họ dân mình có dùng, và có lẽ cũng không phải là không phổ biến, nên ĐT quyết định gởi thư điện tử tiếng Anh cho họ như sau, ( đã sửa vài từ như được góp ý, vì nếu lịch sự thì dù vòng vo cũng nên phản hồi, vì...
-
Channel: Tâm tình dân kỹ thuật
Hôm qua, 16:36 -
-
Trả lời cho Tiếng Anh cho người Việtbởi tuyennhanCái thư sai ngay câu chào Dear sir mới đúng Hi chỉ dùng cho người quen , các vấn đề về kỹ thuật nó không trả lời hoặc nói loanh quanh tránh ảnh hưởng đến công ty .
Giup1 người cần không giúp người không cần với lại văn mình vợ người nha đừng quên .-
Channel: Tâm tình dân kỹ thuật
23-02-2025, 07:44 -
-
Trả lời cho Tiếng Anh cho người Việtbởi vi van phamCám ơn những lời chúc tốt đẹp của em.
Việc em làm giống như chê sếp dốt, chẳng những không có miếng xôi nào để ăn mà còn chịu nhiều trù dập lên bờ , xuống ruộng.
Hãy tránh vết xe đổ của tui đi. Dành thời gian lo cho gia đình....-
Channel: Tâm tình dân kỹ thuật
23-02-2025, 02:00 -
-
Trả lời cho Tiếng Anh cho người Việtbởi nhathung1101Ngoại ngữ là không thể thiếu, nhất là làm việc với công nghệ.
Nhưng học để tán gái hay để đọc datasheet, manual là chuyện cần quan tâm.
Và đọc ở nguồn nào đáng tin cậy, chứ cứ lên tictok hay facebook học lỏm thì...-
Channel: Tâm tình dân kỹ thuật
22-02-2025, 22:18 -
-
Trả lời cho Tiếng Anh cho người Việtbởi dinhthuong80Bác nói rất khách quan và chính xác. Ngoại ngữ là chìa khóa thăng tiến dù làm gì. Chả thế mà nay nước mình dạy tiếng Anh từ tiểu học.
Nhớ hồi năm 2006 em ra Hải Phòng, Hải Dương tìm việc, thời đó ở Bình Dương lương công...-
Channel: Tâm tình dân kỹ thuật
22-02-2025, 14:51 -
-
Trả lời cho Tiếng Anh cho người Việtbởi dinhthuong80Cảm ơn bạn, ĐT cũng có ý nghĩ như vậy.
Thực ra, lỗi của hãng đó ( gọi là hãng vì không chỉ một model sản phẩm) là về phần cứng, ĐT tuy không biết về lập trình phần mềm nhưng cũng thấy rằng sẽ chẳng khó khăn gì đáng...-
Channel: Tâm tình dân kỹ thuật
22-02-2025, 14:39 -
Comment