FAQ | Points | Add... | Recent posts | Search | Register | Log in


Moduł generatora VGA - Verilog


Post new topic  Reply to topic      Main Page -> Forum Index -> Microcontrollers Generally -> Programmable Systems -> Moduł generatora VGA - Verilog
Author
Message
^Rachel
Poziom 18
Poziom 18


Joined: 19 Nov 2010
Posts: 540
Location: Częstochowa

Post#1 Post from the author of the topic 26 Oct 2011 23:15   

Generator VGA - Verilog


Witam !

Proszę o pomoc, bo już nerwy mi puszczają, siedzę nad tym drugi dzień i ciągle to samo, czyli po uruchomieniu programu na płytce testowej monitor przechodzi w stan uśpienia, tak jakby wgl nie reagował na impulsy.

Układ FPGA taktowany jest zegarem 50 MHz, timingi wziąłem z tąd : (strona 6)
http://www.xilinx.com/support/documentation/ip_documentation/xps_tft.pdf

wycinek z timingami :
Moduł generatora VGA - Verilog

Problemem jest zegar 50MHz, do którego niby jest tryb 800x600 72Hz, ale w tym trybie również nie działał. W materiale jak wyżej przedstawione są timingi dla zegaru 25MHz tryb 640x480 60Hz.

Więc podzieliłem częstotliwość 50MHz na 2 i wtedy częstotliwością 25MHz mogłem taktować swój układ.

Kod :
Code Verilog - [expand]
 
module vga_generator(input wire clk,
output reg h_sync,v_sync,h_video_en,v_video_en);
 
reg [9:0] h_count;
reg [9:0] v_count;
 
initial
begin
h_sync = 0;
v_sync = 0;
h_video_en = 0;
v_video_en = 0;
h_count = 0;
v_count = 0;
end
 
always @(posedge clk)
begin
h_count <= h_count+1;
case(h_count)
95: h_sync <= 1;
143: h_video_en <= 1;
783: h_video_en <= 0;
799: begin
h_sync <= 0;
h_count <= 0;
v_count <= v_count+1;
end
endcase
 
case(v_count)
1: v_sync <= 1;
32: v_video_en <= 1;
512:v_video_en <= 0;
524: begin
v_sync <= 0;
v_count <= 0;
end
endcase
end
 
endmodule
 
module div_2(input wire clock,output reg half_clock);
 
initial
begin
half_clock = 0;
end
 
always @(posedge clock)
half_clock <= ~half_clock;
endmodule
 
 


i wykresy czasowe:
Moduł generatora VGA - Verilog Moduł generatora VGA - Verilog

h_video_en i v_video_en to linie, które są 1 gdy kolory pixeli mają być pobierane z bufora.
Czasy są poprawne. Sam nie wiem co już źle robię , generator z tej strony :
http://www.fpga4fun.com/PongGame.html

Działał bez zarzutów, ale nie chcę bezmyślnie kopiować kodu tylko napisać coś samemu.

Proszę dobrych ludzi o pomoc :)
Back to top
   
KonusiK
Poziom 9
Poziom 9


Joined: 04 Nov 2007
Posts: 33
Location: Kraków

Post#2 27 Oct 2011 09:31helpful post - solution   

Re: Generator VGA - Verilog


Wybacz, ale na razie nie bede Ci sprawdzal wartosci dla case'ow czy sa poprawne, jak pozniej znajde chwilke to na nie lookne. Teraz najbardziej rzucajace sie w oczy:

Primo:
Niby ladnie podzililes przez 2, ale czemu go potem nie uzywasz?
W pierwszym block procesie zamien clock na half_clock i zobacz co wtedy.

Secundo:
Synchronizacje v_sync'a ma byc zupelnie inna. v_count powinien byc inkrementowany przez zmiane na h_sync (innymi slowy, v_count jest licznikiem h_sync'ow a nie zegara, jak to jest w Twoim przypadku):
1. najpierw uklad wystawia kilkaset impulsow h_sync (kazdy wskazuje nowa linie)
2. v_sync schodzi na 0, ale wystawiane sa jeszcze, o ile dobrze pamietam, 2 h_sync'i
3. v_sync idzie w gore

i proces zaczyna sie od nowa.

Popraw kod, zobacz co sie dzieje, a potem bedziem ywalczyc dalej, bo pewnie to nie jedyne problemy - pozniej jeszcze moga byc kwiatki z kolorami, ale do tego dojdziemy :D

powodzenia :)
Back to top
   
Google

Google Adsense


Post# 27 Oct 2011 09:31helpful post - solution   





Back to top
   
^Rachel
Poziom 18
Poziom 18


Joined: 19 Nov 2010
Posts: 540
Location: Częstochowa

Post#3 Post from the author of the topic 27 Oct 2011 17:49   

Re: Generator VGA - Verilog


Tzn, ja połączyłem te moduły ( dzielnik częstotliwości i generator VGA ) w module testbencha, oto kod testbenchu :
Code Verilog - [expand]
module engine_tb;
 
reg clk;
wire h_sync,v_sync,h_video_en,v_video_en,clk2;
 
initial
begin
clk = 0;
end
div_2 u2(clk,clk2);
vga_generator u1(clk2,h_sync,v_sync,h_video_en,v_video_en);
 
always #10 clk <= ~clk;
 
endmodule


Moduł generatora VGA - Verilog

Rozumiem, że h_sync jest sygnałem taktującym licznik v_sync, tak też jest u mnie, czas pomiędzy impulsami v_sync (czyli okres ) wynosi 16,8 ms 1 impuls h_sync trwa 32,8 us, a więc tych impulsów h_sync jest 16,8ms / 32,8us = 512 , co się nie zgadza, bo powinno być 800
Back to top
   
Dave_PL
Poziom 9
Poziom 9


Joined: 15 Sep 2010
Posts: 40
Location: Kraków

Post#4 28 Oct 2011 00:26helpful post - solution   

Re: Generator VGA - Verilog


Zastąp 'initial' jakimś resetem.
Back to top
   
Google

Google Adsense


Post# 28 Oct 2011 00:26helpful post - solution   





Back to top
   
^Rachel
Poziom 18
Poziom 18


Joined: 19 Nov 2010
Posts: 540
Location: Częstochowa

Post#5 Post from the author of the topic 28 Oct 2011 09:34   

Re: Generator VGA - Verilog


Dave_PL wrote:
Zastąp 'initial' jakimś resetem.


a ten reset zrobić synchroniczny czy asynchroniczny ?

Co w tym kodzie jeszcze jest źle ?
Back to top
   
lss
Poziom 17
Poziom 17


Joined: 14 Dec 2008
Posts: 352
Location: Warszawa

Post#6 28 Oct 2011 14:49helpful post - solution   

Re: Generator VGA - Verilog


Zrób asynchroniczny aby nie był zależny od zegara
Back to top
   
Google

Google Adsense


Post# 28 Oct 2011 14:49helpful post - solution   





Back to top
   
Dave_PL
Poziom 9
Poziom 9


Joined: 15 Sep 2010
Posts: 40
Location: Kraków

Post#7 28 Oct 2011 21:08helpful post - solution   

Re: Generator VGA - Verilog


Asynchroniczny reset to można jedynie do symulacji dać. W przypadku rzeczywistych projektów lepiej dać reset synchroniczny.
Back to top
   
lss
Poziom 17
Poziom 17


Joined: 14 Dec 2008
Posts: 352
Location: Warszawa

Post#8 28 Oct 2011 23:46helpful post - solution   

Re: Generator VGA - Verilog


Rozwin temat.... Podaj za przeciw... Na dobra sprawe przy zegarze 25MHz albo w granicach to bez roznicy ale przy mniejszych to jest. Dlatego uzasdnij.
Back to top
   
Dave_PL
Poziom 9
Poziom 9


Joined: 15 Sep 2010
Posts: 40
Location: Kraków

Post#9 28 Oct 2011 23:50helpful post - solution   

Re: Generator VGA - Verilog


Ogólnie do poczytania polecam notę:
http://www.xilinx.com/support/documentation/white_papers/wp272.pdf

Ponadto troszkę ogólniej:
http://forums.xilinx.com/t5/PLD-Blog/That-Dangerous-Asynchronous-Reset/ba-p/12856
Back to top
   
tymon_x
Poziom 20
Poziom 20


Joined: 17 Jun 2010
Posts: 814
Location: Gdańsk

Post#10 01 Nov 2011 17:52helpful post - solution   

Re: Generator VGA - Verilog


Może tak. Opis zrób z asynchronicznym resetem. Zamiana z asynchronicznego na synchroniczny to tylko dodanie dodatkowej flagi dla syntezera XST (-async_to_sync), albo w GUI ISE na PPM na Synthesize - XST.

Pełny synchroniczny reset w systemie to brak resetu jeśli nie ma domeny zegarowej. Jak używasz opisu logiki synchronicznego z asynchronicznym resetem, to wystarczy przefiltrować rejestrem przesuwnym taki reset, aby pozbyć się glitchy, a ścieżka globalna jest na tyle zoptymalizowana, że nie ma co się obawiać jitter'a szczególnie przy tak prostym układzie z niską częstotliwością taktowania.
Back to top
   
J.A
Poziom 17
Poziom 17


Joined: 06 Sep 2007
Posts: 417
Location: Krakow

Post#11 02 Nov 2011 01:48helpful post - solution   

Re: Generator VGA - Verilog


lss wrote:
Rozwin temat.... Podaj za przeciw... Na dobra sprawe przy zegarze 25MHz albo
w granicach to bez roznicy ale przy mniejszych to jest. Dlatego uzasdnij.

niebezpieczenstwo asynchronicznego resetu nie jest zalezne
od czestotliwosci zegara;
w pewnym skrocie sprawa przedstawia sie tak:
sygnal reset ustawia sie w stan aktywny [zalozmy ze jest to '0']
i zeruje rejestry niezaleznie od swej pozycji w czasie wzgledem
sygnalu zegarowego, po jakims czasie sygnal reset jest de-aktywowany
i jesli jest rzeczywiscie asynchroniczny wzgledem zegara, to moze
sie zdarzyc, ze jego [reset] pos. zbocze jest niemal rownoczesne ze
zboczem sygnalu zegara - w takiej sytuacji zaczynaja odgrywac role
roznice w propagacji resetu i zegara do poszczegolnych przerzutnikow
w ukladzie, poniewaz nawet male fpga ma jakies wymiary przestrzenne,
do jednych przerzutnikow de-aktywacja reset dotrze tuz przed zegarem,
do innych tuz po, w konsekwencji czesc F-F [przerzutnikow] bedzie
w danym takcie zegara jeszcze 'zerowana' a inna nie i caly uklad po resecie
wejdzie w stan nieustalony, przypadkowy, ma to szczegolnie fatalne
konsekwencje, jesli beda to przerzutniki jakiejs maszyny stanow
kontrolujacej dzialanie calosci ukladu;

mimo to asynchroniczne zerowanie jest obecnie dosc czesto
stosowane, a to z tego powodu, ze podstawowe jednostki architektury
fpga maja odzielne wejscie zerowania asynchronicznego, wiec
reset asynchroniczny nie konsumuje jednego z wejsc informacyjnych
funkcji kombinacyjnej, jak to jest w przypadku zerowania synchronicznego;
innymi slowy w przypadku rozbudowanej funkcji kombinacyjnej dzieki
zerowaniu asynchronicznemu funkcja jest realizowana przez mniejsza
ilosc podstawowych komorek fpga, a przez to calosc jest szybsza;

mam nadzieje, ze udalo mi sie to opisac w sposob w miare zrozumialy :);

aby uniknac niebezpieczenstwa ktore opisalem powyzej, stosuje sie
prosty zabieg, synchronizuje sie asynchroniczny reset do zegara,
a w przerzutnikach uzywa sie go jako asynchroniczny;

wyglada to mniej wiecej tak: [przyklad w verilog]

Code:
input reset_asynch;

reg reset_synch;

 always @(posedge clk)
    reset_synch <= reset_asynch;

reg [7:0] registers;
 
 always @(posedge clk or posedge reset_synch)
   if ( reset_synch) registers <= 8'h0; // reset korzystajacy z asynch.
                                           wejscia do komorki fpga
   else              registers <= <jakas funkcja>;


dzieki temu de-aktywacja zerowania dotrze do wszystkich przerzutnikow
po aktywnym zboczu zegara;



tymon_x wrote:
. Jak używasz opisu logiki synchronicznego z asynchronicznym resetem,
to wystarczy przefiltrować rejestrem przesuwnym taki reset, aby pozbyć się
glitchy, a ścieżka globalna jest na tyle zoptymalizowana...


Panie Tymonie - mam nadzieje, ze nie odbierze Pan to jako jakis osobisty
przytyk, ale... ma Pan tendencje do wpadania w jakis zamkniety dla wiekszosci
zargon, przez ktory Panskie wypowiedzi sa trudno zrozumiale, zwlaszcza
dla poczatkujacych, a tacy przeciez glownie pytaja tu o rade;

wypowiedzi zwykle trafne merytorycznie, chcialbym zaznaczyc;

pozdrawiam
J.A
Back to top
   
^Rachel
Poziom 18
Poziom 18


Joined: 19 Nov 2010
Posts: 540
Location: Częstochowa

Post#12 Post from the author of the topic 04 Feb 2012 00:41   

Re: Generator VGA - Verilog


Witam ponownie :)

Poradziłem sobie już z timingami, mam "goły" generator, bez pamięci , mogę np wyświetlić jakiś kolor.

Teraz chciałbym dodać pamięć.

Na początku nie będę wykorzystywał zewnętrznej pamięci SRAM jako buforu. Użyje rejestrów. Trochę pokombinowałem i efekt jest taki :
Code Verilog - [expand]
 
module vga_controller(
input clk,
input reset,
input data_wr,
input [9:0] data_in,
output reg [1:0] wr_count,
output reg h_sync,
output reg v_sync,
output reg [2:0]red,
output reg [2:0]green,
output reg [2:0]blue);
 
reg clk_div2;
reg video_h,video_v;
reg [9:0] h_count;
reg [9:0] v_count;
 
reg [9:0] buffer [9:0][8:0];
 
reg [8:0] color_wr;
reg [9:0] x_pos_wr;
reg [8:0] y_pos_wr;
 
 
initial //tylko do symulacji
begin
h_sync=0;
v_sync=0;
red=0;
green=0;
blue=0;
clk_div2=0;
video_h=0;
video_v=0;
h_count=0;
v_count=0;
color_wr=0;
x_pos_wr=0;
y_pos_wr=0;
wr_count=0;
end
 
always @(posedge data_wr) wr_count<=wr_count+1;
always @(posedge clk)
begin
case(data_wr)
1: x_pos_wr <= data_in;
2: y_pos_wr <= data_in;
3: begin
color_wr <= data_in;
buffer[x_pos_wr][y_pos_wr]<= color_wr;
wr_count <= 0;
end //impuls data_good przez 2 cykle czyli 40ns
endcase
end
 
always @(posedge clk)
begin
if(!reset)
clk_div2 <= 1'b0;
else
clk_div2 <= ~clk_div2;
end
 
 
always @(posedge clk)
begin
if(!reset)
h_count <= 10'd0;
else if(clk_div2)
begin
if(h_count != 10'd799)
h_count <= h_count + 1'b1;
else
h_count <= 10'd0;
end
end
 
always @(posedge clk)
begin
if(!reset)
v_count <= 10'd0;
else if(clk_div2)
begin
if(h_count == 10'd799)
begin
if(v_count != 10'd524)
v_count <= v_count + 1'b1;
else
v_count <= 10'd0;
end
end
end
 
always @(posedge clk)
begin
if(!reset)
h_sync <= 1'b0;
else if(clk_div2)
begin
if(h_count >= 10'd656 && h_count< 10'd752)
h_sync <= 1'b0;
else
h_sync <= 1'b1;
end
end
 
always @(posedge clk)
begin
if(!reset)
v_sync <= 1'b0;
else if(clk_div2)
begin
if(v_count >= 10'd490 && v_count < 10'd492)
v_sync <= 1'b0;
else
v_sync <= 1'b1;
end
end
 
always @(posedge clk)
begin
if(!reset)
{red,green,blue} <= 3'b000;
else if(clk_div2)
begin
if(h_count < 10'd640 && v_count < 10'd480)
begin
// tutaj musze wstawic obsluge wyrzucania kolorow z pamieci
// moge tez zapelnic caly obraz jednym kolorem
// uzywajac red <= 7;
red[2:0] <= buffer[h_count][v_count];
green[5:3] <= buffer[h_count][v_count];
blue[8:6] <= buffer[h_count][v_count];
end
else //bez tego elsa widzielibysmy tylko czarny obraz ;/
begin
red <= 0;
green<=0;
blue <=0;
end
end
end
 
endmodule
 


Zasada zapisu kolorów do bufora jest następująca :
Przygotowuję dane do wpisu ( data_in) , a następnie zboczem na wejściu data_wr, zapisuję je do pamięci. Aby zapisać pojedynczy piksel najpierw wysyłamy do pamięci zmięnną x_pos, później y_pos, a na końcu kolor.

Tym sposobem zmniejszam liczbę połączeń, tym bardziej że w przyszłości planuję wrzucić taki sterownik do mniejszego układu abym mógł sobie bez problemu sterować monitorem przez mikrokontroler.

Może ktoś ma jakiś inny pomysł jak rozwiązać sprawę buforu ?

Poza tym nie wiem jak zapisywać i odczytywać dane z takiego buforu, bo np
Code Verilog - [expand]
 
red[2:0] <= buffer[h_count][v_count];
green[5:3] <= buffer[h_count][v_count];
blue[8:6] <= buffer[h_count][v_count];
 


modelsim nie wyrzucił błędu a quatrus wyrzucił, że linie red,gren blue są [2:0].

Pozdrawiam.
Back to top
   
J.A
Poziom 17
Poziom 17


Joined: 06 Sep 2007
Posts: 417
Location: Krakow

Post#13 04 Feb 2012 17:29helpful post - solution   

Re: Generator VGA - Verilog


tu chyba jest blad:
Code:

   input             data_wr,
   /.../
 always @(posedge clk)
   begin
   case(data_wr)
      1: x_pos_wr <= data_in;
      2: y_pos_wr <= data_in;
      3: begin


mialo byc case (wr_count) ?

a te linijki:
red[2:0] <= buffer[h_count][v_count];
green[5:3] <= buffer[h_count][v_count];
blue[8:6] <= buffer[h_count][v_count];

chyba nalezaloby zapisac:
{blue,green,red} <= buffer[h_count][v_count];

dziwne, ze questa przepuscila cos takiego,

output reg [2:0] green,
/.../
green[5:3] <= buffer[h_count][v_count];

J.A
Back to top
   
^Rachel
Poziom 18
Poziom 18


Joined: 19 Nov 2010
Posts: 540
Location: Częstochowa

Post#14 Post from the author of the topic 06 Feb 2012 19:39   

Re: Generator VGA - Verilog


Dzięki za rady. Wpadłem na inny pomysł, żeby zrobić oddzielne moduły tj. oddzielny sam generator i pamięć. Ma to swoje zalety, ponieważ później z łatwością będę mógł zastosować podwójne buforowanie pamięci, zmieniając tylko jeden moduł. Obydwa moduły przedstawiają się tak :

Moduł generatora

Wyprowadzone wyjścia h_count i v_count do adresowania pamięci, a także video_on do włączania rysowania kolorów.

Code Verilog - [expand]
 
module vga_controller(
input clk,
input reset,
output reg video_on,
output reg [9] h_count,
output reg [9] v_count,
output reg h_sync,
output reg v_sync);
 
reg clk_div2;
 
initial //tylko do symulacji
begin
video_on=0;
h_sync=0;
v_sync=0;
clk_div2=0;
h_count=0;
v_count=0;
end
 
 
always @(posedge clk)
begin
if(!reset)
clk_div2 <= 1'b0;
else
clk_div2 <= ~clk_div2;
end
 
 
always @(posedge clk)
begin
if(!reset)
h_count <= 10'd0;
else if(clk_div2)
begin
if(h_count != 10'd799)
h_count <= h_count + 1'b1;
else
h_count <= 10'd0;
end
end
 
always @(posedge clk)
begin
if(!reset)
v_count <= 10'd0;
else if(clk_div2)
begin
if(h_count == 10'd799)
begin
if(v_count != 10'd524)
v_count <= v_count + 1'b1;
else
v_count <= 10'd0;
end
end
end
 
always @(posedge clk)
begin
if(!reset)
h_sync <= 1'b0;
else if(clk_div2)
begin
if(h_count >= 10'd656 && h_count< 10'd752)
h_sync <= 1'b0;
else
h_sync <= 1'b1;
end
end
 
always @(posedge clk)
begin
if(!reset)
v_sync <= 1'b0;
else if(clk_div2)
begin
if(v_count >= 10'd490 && v_count < 10'd492)
v_sync <= 1'b0;
else
v_sync <= 1'b1;
end
end
 
always @(posedge clk)
begin
if(!reset)
video_on<=1'b0;
// {red,green,blue} <= 3'b000;
else if(clk_div2)
begin
if(h_count < 10'd640 && v_count < 10'd480)
begin
video_on<=1'b1;
end
else //bez tego elsa widzielibysmy tylko czarny obraz ;/
begin
video_on<=1'b0;
end
end
end
 
endmodule
 
 
 


Moduł pamięci

Zapis do pamięci odbywa się równolegle, podajemy na wejścia x_pos i y_pos pozycję zapisu piksela o kolorze RGB {Blue,Green,Red} i zapisujemy impulesm wr.

Code Verilog - [expand]
 
module single_buffering_memory(
input clk,
input wr,
input video_on,
input [8]RGB,
input [9]x_pos,
input [9]y_pos,
input [9]h_count,
input [9]v_count,
output reg [2]red,
output reg [2]green,
output reg [2]blue);
 
reg [9] buffer [9][8];
 
initial
begin
red=0;
green=0;
blue=0;
end
 
always @(posedge clk) ////////////zapis do pamieci , najpierw dane, a zapisujemy impulsem wr
begin
if(wr) buffer [x_pos][y_pos] <= RGB;
end
 
always @(posedge clk) /////////// wyswietlanie
begin
if(video_on)
begin
{blue,green,red} <= buffer[h_count][v_count];
end
else
begin
red <= 0;
green<=0;
blue <=0;
end
end
endmodule
 



Do tego postanowiłem zrobić prosty moduł testujący cały układ rysujący kwadrat o kolorze niebieskim i wymiarach 100x100.

Code Verilog - [expand]
 
module test(
input clk,
output reg wr,
output reg [8]RGB,
output reg [9]x_pos,
output reg [9]y_pos);
 
reg [9] x;
reg [9] y;
 
always @(posedge clk)
begin
if(x>100)x<=0; else x<= x+1'b1;
if(y>100)y<=0; else y<= y+1'b1;
end
 
always @(posedge clk)
begin
wr <= ~wr;
if(wr)
begin
x_pos <= x;
y_pos <= y;
RGB <= 9'b111000000;
end
end
 
endmodule
 
 


Ale problem jest taki, że zamiast prostokąta cały ekran jest niebieski :(

Gdzie może być błąd ?

Dołączam jeszcze schemat połączeń między modułami.
Moduł generatora VGA - Verilog

Dodano po 33 [minuty]:

Problem leży w module pamięci, ponieważ robiłem testbench układu testującego i generuje prawidłowe impulsy.
Back to top
   
Google

Google Adsense


Post# Post from the author of the topic 06 Feb 2012 19:39   





Back to top
   
^Rachel
Poziom 18
Poziom 18


Joined: 19 Nov 2010
Posts: 540
Location: Częstochowa

Post#15 Post from the author of the topic 07 Feb 2012 12:48   

Re: Moduł generatora VGA - Verilog


Wydaje mi się , żę problem tkwi w źle opisanej pamięci, tzn muszę wykorzystać pamięć SDRAM dostępną na płytce, bo implementując pamięć niby o tej samej pojemności czyli :

reg [8:0] memory [640*480:0]

otrzymuję błąd:
"Error (276003): Cannot convert all sets of registers into RAM megafunctions when creating nodes. The resulting number of registers remaining in design exceeds the number of registers in the device or the number specified by the assignment max_number_of_registers_from_uninferred_rams. This can cause longer compilation time or result in insufficient memory to complete Analysis and Synthesis"
Back to top
   
Post new topic  Reply to topic      Main Page -> Forum Index -> Microcontrollers Generally -> Programmable Systems -> Moduł generatora VGA - Verilog
Page 1 of 1
Similar topics
Schemat generatora generatora prądu do przydomowej elektrowni wiatrowej. (5)
[Verilog]PS2 + VGA, timing się rozsypuje (2)
[verilog] Spartan3e generator VGA (8)
Switch VGA. Przełączniki sygnałów VGA. Czy jest taki układ? (2)

Page generation time: 0.193 seconds


FAQ || Administrator || Moderators || Widgets and banners || Contact
elektroda.pl topic RSS feed